QCad原始碼分析 第三章
阿新 • • 發佈:2018-12-07
QCad處理指令碼的基本流程如下:
//將指令碼的工廠函式和指令碼型別註冊到系統當中,【jsfactory--js, pytonfactory--python】 RScriptHandlerRegistry::registerScriptHandler(RScriptHandlerEcma::factory, RScriptHandlerEcma::getSupportedFileExtensionsStatic()); //通過指令碼工廠【jsfactory】建立具體的指令碼類 RScriptHandler* handler = RScriptHandlerRegistry::getGlobalScriptHandler("js"); Q_ASSERT(handler!=NULL); //初始化自動指令碼程式【初始化過程中會建立主介面】 handler->init(autostartFile, arguments.mid(i+1)); //如果指令碼初始化過程中出現異常,則返回 int ret = 0; if (handler->hasUncaughtExceptions()) { ret = 1; } // delete script handler and print uncaught exceptions: //刪除指令碼控制代碼,列印異常 delete handler;
下面的程式碼用於在指令碼直譯器中初始化並啟動指令碼:
void RScriptHandler::init(const QString& autostartFile, const QStringList& arguments) { QStringList triedLocations; if (!autostartFile.isEmpty()) { //如果啟動的指令碼檔案不是空的 QFileInfo fi(autostartFile); //如果不是絕路徑,就轉換為絕對路徑 if (!fi.isAbsolute() && !autostartFile.startsWith(":")) { triedLocations << RSettings::getLaunchPath() + QDir::separator() + autostartFile; } triedLocations << autostartFile; triedLocations << ":" + autostartFile; } else { //如果沒有設定檔案則獲取預設的指令碼檔案 QStringList extensions = getSupportedFileExtensions(); QStringList::iterator it; for (it = extensions.begin(); it != extensions.end(); ++it) { QString scriptFile = "scripts" + QString(QDir::separator()) + autostartScriptName + "." + (*it); triedLocations << scriptFile; triedLocations << ":" + scriptFile; } } for (int i=0; i<triedLocations.size(); i++) { if (QFileInfo(triedLocations[i]).exists()) { //執行指令碼 doScript(triedLocations[i], arguments); return; } } qWarning() << "Autostart script not found at: \n" << triedLocations.join("\\n"); }
下面的程式碼用於執行指令碼的統一方法:
void RScriptHandlerEcma::doScript(const QString& scriptFile,const QStringList& arguments) { QFileInfo fi(scriptFile); if (!fi.exists()) { //如果指令碼不存在 qWarning() << QString("RScriptHandlerEcma::doScript: " "file '%1' does not exist").arg(scriptFile); return; } //如果這個指令碼已經被載入過了就返回 if (isIncluded(engine, fi.completeBaseName())) { return; } QScriptValue globalObject = engine->globalObject(); initGlobalVariables(scriptFile); if (!arguments.isEmpty()) { // set global variable args to (command line) arguments: //設定args變數 globalObject.setProperty("args", qScriptValueFromValue(engine,arguments)); } //讀取指令碼 QString contents = readScript(scriptFile, alwaysLoadScripts); if (contents.isEmpty()) { qDebug() << "RScriptHandlerEcma::doScript: script file is empty"; return; } //呼叫檔案 eval(contents, scriptFile); //將檔案加入到直譯器當中 markIncluded(engine, fi.completeBaseName()); }
已經載入的指令碼檔案列表儲存在直譯器中,下面是用於檢測指令碼是否已經載入的程式碼:
bool RScriptHandlerEcma::isIncluded(QScriptEngine* engine, const QString& className) {
if (alwaysLoadScripts && className!="library" && className!="EAction" && className!="WidgetFactory") {
//alwaysLoadScripts:同一個指令碼可以重複載入
//"library"、"EAction"、"WidgetFactory"不能重複載入
// always include (again) to reload potential changes:
return false;
}
QVariant vAlreadyIncluded;
//判斷直譯器中是否有alreadyIncluded這個屬性,alreadyIncluded是一個列表,包含已經載入的所有指令碼
vAlreadyIncluded = engine->property("alreadyIncluded");
if (!vAlreadyIncluded.isValid()) {
//如果直譯器中alreadyIncluded沒有定義,則可以載入
return false;
}
//遍歷指令碼直譯器中的vAlreadyIncluded列表看看是否存在className
QSet<QString> alreadyIncluded;
alreadyIncluded = vAlreadyIncluded.value<QSet<QString> >();
if (!alreadyIncluded.contains(className)) {
return false;
}
return true;
}
void RScriptHandlerEcma::initGlobalVariables(const QString& scriptFile) {
// initialize global ECMA variables:
//初始化全域性變數,設定當前指令碼以及當前指令碼的全路徑
QScriptValue globalObject = engine->globalObject();
globalObject.setProperty("scriptFile", QScriptValue(engine, scriptFile));
globalObject.setProperty("includeBasePath", QScriptValue(engine,
QFileInfo(scriptFile).absolutePath()));
}
當指令碼載入完成後,將指令碼標記為已經包含,程式碼如下:
void RScriptHandlerEcma::markIncluded(QScriptEngine* engine, const QString& className) {
QVariant vAlreadyIncluded;
QSet<QString> alreadyIncluded;
//獲取已經載入的標記
vAlreadyIncluded = engine->property("alreadyIncluded");
if (vAlreadyIncluded.isValid()) {
//如果有效則建立一個QSet物件
alreadyIncluded = vAlreadyIncluded.value<QSet<QString> >();
}
//是否包含js檔案,如果已經包含了就返回
if (alreadyIncluded.contains(className)) {
return;
}
//將類檔案加入到變數當中
alreadyIncluded.insert(className);
vAlreadyIncluded.setValue(alreadyIncluded);
//設定到指令碼直譯器當中
engine->setProperty("alreadyIncluded", vAlreadyIncluded);
}