【问题标题】:Modifying VirtualBox GUI to use kchmviewer if available修改 VirtualBox GUI 以使用 kchmviewer(如果可用)
【发布时间】:2015-10-19 17:27:24
【问题描述】:

注意:我想指出我没有 C/C++ 知识,但我知道bash 所以请尝试提供功能解决方案而不是语言特定的解释。谢谢。

为了更清楚起见,我将把我的问题分成两个不同的部分:

1.)

我正在尝试使以下代码工作:

if (system("which kchmviewer > /dev/null") == 0)
{
    // "which kchmviewer" exit code 0
    #define USE_KCHMVIEWER 1
}
else
{
    // "which kchmviewer" exit code 1
    #define USE_KCHMVIEWER 0
}

说明:检查,运行时kchmviewer在操作系统中是否可用,如果是,将USE_KCHMVIEWER设置为“1”(真) ,否则为“0”(假)。

2.)

我想将上面的代码放到VirtualBox代码库中,然后在以下情况下使用它来代替VBOX_OSE

a.)UIMessageCenter::sltShowHelpHelpDialog(),包含#ifndef VBOX_OSE 的行将被替换为#ifdef USE_KCHMVIEWER
b.)UIMessageCenter::sltShowUserManual(),行包含# ifndef VBOX_OSE 的行将替换为# ifdef USE_KCHMVIEWER
c.)VBoxGlobal::helpFile() 中,包含# if defined VBOX_OSE 的行将替换为# if !defined USE_KCHMVIEWER

// File: VirtualBox-5.0.6/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp

void UIMessageCenter::sltShowHelpHelpDialog()
{
#ifndef VBOX_OSE
    /* For non-OSE version we just open it: */
    sltShowUserManual(vboxGlobal().helpFile());
#else /* #ifndef VBOX_OSE */
    /* For OSE version we have to check if it present first: */
    QString strUserManualFileName1 = vboxGlobal().helpFile();
    QString strShortFileName = QFileInfo(strUserManualFileName1).fileName();
    QString strUserManualFileName2 = QDir(vboxGlobal().homeFolder()).absoluteFilePath(strShortFileName);
    /* Show if user manual already present: */
    if (QFile::exists(strUserManualFileName1))
        sltShowUserManual(strUserManualFileName1);
    else if (QFile::exists(strUserManualFileName2))
        sltShowUserManual(strUserManualFileName2);
    /* If downloader is running already: */
    else if (UIDownloaderUserManual::current())
    {
        /* Just show network access manager: */
        gNetworkManager->show();
    }
    /* Else propose to download user manual: */
    else if (cannotFindUserManual(strUserManualFileName1))
    {
        /* Create User Manual downloader: */
        UIDownloaderUserManual *pDl = UIDownloaderUserManual::create();
        /* After downloading finished => show User Manual: */
        connect(pDl, SIGNAL(sigDownloadFinished(const QString&)), this, SLOT(sltShowUserManual(const QString&)));
        /* Start downloading: */
        pDl->start();
    }
#endif /* #ifdef VBOX_OSE */
}
…
void UIMessageCenter::sltShowUserManual(const QString &strLocation)
{
#if defined (Q_WS_WIN32)
    HtmlHelp(GetDesktopWindow(), strLocation.utf16(), HH_DISPLAY_TOPIC, NULL);
#elif defined (Q_WS_X11)
# ifndef VBOX_OSE
    char szViewerPath[RTPATH_MAX];
    int rc;
    rc = RTPathAppPrivateArch(szViewerPath, sizeof(szViewerPath));
    AssertRC(rc);
    QProcess::startDetached(QString(szViewerPath) + "/kchmviewer", QStringList(strLocation));
# else /* #ifndef VBOX_OSE */
    vboxGlobal().openURL("file://" + strLocation);
# endif /* #ifdef VBOX_OSE */
#elif defined (Q_WS_MAC)
    vboxGlobal().openURL("file://" + strLocation);
#endif
}

// File: VirtualBox-5.0.6/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp

