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

QCad原始碼分析 第一章

   鑑於介紹Qcad相關的文章很少,決定寫此部落格,一來便於日後查詢,二來要有分享精神。本文章基於Qcad3 .21.3.4的開源版本進行分析,分過程中難免有疏漏,如果有新的發現會及時更改,不足之處望高手指正,十分感謝。

   QCad是一款2維的cad軟體,基於Qt類庫開發,邏輯處理方面夾雜著QtScript,所以首先要熟悉javascript,js相關文章不在贅述,其次QtScript的使用方面,詳細閱讀Qt官方文件Qt Script。

    首先講一下QCad軟體中的簡單啟動過程,也就是程式碼中的main函式,QCad是一款跨平臺的軟體,暫時之講解window平臺的原始碼。

int main(int argc, char *argv[]) {
    qDebug() << "QCAD version " << R_QCAD_VERSION_STRING;
    // For correct Unicode translation, apply the current system locale:
    setlocale(LC_ALL, "");
    // But use usual conversion for scanf()/sprintf():
    setlocale(LC_NUMERIC, "C");

    // Finetuning Japanese encoding for correct DXF/DWG import.
    // see http://qt-project.org/doc/qt-4.8/codecs-jis.html
#ifdef Q_OS_WIN
    _putenv_s("UNICODEMAP_JP", "cp932");
#else
    setenv("UNICODEMAP_JP", "cp932", 1);
#endif

#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050200
    // enable OpenGL logging under Windows
    // this info can then be shown in the about dialog
    QLoggingCategory::setFilterRules(QStringLiteral("qt.qpa.gl=true"));
#endif
#endif

    // Auto scale up user interface for high res displays under Windows:
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050600
    //_putenv_s("QT_SCALE_FACTOR", "auto");
    _putenv_s("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
#else
    _putenv_s("QT_DEVICE_PIXEL_RATIO", "auto");
#endif
#endif

#ifdef Q_OS_MAC
    // TODO: fix linking with objective c
    removeMacMenus();
#endif

    // these are defaults:
    //新增組織、公司、版本資訊
    qApp->setOrganizationName("QCAD");
    qApp->setOrganizationDomain("QCAD.org");
    qApp->setApplicationName("QCAD");
    qApp->setApplicationVersion(RSettings::getVersionString());

    //除錯輸出重定義
    RMainWindow::installMessageHandler();

#if QT_VERSION >= 0x050000
    //高畫素比
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif

#ifdef Q_OS_MAC
    // TODO: make available as script function:
    QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus);

    if (QSysInfo::MacintoshVersion>=0x000B) {
        // system font change bug fix on OS X 10.9 (Mavericks):
        QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
    }
#endif

    //產生隨機數
    QTime time = QTime::currentTime();
    qsrand((uint)time.msec());

    //設定原始引數到RSettings當中
    QStringList originalArguments;
    for (int i=0; i<argc; i++) {
        QString a = argv[i];
        originalArguments.append(a);
    }
    RSettings::setOriginalArguments(originalArguments);

    //得到應用程式的id,用於一個終端只能啟用一個QCad程式
    QString appId = "QCAD";
    for (int i=0; i<argc; i++) {
        QString a = argv[i];
        if (a=="-app-id" && i+1<argc) {
            appId = argv[i+1];
        }
    }

    //是否啟用幫助介面
    bool guiEnabled = true;
    for (int i=1; i<argc; i++) {
        if (!strcmp(argv[i], "-no-gui") || !strcmp(argv[i], "-help")) {
            //如果設定-no-gui或者-help引數,則不啟用介面
            guiEnabled = false;
        }
    }

    //應用程式的派生類,派生主要用於一個終端只能啟用一個QCad程式中的本地服務通訊
    RSingleApplication* app = new RSingleApplication(appId, argc, argv, guiEnabled);

#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
    // note that SIGPIPE is only ignored in release mode, gdb catches SIGPIPE
    // by default. To disable that behavior in gdb, use:
    // handle SIGPIPE nostop noprint pass
    signal(SIGPIPE,catchSigPipe);
#endif

#ifdef Q_OS_MAC
    // activate Mac OS X dock icon if desired:
    if (!app->arguments().contains("-no-dock-icon") &&
            !app->arguments().contains("-help") && !app->arguments().contains("-h") &&
            !app->arguments().contains("-version") && !app->arguments().contains("-v")) {
        ProcessSerialNumber psn;
        if (GetCurrentProcess(&psn) == noErr) {
            TransformProcessType(&psn, kProcessTransformToForegroundApplication);
        }
    }
#endif
    if (!app->arguments().contains("-allow-multiple-instances")) {
        //如果程序不允許多例項
        // send arguments to running instance for further processing:
        if (app->sendMessage(app->arguments().join("\n"), 30000)) {
            qWarning("Application already running. Aborting...");
            return 0;
        }
    }

#ifdef Q_OS_WIN
    // SVG icons are only rendered if this line is present under windows:
    QImageReader::supportedImageFormats();

    // the SQLite plugin can only be loaded if this line is present under windows:
    QSqlDatabase::drivers();
#endif

    //註冊RColor型別到元物件系統
    qRegisterMetaType<RColor>();
    //將RColor註冊到流操縱當中去,RColor支援<<操作
    qRegisterMetaTypeStreamOperators<RColor>("RColor");

    //註冊RVector型別到元物件系統
    qRegisterMetaType<RVector>();
    //將RColor註冊到流操縱當中去,RVector支援<<操作
    qRegisterMetaTypeStreamOperators<RVector>("RVector");

    //獲取當前路徑
    QString cwd = QDir::currentPath();
    //設定釋出路徑
    RSettings::setLaunchPath(cwd);

    // set current working directory:
    //將應用程式所在的目錄設為當前目錄
    QDir::setCurrent(RSettings::getApplicationPath());

    // disable Qt library paths to avoid plugins for Qt designer from being found:
    QStringList pluginPaths = RSettings::getPluginPaths();
    if (pluginPaths.isEmpty()) {
        qWarning() << "No plugin paths found";
        return -1;
    }
    //設定庫路徑,查詢dll時將在此目錄下查詢
    app->setLibraryPaths(pluginPaths);
    //數學庫
    RMath::init();
    //載入字型
    RFontList::init();
    //載入填充圖形
    RPatternListMetric::init();
    RPatternListImperial::init();

    // init object properties:
    //初始化物件屬性id
    RObject::init();
    REntity::init();
    RDocumentVariables::init();

    RArcEntity::init();
    RBlockReferenceEntity::init();
    RCircleEntity::init();
    RDimensionEntity::init();
    RDimLinearEntity::init();
    RDimAlignedEntity::init();
    RDimAngularEntity::init();
    RDimAngular2LEntity::init();
    RDimAngular3PEntity::init();
    RDimArcLengthEntity::init();
    RDimDiametricEntity::init();
    RDimOrdinateEntity::init();
    RDimRadialEntity::init();
    RDimRotatedEntity::init();
    REllipseEntity::init();
    RImageEntity::init();
    RHatchEntity::init();
    RLeaderEntity::init();
    RLineEntity::init();
    RPointEntity::init();
    RPolylineEntity::init();
    RSolidEntity::init();
    RTraceEntity::init();
    RFaceEntity::init();
    RSplineEntity::init();
    RXLineEntity::init();
    RRayEntity::init();
    RViewportEntity::init();

    RTextBasedEntity::init();
    RTextEntity::init();
    RAttributeDefinitionEntity::init();
    RAttributeEntity::init();

    RUcs::init();
    RLayer::init();
    RLayout::init();
    RLinetype::init();
    RBlock::init();
    RView::init();

    // make sure plugins can find plugin related settings:
    // these are always stored in "QCAD3.ini/conf":
    //過載應用程式名稱【】
    RSettings::setApplicationNameOverride("QCAD3");
    //外掛管理類
    RPluginLoader::loadPlugins(true);
    //初始化線型檔案
    RLinetypeListMetric::init();
    RLinetypeListImperial::init();

    // check for autostart option:
    //檢查自動指令碼選項
    QString autostartFile;
    //獲取引數列表,並從引數列表中查詢是否有啟動的指令碼檔案
    QStringList arguments = app->arguments();
    int i = arguments.indexOf("-autostart");
    if (i!=-1 && arguments.count()>i+1) {
        autostartFile = arguments.at(i+1);
    }

    //將指令碼的工廠函式和指令碼型別註冊到系統當中,【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;

    
    RPluginLoader::unloadPlugins();

    RSettings::uninit();
    RFontList::uninit();
    RPatternListMetric::uninit();
    RPatternListImperial::uninit();
    RSingleton::cleanUp();
    RMath::uninit();

    RDocumentInterface::deleteClipboard();

    //RDebug::printCounters();

    return ret;
}