1. 程式人生 > >QCad原始碼分析 第三章

QCad原始碼分析 第三章

     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);
}