/** Special case to launch a viz on Argonne's cluster * this will always render to multicast */ void Gridifier::launchArgonneViz(const LauncherConfig &config){ QProcess *launchArgonneVizProcess = new QProcess(QString("./argonneVis.sh")); launchArgonneVizProcess->setWorkingDirectory(mScriptsDir); launchArgonneVizProcess->addArgument(config.visualizationGSH.mEPR); launchArgonneVizProcess->addArgument(QString::number(config.mTimeToRun)); launchArgonneVizProcess->addArgument(config.multicastAddress); QString vizTypeStr = ""; if (config.vizType == isosurface){ vizTypeStr = "iso"; } else if (config.vizType == volumeRender){ vizTypeStr = "vol"; } if (config.vizType == hedgehog){ vizTypeStr = "hog"; } else if (config.vizType == cutPlane){ vizTypeStr = "cut"; } launchArgonneVizProcess->addArgument(vizTypeStr); cout << launchArgonneVizProcess->arguments().join(" ") << endl; launchArgonneVizProcess->start(); while (launchArgonneVizProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } cout << "Stdout:" << endl << launchArgonneVizProcess->readStdout() << endl; if (launchArgonneVizProcess->canReadLineStderr()) cout << "Stderr:" << endl << launchArgonneVizProcess->readStderr() << endl; }
//--------------------------------------------------------------- QString Gridifier::makeSGSFactory(const QString &container, const QString &topLevelRegistry, const QString &className){ QString result; QProcess *makeSGSFactoryProcess = new QProcess(QString("./make_" + className + "_factory.pl")); makeSGSFactoryProcess->setWorkingDirectory(mScriptsDir); makeSGSFactoryProcess->addArgument(container); makeSGSFactoryProcess->addArgument(topLevelRegistry); cout << makeSGSFactoryProcess->arguments().join(" ") << endl; makeSGSFactoryProcess->start(); while (makeSGSFactoryProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } // this functionality is left in a seperate slot since it could be better // to allow the standard qt events to handle it, rather than sitting in the // above loop result = QString(makeSGSFactoryProcess->readStdout()).stripWhiteSpace(); return result; }
/** Method calls appropriate xxx_launch.sh script to * actually launch the visualization job on the target machine */ int Gridifier::launchVizScript(const QString &scriptConfigFileName, const LauncherConfig &config){ // Construct name of script from name of application QProcess *launchVizScriptProcess = new QProcess(QString("./"+config.mAppToLaunch->mAppName+"_launch.sh")); launchVizScriptProcess->setWorkingDirectory(mScriptsDir); launchVizScriptProcess->addArgument(scriptConfigFileName); launchVizScriptProcess->addArgument(QString::number(config.mTimeToRun)); launchVizScriptProcess->start(); while (launchVizScriptProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } if (launchVizScriptProcess->canReadLineStdout()){ QString out(launchVizScriptProcess->readStdout()); cout << "Stdout:" << endl << out << endl; if(out.contains("ERROR")){ return REG_FAILURE; } } if (launchVizScriptProcess->canReadLineStderr()){ QString out(launchVizScriptProcess->readStderr()); cout << "Stderr:" << endl << out << endl; if(out.contains("ERROR")){ return REG_FAILURE; } } return REG_SUCCESS; }
/** Calls setServiceData on the specified service using the second argument as the basis for the argument to setServiceData. (The <ogsi:setByServiceDataNames> tags are added in this routine.) */ void Gridifier::setServiceData(const QString &nameSpace, const QString &gsh, const QString &sdeText){ QString arg("<ogsi:setByServiceDataNames>"); arg.append(sdeText); arg.append("</ogsi:setByServiceDataNames>"); QProcess *setServiceDataProcess = new QProcess(QString("./setServiceData.pl")); setServiceDataProcess->setWorkingDirectory(mScriptsDir); setServiceDataProcess->addArgument(nameSpace); setServiceDataProcess->addArgument(gsh); setServiceDataProcess->addArgument(arg); setServiceDataProcess->start(); while (setServiceDataProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } if(setServiceDataProcess->canReadLineStdout()){ cout << "Stdout:" << endl << setServiceDataProcess->readStdout() << endl; } if (setServiceDataProcess->canReadLineStderr()){ cout << "Stderr:" << endl << setServiceDataProcess->readStderr() << endl; } }
void Tmpl::ready() { for (QValueList<TmplExpand>::iterator it = tmpls.begin(); it != tmpls.end(); ++it){ QProcess *p = (*it).process; if (p && !p->isRunning()){ if (p->normalExit() && p->exitStatus() == 0){ (*it).bReady = true; (*it).res += QString::fromLocal8Bit(p->readStdout()); QTimer::singleShot(0, this, SLOT(clear())); return; } } } }
/** Instructs the simulation associated with the specified SGS to take a checkpoint and then stop. This call blocks until job has stopped or a time-out occurs. */ QString Gridifier::checkPointAndStop(const QString &sgsGSH){ QProcess *checkPointAndStopProcess = new QProcess(QString("./checkpoint_and_stop.pl")); checkPointAndStopProcess->setWorkingDirectory(mScriptsDir); checkPointAndStopProcess->addArgument(sgsGSH); checkPointAndStopProcess->start(); while (checkPointAndStopProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } QString result = checkPointAndStopProcess->readStdout(); return result; }
/** * Method calls lb3d_client.pl script to call web service * to actually launch the job on the target machine */ void Gridifier::webServiceJobSubmit(const QString & scriptConfigFileName){ // Construct name of script from name of application QProcess *launchSimScriptProcess = new QProcess(QString("./lb3d_client.pl")); launchSimScriptProcess->setWorkingDirectory(mScriptsDir); launchSimScriptProcess->addArgument(scriptConfigFileName); launchSimScriptProcess->start(); while (launchSimScriptProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } cout << "Stdout:" << endl << launchSimScriptProcess->readStdout() << endl; if (launchSimScriptProcess->canReadLineStderr()) cout << "Stderr:" << endl << launchSimScriptProcess->readStderr() << endl; }
/** Create a MetaSGS */ QString Gridifier::makeMetaSGS(const QString &factory, const LauncherConfig &config, const QString &parentGSH){ QString result; QProcess *makeSimSGSProcess = new QProcess(QString("./make_msgs.pl")); makeSimSGSProcess->setWorkingDirectory(mScriptsDir); makeSimSGSProcess->addArgument(factory); // the tag is handled correctly if it contains spaces - thanks QT! makeSimSGSProcess->addArgument(config.mJobData->toXML(QString("MetaSGS"))); makeSimSGSProcess->addArgument(config.topLevelRegistryGSH); makeSimSGSProcess->addArgument(config.currentCheckpointGSH); makeSimSGSProcess->addArgument(config.mInputFileName); makeSimSGSProcess->addArgument(QString::number(config.mTimeToRun)); makeSimSGSProcess->addArgument(parentGSH); if (config.treeTag.length() > 0){ makeSimSGSProcess->addArgument(config.treeTag); makeSimSGSProcess->addArgument(config.checkPointTreeFactoryGSH); } makeSimSGSProcess->start(); while(makeSimSGSProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } // Grab the sgs and return it // Do some error checking here - or in the calling class? result = QString(makeSimSGSProcess->readStdout()).stripWhiteSpace(); cout << "Stdout:" << endl << result << endl; if (makeSimSGSProcess->canReadLineStderr()) cout << "Stderr:" << endl << makeSimSGSProcess->readStderr() << endl; return result; }
/** The following static methods wrap around QProcess objects to * run the reg_perl_launcher scripts. Ultimately replace with * code that uses an API to perform the same function programatically. */ QString Gridifier::getSGSFactories(const QString &topLevelRegistry, const QString &desiredContainer, const QString &className){ QString result; QProcess *getSGSFactoriesProcess = new QProcess(QString("./get_" + className + "_factories.pl")); getSGSFactoriesProcess->setWorkingDirectory(mScriptsDir); getSGSFactoriesProcess->addArgument(topLevelRegistry); getSGSFactoriesProcess->start(); // At this point we need to wait for the process to complete. // Clearly this isn't ideal - hence the desire to replace this with API calls. // An alternative is to send the result back via a QT event.... // for the time being stick with this slightly naff approach while (getSGSFactoriesProcess->isRunning()){ // don't sit in an exhaustive loop - waste of electricity :) usleep(10000); // and keep the gui updated mApplication->processEvents(); } // this functionality is left in a seperate slot since it could be better // to allow the standard qt events to handle it, rather than sitting in the // above loop //result = getSGSFactoriesProcessEnded(desiredContainer); QString allFactories = getSGSFactoriesProcess->readStdout(); if (allFactories.length() == 0){ // then no SGS Factories exist - so create one - actually do this elsewhere result = ""; } else { QStringList factories = QStringList::split("\n", allFactories); int numFactories = factories.size(); // prune the list - remove any factories not on the desired container for (int i=0; i<numFactories; i++){ if (!factories[i].contains(desiredContainer)){ factories.erase(factories.at(i)); numFactories = factories.size(); // undo the increment since we've removed an element i--; } } // if there's no factories left - return the blank string if (numFactories <= 0) result = ""; // choose a factory at random int randomNum = rand(); randomNum = (int)((randomNum / (float)RAND_MAX) * numFactories); QString randomFactory = factories[randomNum]; result = randomFactory; } return result; }
//--------------------------------------------------------------- QString Gridifier::makeVizSGS(const QString &factory, const LauncherConfig &config){ QString result; #ifndef REG_WSRF QProcess *makeVizSGSProcess = new QProcess(QString("./make_vis_sgs.pl")); makeVizSGSProcess->setWorkingDirectory(mScriptsDir); makeVizSGSProcess->addArgument(factory); makeVizSGSProcess->addArgument(config.mJobData->toXML(QString("SGS"))); makeVizSGSProcess->addArgument(config.topLevelRegistryGSH); makeVizSGSProcess->addArgument(config.simulationGSH.mEPR); makeVizSGSProcess->addArgument(QString::number(config.mTimeToRun)); makeVizSGSProcess->start(); while (makeVizSGSProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } if(makeVizSGSProcess->canReadLineStdout()){ result = QString(makeVizSGSProcess->readStdout()); cout << "stdout: " << result << endl; } else{ cout << "Full line of stdout unavailable" << endl; } if(makeVizSGSProcess->canReadLineStderr()){ cout << "stderr: " << QString(makeVizSGSProcess->readStderr()) << endl; } else{ cout << "Full line of stderr unavailable" << endl; } result = QString(makeVizSGSProcess->readStdout()).stripWhiteSpace(); #else // REG_WSRF is defined char purpose[1024]; char proxyAddress[1024]; int proxyPort; char iodef_label[256]; char *ioTypes; struct soap mySoap; char *EPR; struct msg_struct *msg; xmlDocPtr doc; xmlNsPtr ns; xmlNodePtr cur; struct io_struct *ioPtr; int i, count; struct reg_job_details job; /* Obtain the IOTypes from the data source */ soap_init(&mySoap); if( Get_resource_property (&mySoap, config.simulationGSH.mEPR.ascii(), config.simulationGSH.mSecurity.userDN, config.simulationGSH.mSecurity.passphrase, "ioTypeDefinitions", &ioTypes) != REG_SUCCESS ){ cout << "Call to get ioTypeDefinitions ResourceProperty on "<< config.simulationGSH.mEPR << " failed" << endl; return result; } cout << "Got ioTypeDefinitions >>" << ioTypes << "<<" << endl; if( !(doc = xmlParseMemory(ioTypes, strlen(ioTypes))) || !(cur = xmlDocGetRootElement(doc)) ){ fprintf(stderr, "Hit error parsing buffer\n"); xmlFreeDoc(doc); xmlCleanupParser(); return result; } ns = xmlSearchNsByHref(doc, cur, (const xmlChar *) "http://www.realitygrid.org/xml/steering"); if ( xmlStrcmp(cur->name, (const xmlChar *) "ioTypeDefinitions") ){ cout << "ioTypeDefinitions not the root element" << endl; return result; } /* Step down to ReG_steer_message and then to IOType_defs */ cur = cur->xmlChildrenNode->xmlChildrenNode; msg = New_msg_struct(); msg->msg_type = IO_DEFS; msg->io_def = New_io_def_struct(); parseIOTypeDef(doc, ns, cur, msg->io_def); Print_msg(msg); if(!(ioPtr = msg->io_def->first_io) ){ fprintf(stderr, "Got no IOType definitions from data source\n"); return result; } i = 0; printf("Available IOTypes:\n"); while(ioPtr){ if( !xmlStrcmp(ioPtr->direction, (const xmlChar *)"OUT") ){ printf(" %d: %s\n", i++, (char *)ioPtr->label); } ioPtr = ioPtr->next; } count = i-1; /* printf("Enter IOType to use as data source (0-%d): ", count); while(1){ if(scanf("%d", &i) == 1)break; } printf("\n"); */ // ARPDBG - temporary hardwire to select first output IOType //i = 0; count = 0; ioPtr = msg->io_def->first_io; while(ioPtr){ if( !xmlStrcmp(ioPtr->direction, (const xmlChar *)"OUT") ){ //if(count == i){ ARPDBG - temporary hardwire to select first output IOType strncpy(iodef_label, (char *)(ioPtr->label), 256); break; //}ARPDBG count++; } ioPtr = ioPtr->next; } Delete_msg_struct(&msg); // Initialize job_details struct snprintf(job.userName, REG_MAX_STRING_LENGTH, config.mJobData->mPersonLaunching.ascii()); snprintf(job.group, REG_MAX_STRING_LENGTH, "RSS"); snprintf(job.software, REG_MAX_STRING_LENGTH, config.mJobData->mSoftwareDescription.ascii()); snprintf(job.purpose, REG_MAX_STRING_LENGTH, config.mJobData->mPurposeOfJob.ascii()); snprintf(job.inputFilename, REG_MAX_STRING_LENGTH, config.mInputFileName.ascii()); job.lifetimeMinutes = config.mTimeToRun; snprintf(job.passphrase, REG_MAX_STRING_LENGTH, config.simulationGSH.mSecurity.passphrase); snprintf(job.checkpointAddress, REG_MAX_STRING_LENGTH, config.currentCheckpointGSH.ascii()); // Now create SWS for the vis if( !(EPR = Create_steering_service(&job, factory.ascii(), config.topLevelRegistryGSH.ascii(), &(config.registrySecurity)) ) ){ cout << "FAILED to create SWS for " << config.mJobData->mSoftwareDescription << " :-(" << endl; soap_end(&mySoap); soap_done(&mySoap); return result; } // Finally, set it up with information on the data source // Check to see whether or not an ioProxy is being used if( Get_resource_property (&mySoap, config.simulationGSH.mEPR.ascii(), config.simulationGSH.mSecurity.userDN, config.simulationGSH.mSecurity.passphrase, "dataSink", &ioTypes) != REG_SUCCESS ){ cout << "Call to get dataSink ResourceProperty on "<< config.simulationGSH.mEPR << " failed" << endl; return result; } // <sws:dataSink xmlns:sws="http://www.sve.man.ac.uk/SWS"> // <Proxy> // <address>methuselah.mvc.mcc.ac.uk</address> // <port>50010</port> // </Proxy> // </sws:dataSink> cout << "ARPDBG: Got dataSink >>" << ioTypes << "<<" << endl; char *ptr, *ptr0, *ptr1; proxyPort = 0; proxyAddress[0] = '\0'; if( ptr0 = strstr(ioTypes, "<Proxy>") ){ // An ioProxy IS being used by the simulation ptr1 = NULL; ptr = strstr(ptr0, "<address"); if(ptr)ptr = strstr(ptr, ">"); if(ptr)ptr++; if(ptr)ptr1 = strstr(ptr, "</address>"); if(ptr1)*ptr1 = '\0'; if(ptr1)strncpy(proxyAddress, ptr, 1024); if(ptr1)*ptr1 = '<'; ptr = strstr(ptr0, "<port"); if(ptr)ptr = strstr(ptr, ">"); if(ptr)ptr++; if(ptr)ptr1 = strstr(ptr, "</port>"); if(ptr1)*ptr1 = '\0'; if(ptr1)proxyPort = atoi(ptr); int idx = snprintf(purpose, 1024, "<dataSink><Proxy><address>%s</address>" "<port>%d</port></Proxy></dataSink>", proxyAddress, proxyPort); snprintf(&(purpose[idx]), 1024, "<dataSource><Proxy><address>%s" "</address><port>%d</port></Proxy><sourceLabel>%s" "</sourceLabel></dataSource>", proxyAddress, proxyPort, iodef_label); } else{ snprintf(purpose, 1024, "<dataSource><sourceEPR>%s</sourceEPR>" "<sourceLabel>%s</sourceLabel></dataSource>", config.simulationGSH.mEPR.ascii(), iodef_label); } printf("Calling Set_resource_property with >>%s<<\n", purpose); if(Set_resource_property(&mySoap, EPR, config.simulationGSH.mSecurity.userDN, config.simulationGSH.mSecurity.passphrase, purpose) != REG_SUCCESS){ cout << "Set_resource_property failed:" << endl; soap_end(&mySoap); soap_done(&mySoap); return result; } result = QString(EPR); soap_end(&mySoap); soap_done(&mySoap); #endif // ndef REG_WSRF return result; }
/* Create an SGS or SWS to associate with a simulation */ QString Gridifier::makeSteeringService(const QString &factory, const LauncherConfig &config){ QString result; #ifndef REG_WSRF QProcess *makeSimSGSProcess = new QProcess(QString("./make_sgs.pl")); makeSimSGSProcess->setWorkingDirectory(mScriptsDir); makeSimSGSProcess->addArgument(factory); // the tag is handled correctly if it contains spaces - thanks QT! makeSimSGSProcess->addArgument(config.mJobData->toXML(QString("SGS"))); makeSimSGSProcess->addArgument(config.topLevelRegistryGSH); makeSimSGSProcess->addArgument(config.currentCheckpointGSH); makeSimSGSProcess->addArgument(config.mInputFileName); makeSimSGSProcess->addArgument(QString::number(config.mTimeToRun)); if (config.treeTag.length() > 0){ makeSimSGSProcess->addArgument(config.treeTag); makeSimSGSProcess->addArgument(config.checkPointTreeFactoryGSH); } makeSimSGSProcess->start(); while(makeSimSGSProcess->isRunning()){ usleep(10000); mApplication->processEvents(); } // Grab the sgs and return it // Do some error checking here - or in the calling class? result = QString(makeSimSGSProcess->readStdout()).stripWhiteSpace(); #else // REG_WSRF is defined struct reg_job_details job; char *chkTree; // Initialize job_details struct snprintf(job.userName, REG_MAX_STRING_LENGTH, config.mJobData->mPersonLaunching.ascii()); snprintf(job.group, REG_MAX_STRING_LENGTH, "RSS"); snprintf(job.software, REG_MAX_STRING_LENGTH, config.mJobData->mSoftwareDescription.ascii()); snprintf(job.purpose, REG_MAX_STRING_LENGTH, config.mJobData->mPurposeOfJob.ascii()); snprintf(job.inputFilename, REG_MAX_STRING_LENGTH, config.mInputFileName.ascii()); job.lifetimeMinutes = config.mTimeToRun; snprintf(job.passphrase, REG_MAX_STRING_LENGTH, config.mServicePassword.ascii()); // Create a new checkpoint tree if requested if(config.treeTag.length()){ chkTree = Create_checkpoint_tree(config.checkPointTreeFactoryGSH.ascii(), config.treeTag.ascii()); if(!chkTree){ QMessageBox::critical( NULL, "Checkpoint tree error", "Failed to create new checkpoint tree.\n\n", QMessageBox::Ok, 0, 0 ); return result; } } else{ chkTree = (char *)(config.currentCheckpointGSH.ascii()); } snprintf(job.checkpointAddress, REG_MAX_STRING_LENGTH, chkTree); char *EPR = Create_steering_service(&job, factory.ascii(), config.topLevelRegistryGSH.ascii(), &(config.registrySecurity)); result = QString(EPR); struct soap mySoap; soap_init(&mySoap); // Put contents of input deck (if any) into the RP doc of the SWS if( EPR && !(config.mInputFileName.isEmpty()) ){ QFile *inputFile = new QFile(config.mInputFileName); inputFile->open( IO_ReadOnly ); QByteArray fileData = inputFile->readAll(); inputFile->close(); QString fileRP("<inputFileContent><![CDATA["); fileRP.append(fileData.data()); fileRP.append("]]></inputFileContent>"); if(Set_resource_property(&mySoap, EPR, job.userName, job.passphrase, (char *)(fileRP.ascii()) ) != REG_SUCCESS){ cout << "Gridifier::makeSteeringService: WARNING - failed to store " "job input file on SWS." << endl; } } if(EPR && config.mIOProxyPort){ QString resourceProp("<dataSink><Proxy><address>"); resourceProp.append(config.mIOProxyAddress); resourceProp.append("</address><port>"); resourceProp.append(QString::number(config.mIOProxyPort, 10)); resourceProp.append("</port></Proxy></dataSink>"); //cout << "Gridifier::makeSteeringService: Calling Set_resource_property " // "with >>" << resourceProp << "<<" << endl; if(Set_resource_property(&mySoap, EPR, job.userName, job.passphrase, (char *)(resourceProp.ascii())) != REG_SUCCESS){ cout << "Gridifier::makeSteeringService: WARNING - failed to set " "details of ioProxy on the SWS" << endl; } } soap_end(&mySoap); soap_done(&mySoap); if(EPR){ cout << "Address of SWS = " << EPR << endl; } else{ cout << "FAILED to create SWS :-(" << endl; } #endif // ndef REG_WSRF return result; }
//==================================== // exportData //------------------------------------ bool SCCTablet::exportData ( void ) { //==================================== // create manipulators... //------------------------------------ SaXManipulateTablets saxTablet ( mSection["Pointers"],mSection["Layout"] ); SaXManipulateDevices saxDevice ( mSection["Pointers"],mSection["Layout"] ); //==================================== // search and remove tablet //------------------------------------ int inputCount = mSection["Pointers"]->getCount(); for (int i=inputCount;i>=0;i--) { if (saxTablet.selectPointer (i)) { if (saxTablet.isTablet()) { saxDevice.removeInputDevice (i); } if (saxTablet.isPen()) { saxDevice.removeInputDevice (i); } if (saxTablet.isEraser()) { saxDevice.removeInputDevice (i); } } } //==================================== // add tablet if enabled //------------------------------------ if (mTabletSelection->isEnabled()) { QString vendor = mTabletSelection->getVendor(); QString model = mTabletSelection->getModel(); if (! model.isEmpty()) { int tabletID = saxDevice.addInputDevice (SAX_INPUT_TABLET); saxTablet.selectPointer ( tabletID ); saxTablet.setTablet ( vendor,model ); QDict<QString> tabletDict = saxTablet.getTabletData ( vendor,model ); //==================================== // save tablet connection port //------------------------------------ if (! mTabletConnection->isAutoPort()) { QString port = mTabletConnection->getPortName(); if (port.contains ("ttyS0")) { saxTablet.setDevice ( "/dev/ttyS0" ); } if (port.contains ("ttyS1")) { saxTablet.setDevice ( "/dev/ttyS1" ); } if (port.contains ("USB")) { QProcess* proc = new QProcess (); proc -> addArgument ( USB_PORT ); if (proc -> start()) { while (proc->isRunning()) { usleep (1000); } QByteArray data = proc->readStdout(); QStringList lines = QStringList::split ("\n",data); saxTablet.setDevice ( lines.first() ); } } } //==================================== // save tablet options //------------------------------------ QString driver = saxTablet.getDriver(); QDict<QString> allOptions = saxTablet.getTabletOptions ( driver ); QDictIterator<QString> it (allOptions); for (; it.current(); ++it) { saxTablet.removeOption (it.currentKey()); } QDict<QString> tabletOptions = mTabletConnection->getOptions(); QDictIterator<QString> io (tabletOptions); for (; io.current(); ++io) { saxTablet.addOption (io.currentKey(),*io.current()); } //==================================== // save tablet mode //------------------------------------ int mode = mTabletConnection->getTabletMode(); if (mode == 0) { saxTablet.setMode ("Relative"); } else { saxTablet.setMode ("Absolute"); } int sticks[2] = {-1,-1}; //==================================== // handle Tablet Pen //------------------------------------ if (mTabletPens->hasPen()) { QString penLink = *tabletDict["StylusLink"]; sticks[0] = saxTablet.addPen ( vendor,penLink ); } //==================================== // handle Tablet Eraser //------------------------------------ if (mTabletPens->hasEraser()) { QString eraserLink = *tabletDict["EraserLink"]; sticks[1] = saxTablet.addPen ( vendor,eraserLink ); } //==================================== // save pen/eraser data //------------------------------------ for (int n=0;n<2;n++) { if (sticks[n] > 0) { SCCTabletPenProperty* pen = 0; switch (n) { case 0: pen = mTabletPens->getPenPropertyData(); break; case 1: pen = mTabletPens->getEraserPropertyData(); break; } //==================================== // create manipulators... //------------------------------------ SaXManipulateTablets saxPen ( mSection["Pointers"],mSection["Layout"] ); saxPen.selectPointer ( sticks[n] ); //==================================== // save pen's mode //------------------------------------ int mode = pen->getPenMode(); if (mode == 0) { saxPen.setMode ("Relative"); } else { saxPen.setMode ("Absolute"); } //==================================== // save pen's options //------------------------------------ QString driver = saxTablet.getDriver(); QDict<QString> allOptions = saxTablet.getTabletOptions (driver); QDictIterator<QString> it (allOptions); for (; it.current(); ++it) { saxPen.removeOption (it.currentKey()); } QDict<QString> penOptions = pen->getPenOptions(); QDictIterator<QString> io (penOptions); for (; io.current(); ++io) { saxPen.addOption (io.currentKey(),*io.current()); } //==================================== // save pen's device //------------------------------------ saxTablet.selectPointer ( tabletID ); QString device = saxTablet.getDevice(); saxPen.selectPointer ( sticks[n] ); saxPen.setDevice (device); } } } } return true; }