| 1 | 
 #include "xmlcustomcode.h" | 
 
 
 
 
 
 | 2 | 
  | 
 
 
 
 
 
 | 3 | 
 XmlCustomCode* XmlCustomCode::uniqueInstance = NULL; | 
 
 
 
 
 
 | 4 | 
  | 
 
 
 
 
 
 | 5 | 
 QScriptValue echo(QScriptContext *context, QScriptEngine*) | 
 
 
 
 
 
 | 6 | 
 { | 
 
 
 
 
 
 | 7 | 
     std::cout << context->argument(0).toString().toUtf8().constData() << std::endl; | 
 
 
 
 
 
 | 8 | 
  | 
 
 
 
 
 
 | 9 | 
     return ""; | 
 
 
 
 
 
 | 10 | 
 } | 
 
 
 
 
 
 | 11 | 
  | 
 
 
 
 
 
 | 12 | 
 XmlCustomCode::XmlCustomCode(): numThreads(QThread::idealThreadCount()) | 
 
 
 
 
 
 | 13 | 
 { | 
 
 
 
 
 
 | 14 | 
     myThreadPool.setMaxThreadCount(numThreads); | 
 
 
 
 
 
 | 15 | 
     myThreadPool.setExpiryTimeout(-1); // don't let threads expire | 
 
 
 
 
 
 | 16 | 
  | 
 
 
 
 
 
 | 17 | 
     // create individual thread script engines | 
 
 
 
 
 
 | 18 | 
     this->jsScriptEngines.reserve(this->numThreads); | 
 
 
 
 
 
 | 19 | 
  | 
 
 
 
 
 
 | 20 | 
     QString jsxmlString; | 
 
 
 
 
 
 | 21 | 
     QFile jsxmlfile(":/resources/libs/jsxml.js"); | 
 
 
 
 
 
 | 22 | 
  | 
 
 
 
 
 
 | 23 | 
     jsxmlfile.open(QFile::ReadOnly | QFile::Text); | 
 
 
 
 
 
 | 24 | 
  | 
 
 
 
 
 
 | 25 | 
     jsxmlString=QTextStream(&jsxmlfile).readAll(); | 
 
 
 
 
 
 | 26 | 
  | 
 
 
 
 
 
 | 27 | 
     for(int i=0; i<this->numThreads; i++){ | 
 
 
 
 
 
 | 28 | 
  | 
 
 
 
 
 
 | 29 | 
         jsCustomCodeEngine e; | 
 
 
 
 
 
 | 30 | 
  | 
 
 
 
 
 
 | 31 | 
         e.scriptEngine = new QScriptEngine(); | 
 
 
 
 
 
 | 32 | 
         e.jsFunction = new QScriptValue(); | 
 
 
 
 
 
 | 33 | 
  | 
 
 
 
 
 
 | 34 | 
         // main needs to be called so the user code is evaluated | 
 
 
 
 
 
 | 35 | 
         // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call(); | 
 
 
 
 
 
 | 36 | 
         // Note the () around the function | 
 
 
 
 
 
 | 37 | 
         e.getXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function getXmlData() { return $xmlData; })")); | 
 
 
 
 
 
 | 38 | 
         e.setXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })")); | 
 
 
 
 
 
 | 39 | 
         e.mutexForEngine = new QMutex; | 
 
 
 
 
 
 | 40 | 
  | 
 
 
 
 
 
 | 41 | 
         // Add echo function so user can debug the code | 
 
 
 
 
 
 | 42 | 
         QScriptValue echoFunction = e.scriptEngine->newFunction(echo); | 
 
 
 
 
 
 | 43 | 
         e.scriptEngine->globalObject().setProperty("echo", echoFunction); | 
 
 
 
 
 
 | 44 | 
  | 
 
 
 
 
 
 | 45 | 
         // Add the js library for XmlEditing | 
 
 
 
 
 
 | 46 | 
         e.scriptEngine->evaluate(jsxmlString); | 
 
 
 
 
 
 | 47 | 
  | 
 
 
 
 
 
 | 48 | 
         this->jsScriptEngines.append(e); | 
 
 
 
 
 
 | 49 | 
     } | 
 
 
 
 
 
 | 50 | 
 } | 
 
 
 
 
 
 | 51 | 
  | 
 
 
 
 
 
 | 52 | 
 XmlCustomCode* XmlCustomCode::getInstance(){ | 
 
 
 
 
 
 | 53 | 
  | 
 
 
 
 
 
 | 54 | 
     if (uniqueInstance==NULL){   // allow only one instance | 
 
 
 
 
 
 | 55 | 
         uniqueInstance = new XmlCustomCode(); | 
 
 
 
 
 
 | 56 | 
     } | 
 
 
 
 
 
 | 57 | 
  | 
 
 
 
 
 
 | 58 | 
     return uniqueInstance; | 
 
 
 
 
 
 | 59 | 
 } | 
 
 
 
 
 
 | 60 | 
  | 
 
 
 
 
 
 | 61 | 
 void XmlCustomCode::executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled){ | 
 
 
 
 
 
 | 62 | 
  | 
 
 
 
 
 
 | 63 | 
     // Reconstruct script functions | 
 
 
 
 
 
 | 64 | 
     for(int i=0; i<this->numThreads; i++){ | 
 
 
 
 
 
 | 65 | 
         *(jsScriptEngines[i].jsFunction) = jsScriptEngines.at(i).scriptEngine->evaluate("(function main() {"+jsString+"})"); | 
 
 
 
 
 
 | 66 | 
     } | 
 
 
 
 
 
 | 67 | 
  | 
 
 
 
 
 
 | 68 | 
     QString currXmlFileString; | 
 
 
 
 
 
 | 69 | 
  | 
 
 
 
 
 
 | 70 | 
     QScriptValue engineResult; // variable to check for js_errors | 
 
 
 
 
 
 | 71 | 
     double elapsed_secs=0; // elapsed seconds that a user script took | 
 
 
 
 
 
 | 72 | 
     clock_t begin; // seconds that a script started | 
 
 
 
 
 
 | 73 | 
  | 
 
 
 
 
 
 | 74 | 
     // Single tread if small number of files or number of threads = 1 | 
 
 
 
 
 
 | 75 | 
     if(filesToProcess.size()<=CUSTOM_FILES_PER_THREAD || numThreads == 1){ | 
 
 
 
 
 
 | 76 | 
  | 
 
 
 
 
 
 | 77 | 
         jsCustomCodeEngine &jsEngine = this->jsScriptEngines.first(); | 
 
 
 
 
 
 | 78 | 
  | 
 
 
 
 
 
 | 79 | 
         // Process all XmlFiles | 
 
 
 
 
 
 | 80 | 
         for(int i=0; i<filesToProcess.size(); i++){ | 
 
 
 
 
 
 | 81 | 
             customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult, | 
 
 
 
 
 
 | 82 | 
                                 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 83 | 
         } | 
 
 
 
 
 
 | 84 | 
     } | 
 
 
 
 
 
 | 85 | 
     else{ // Multithread if there are many files | 
 
 
 
 
 
 | 86 | 
         // Process all XmlFiles | 
 
 
 
 
 
 | 87 | 
  | 
 
 
 
 
 
 | 88 | 
         QVector<QFuture<void>> executingThreads; | 
 
 
 
 
 
 | 89 | 
  | 
 
 
 
 
 
 | 90 | 
         for(int i=0, iteration = 0; i<=filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD, ++iteration){ | 
 
 
 
 
 
 | 91 | 
  | 
 
 
 
 
 
 | 92 | 
             executingThreads << QtConcurrent::run(&this->myThreadPool, [=]() | 
 
 
 
 
 
 | 93 | 
             { | 
 
 
 
 
 
 | 94 | 
  | 
 
 
 
 
 
 | 95 | 
                 const int indexJsEngine = iteration % this->numThreads; | 
 
 
 
 
 
 | 96 | 
  | 
 
 
 
 
 
 | 97 | 
                 jsCustomCodeEngine &jsEngine = this->jsScriptEngines[indexJsEngine]; | 
 
 
 
 
 
 | 98 | 
  | 
 
 
 
 
 
 | 99 | 
                 jsEngine.mutexForEngine->lock(); | 
 
 
 
 
 
 | 100 | 
  | 
 
 
 
 
 
 | 101 | 
                 QString currXmlFileStringThread; | 
 
 
 
 
 
 | 102 | 
  | 
 
 
 
 
 
 | 103 | 
                 QScriptValue engineResultThread; // variable to check for js_errors | 
 
 
 
 
 
 | 104 | 
                 double elapsedSecsThread=0; // elapsed seconds that a user script took | 
 
 
 
 
 
 | 105 | 
                 clock_t beginThread; // seconds that a script started | 
 
 
 
 
 
 | 106 | 
  | 
 
 
 
 
 
 | 107 | 
                 customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread, | 
 
 
 
 
 
 | 108 | 
                                     *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 109 | 
  | 
 
 
 
 
 
 | 110 | 
                 customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread, | 
 
 
 
 
 
 | 111 | 
                                     *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 112 | 
  | 
 
 
 
 
 
 | 113 | 
                 customCodeUnwinding(filesToProcess.at(i+2),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread, | 
 
 
 
 
 
 | 114 | 
                                     *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 115 | 
  | 
 
 
 
 
 
 | 116 | 
                 customCodeUnwinding(filesToProcess.at(i+3),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread, | 
 
 
 
 
 
 | 117 | 
                                     *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 118 | 
  | 
 
 
 
 
 
 | 119 | 
                 jsEngine.mutexForEngine->unlock(); | 
 
 
 
 
 
 | 120 | 
             }); | 
 
 
 
 
 
 | 121 | 
         } | 
 
 
 
 
 
 | 122 | 
  | 
 
 
 
 
 
 | 123 | 
         // Wait for all threads to finish | 
 
 
 
 
 
 | 124 | 
         for(QFuture<void> &f :executingThreads){ | 
 
 
 
 
 
 | 125 | 
             f.waitForFinished(); | 
 
 
 
 
 
 | 126 | 
         } | 
 
 
 
 
 
 | 127 | 
  | 
 
 
 
 
 
 | 128 | 
         if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){ | 
 
 
 
 
 
 | 129 | 
  | 
 
 
 
 
 
 | 130 | 
             int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD; | 
 
 
 
 
 
 | 131 | 
  | 
 
 
 
 
 
 | 132 | 
             jsCustomCodeEngine &jsEngine = this->jsScriptEngines.first(); | 
 
 
 
 
 
 | 133 | 
  | 
 
 
 
 
 
 | 134 | 
             for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){ | 
 
 
 
 
 
 | 135 | 
  | 
 
 
 
 
 
 | 136 | 
                 customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult, | 
 
 
 
 
 
 | 137 | 
                                     *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled); | 
 
 
 
 
 
 | 138 | 
             } | 
 
 
 
 
 
 | 139 | 
         } | 
 
 
 
 
 
 | 140 | 
     } | 
 
 
 
 
 
 | 141 | 
 } | 
 
 
 
 
 
 | 142 | 
  | 
 
 
 
 
 
 | 143 | 
 void XmlCustomCode::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){ | 
 
 
 
 
 
 | 144 | 
     if (engine.hasUncaughtException()) { | 
 
 
 
 
 
 | 145 | 
         UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString()); | 
 
 
 
 
 
 | 146 | 
     } | 
 
 
 
 
 
 | 147 | 
 } |