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

猜你喜欢

转载自blog.csdn.net/tianyapai/article/details/84753601
今日推荐