1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "assistantclient.h"
30
31#include <QtCore/qstring.h>
32#include <QtCore/qprocess.h>
33#include <QtCore/qdir.h>
34#include <QtCore/qlibraryinfo.h>
35#include <QtCore/qdebug.h>
36#include <QtCore/qfileinfo.h>
37#include <QtCore/qobject.h>
38#include <QtCore/qtextstream.h>
39#include <QtCore/qcoreapplication.h>
40
41QT_BEGIN_NAMESPACE
42
43enum { debugAssistantClient = 0 };
44
45AssistantClient::AssistantClient() = default;
46
47AssistantClient::~AssistantClient()
48{
49 if (isRunning()) {
50 m_process->terminate();
51 m_process->waitForFinished();
52 }
53 delete m_process;
54}
55
56bool AssistantClient::showPage(const QString &path, QString *errorMessage)
57{
58 QString cmd = QStringLiteral("SetSource ");
59 cmd += path;
60 return sendCommand(cmd, errorMessage);
61}
62
63bool AssistantClient::activateIdentifier(const QString &identifier, QString *errorMessage)
64{
65 QString cmd = QStringLiteral("ActivateIdentifier ");
66 cmd += identifier;
67 return sendCommand(cmd, errorMessage);
68}
69
70bool AssistantClient::activateKeyword(const QString &keyword, QString *errorMessage)
71{
72 QString cmd = QStringLiteral("ActivateKeyword ");
73 cmd += keyword;
74 return sendCommand(cmd, errorMessage);
75}
76
77bool AssistantClient::sendCommand(const QString &cmd, QString *errorMessage)
78{
79 if (debugAssistantClient)
80 qDebug() << "sendCommand " << cmd;
81 if (!ensureRunning(errorMessage))
82 return false;
83 if (!m_process->isWritable() || m_process->bytesToWrite() > 0) {
84 *errorMessage = QCoreApplication::translate(context: "AssistantClient", key: "Unable to send request: Assistant is not responding.");
85 return false;
86 }
87 QTextStream str(m_process);
88 str << cmd << QLatin1Char('\n') << Qt::endl;
89 return true;
90}
91
92bool AssistantClient::isRunning() const
93{
94 return m_process && m_process->state() != QProcess::NotRunning;
95}
96
97QString AssistantClient::binary()
98{
99 QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator();
100#if !defined(Q_OS_MACOS)
101 app += QStringLiteral("assistant");
102#else
103 app += QStringLiteral("Assistant.app/Contents/MacOS/Assistant");
104#endif
105
106#if defined(Q_OS_WIN)
107 app += QStringLiteral(".exe");
108#endif
109
110 return app;
111}
112
113void AssistantClient::readyReadStandardError()
114{
115 qWarning(msg: "%s: %s",
116 qPrintable(QDir::toNativeSeparators(m_process->program())),
117 m_process->readAllStandardError().constData());
118}
119
120void AssistantClient::processTerminated(int exitCode, QProcess::ExitStatus exitStatus)
121{
122 const QString binary = QDir::toNativeSeparators(pathName: m_process->program());
123 if (exitStatus != QProcess::NormalExit)
124 qWarning(msg: "%s: crashed.", qPrintable(binary));
125 else if (exitCode != 0)
126 qWarning(msg: "%s: terminated with exit code %d.", qPrintable(binary), exitCode);
127}
128
129bool AssistantClient::ensureRunning(QString *errorMessage)
130{
131 if (isRunning())
132 return true;
133
134 if (!m_process) {
135 m_process = new QProcess;
136 QObject::connect(sender: m_process, signal: QOverload<int, QProcess::ExitStatus>::of(ptr: &QProcess::finished),
137 receiver: this, slot: &AssistantClient::processTerminated);
138 QObject::connect(sender: m_process, signal: &QProcess::readyReadStandardError,
139 receiver: this, slot: &AssistantClient::readyReadStandardError);
140 }
141
142 const QString app = binary();
143 if (!QFileInfo(app).isFile()) {
144 *errorMessage = QCoreApplication::translate(context: "AssistantClient", key: "The binary '%1' does not exist.").arg(a: app);
145 return false;
146 }
147 if (debugAssistantClient)
148 qDebug() << "Running " << app;
149 // run
150 QStringList args(QStringLiteral("-enableRemoteControl"));
151 m_process->start(program: app, arguments: args);
152 if (!m_process->waitForStarted()) {
153 *errorMessage = QCoreApplication::translate(context: "AssistantClient", key: "Unable to launch assistant (%1).").arg(a: app);
154 return false;
155 }
156 return true;
157}
158
159QString AssistantClient::documentUrl(const QString &module, int qtVersion)
160{
161 if (qtVersion == 0)
162 qtVersion = QT_VERSION;
163 QString rc;
164 QTextStream(&rc) << "qthelp://org.qt-project." << module << '.'
165 << (qtVersion >> 16) << ((qtVersion >> 8) & 0xFF) << (qtVersion & 0xFF)
166 << '/' << module << '/';
167 return rc;
168}
169
170QString AssistantClient::designerManualUrl(int qtVersion)
171{
172 return documentUrl(QStringLiteral("qtdesigner"), qtVersion);
173}
174
175QString AssistantClient::qtReferenceManualUrl(int qtVersion)
176{
177 return documentUrl(QStringLiteral("qtdoc"), qtVersion);
178}
179
180QT_END_NAMESPACE
181

source code of qttools/src/designer/src/designer/assistantclient.cpp