QString VBoxGlobal::helpFile() const
{
#if defined (Q_WS_WIN32)
    const QString name = "VirtualBox";
    const QString suffix = "chm";
#elif defined (Q_WS_MAC)
    const QString name = "UserManual";
    const QString suffix = "pdf";
#elif defined (Q_WS_X11)
# if defined VBOX_OSE
    const QString name = "UserManual";
    const QString suffix = "pdf";
# else
    const QString name = "VirtualBox";
    const QString suffix = "chm";
# endif
#endif
    /* Where are the docs located? */
    char szDocsPath[RTPATH_MAX];
    int rc = RTPathAppDocs (szDocsPath, sizeof (szDocsPath));
    AssertRC (rc);
    /* Make sure that the language is in two letter code.
     * Note: if languageId() returns an empty string lang.name() will
     * return "C" which is an valid language code. */
    QLocale lang (VBoxGlobal::languageId());

    /* Construct the path and the filename */
    QString manual = QString ("%1/%2_%3.%4").arg (szDocsPath)
                                            .arg (name)
                                            .arg (lang.name())
                                            .arg (suffix);
    /* Check if a help file with that name exists */
    QFileInfo fi (manual);
    if (fi.exists())
        return manual;

    /* Fall back to the standard */
    manual = QString ("%1/%2.%4").arg (szDocsPath)
                                 .arg (name)
                                 .arg (suffix);
    return manual;
}

底线

如何做到这一点?我的操作系统是Trisquel 7.0 (GNU/Linux)。

感谢您的建议。

P.S.:更多详情请见this forum thread

P.P.S.:由于我还不知道如何仅重建源代码的特定部分,因此尝试您的解决方案很可能需要我重新编译整个应用程序,然后我才能检查它是否工作与否。这可能需要一个小时或更长时间,请耐心等待。

更新:重新表述问题以反映我的发现。这次我尽量做到具体一点。

【问题讨论】:

  • 如果进行如此小的更改“可能需要重新编译整个应用程序 [这] 可能需要一个小时或更长时间” 那么 1) 你的代码过度耦合和 2) 你的构建系统由 Rube Goldberg 设计。
  • @LightnessRacesinOrbit:因为我必须这样做。我还没有从开发人员那里得到帮助,所以我自己尝试这样做。
  • 您想在构建时还是在运行时检查kchmviewer
  • @Beta:这是因为我不知道如何仅重新编译已更改的部分。有可能,就是不知道怎么办。
  • @mYself if (system("which kchmviewer") != 0) 可能不会返回您期望的值,请参阅reference docs

标签: c++ qt g++ virtualbox c-preprocessor


【解决方案1】:

您在system("which kchmviewer") 的上一个论坛帖子几乎是正确的。您只需要在if 上方声明QString name, suffix; 并跳过{} 块中的const QString。但是,它仅适用于 Linux,因为 which 不适用于 Windows。

由于您的项目使用 Qt,您可以使用 QProcess 来检查 which 命令的退出代码(如果该命令退出):

QString name = "UserManual";
QString suffix = "pdf";

if (QProcess::execute("which kchmviewer") == 0)
{
    // "which kchmviewer" exit code 0
    name = "VirtualBox";
    suffix = "chm";
}

这是为你的功能helpFile()

但是,您可以尝试在sltShowUserManual() 中通过QProcess::startDetached() 直接启动kchmviewer。如果失败,startDetached() 的返回值为false。在这种情况下,您可以使用 pdf 转到默认行为。

【讨论】:

  • 可以使用QProcess::startDetached()QProcess::exitCode() 中的任何一个来检查kchmviewer 是否可用于多平台方式?我不打算在 GNU/Linux 之外编译 VirtualBox,但我更喜欢进行不是以特定于平台的方式编写的更改,前提是它们足够简单。
  • @mYself 我用更简单的QProcess::execute() 更新了答案。它作为system 工作,但是该函数的返回值已明确定义doc.qt.io/qt-5/qprocess.html#execute 但是,它仍然仅适用于Unix,因为它调用whichQProcess::startDetached() 可用于多平台解决方案,但我不确定您是否要在 Windows 上运行 kchmviewer
  • 不,我不打算在 Windows 上使用它。我之所以这么提议,是因为我打算发布一组命令来构建具有特定更改的 VirtualBox,并且我不想阻止其他人在其他平台上构建程序。
  • 我尝试了第一段中的建议,编译通过了修改后的 C++ 文件。由于这需要一些时间,我会在正确测试您提出的所有不同解决方案并在 Internet 上四处寻找解释后回信。非常感谢您的帮助。
  • 抱歉回复晚了,但我没有注意到我昨天回信的时间,我不得不去睡觉。现在我多次重新编译 VirtualBox 以检查不同解决方案的行为,我意识到我犯了一些错误:„1.) 我忘记将 which kchmviewer 的输出重定向到 /dev/null (适用于system(),但不适用于QProcess::execute()); 2.) 你对sltShowUserManual() 的看法是对的,我也需要更改,否则kchmviewer 会将所有内容输出到标准输出,这不是预期的行为; 3.) 我还需要更改`sltShowHelpH...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多