Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
assistantclient.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qstring.h>
8#include <QtCore/qprocess.h>
9#include <QtCore/qdir.h>
10#include <QtCore/qlibraryinfo.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qfileinfo.h>
13#include <QtCore/qobject.h>
14#include <QtCore/qtextstream.h>
15#include <QtCore/qcoreapplication.h>
16
18
19using namespace Qt::StringLiterals;
20
21constexpr bool debugAssistantClient = false;
22
23AssistantClient::AssistantClient() = default;
24
26{
27 if (isRunning()) {
28 QString errorMessage;
29 if (!sendCommand("quit"_L1, &errorMessage) || !m_process->waitForFinished(1000)) {
30 m_process->terminate();
31 m_process->waitForFinished();
32 }
33 }
34 delete m_process;
35}
36
37bool AssistantClient::showPage(const QString &path, QString *errorMessage)
38{
39 const QString cmd = "SetSource "_L1 + path;
40 return sendCommand(cmd, errorMessage);
41}
42
43bool AssistantClient::activateIdentifier(const QString &identifier, QString *errorMessage)
44{
45 const QString cmd = "ActivateIdentifier "_L1 + identifier;
46 return sendCommand(cmd, errorMessage);
47}
48
49bool AssistantClient::sendCommand(const QString &cmd, QString *errorMessage)
50{
51 if constexpr (debugAssistantClient)
52 qDebug() << "sendCommand " << cmd;
53 if (!ensureRunning(errorMessage))
54 return false;
55 if (!m_process->isWritable() || m_process->bytesToWrite() > 0) {
56 *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to send request: Assistant is not responding.");
57 return false;
58 }
59 QTextStream str(m_process);
60 str << cmd << "\n\n";
61 return true;
62}
63
65{
66 return m_process && m_process->state() != QProcess::NotRunning;
67}
68
69QString AssistantClient::binary()
70{
71 QString app = QLibraryInfo::paths(QLibraryInfo::BinariesPath).value(0) + QDir::separator();
72#if defined(Q_OS_WIN)
73 app += "assistant.exe"_L1;
74#elif !defined(Q_OS_MACOS)
75 app += "assistant"_L1;
76#else
77 app += "Assistant.app/Contents/MacOS/Assistant"_L1;
78#endif
79
80
81 return app;
82}
83
84void AssistantClient::readyReadStandardError()
85{
86 qWarning("%s: %s",
87 qPrintable(QDir::toNativeSeparators(m_process->program())),
88 m_process->readAllStandardError().constData());
89}
90
91void AssistantClient::processTerminated(int exitCode, QProcess::ExitStatus exitStatus)
92{
93 const QString binary = QDir::toNativeSeparators(m_process->program());
94 if (exitStatus != QProcess::NormalExit)
95 qWarning("%s: crashed.", qPrintable(binary));
96 else if (exitCode != 0)
97 qWarning("%s: terminated with exit code %d.", qPrintable(binary), exitCode);
98}
99
100bool AssistantClient::ensureRunning(QString *errorMessage)
101{
102 if (isRunning())
103 return true;
104
105 if (!m_process) {
106 m_process = new QProcess;
107 auto exitHandler = [this](int exitCode, QProcess::ExitStatus exitStatus) { this->processTerminated(exitCode, exitStatus); };
108 QObject::connect(m_process, &QProcess::finished, m_process, exitHandler);
109 auto readHandler = [this]() { this->readyReadStandardError(); };
110 QObject::connect(m_process, &QProcess::readyReadStandardError, m_process, readHandler);
111 }
112
113 const QString app = binary();
114 if (!QFileInfo(app).isFile()) {
115 *errorMessage = QCoreApplication::translate("AssistantClient", "The binary '%1' does not exist.").arg(app);
116 return false;
117 }
118 if constexpr (debugAssistantClient)
119 qDebug() << "Running " << app;
120 // run
121 QStringList args{u"-enableRemoteControl"_s};
122
123 m_process->start(app, args);
124
125 if (!m_process->waitForStarted()) {
126 *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to launch assistant (%1).").arg(app);
127 return false;
128 }
129 return true;
130}
131
132QString AssistantClient::documentUrl(const QString &module) const
133{
134 const int qtVersion = QT_VERSION;
135 QString rc;
136 QTextStream(&rc) << "qthelp://org.qt-project." << module << '.'
137 << (qtVersion >> 16) << ((qtVersion >> 8) & 0xFF) << (qtVersion & 0xFF)
138 << '/' << module << '/';
139 return rc;
140}
141
142QT_END_NAMESPACE
constexpr bool debugAssistantClient
bool isRunning() const
bool showPage(const QString &path, QString *errorMessage) override
~AssistantClient() override
bool activateIdentifier(const QString &identifier, QString *errorMessage) override
QString documentUrl(const QString &module) const override
Combined button and popup list for selecting options.