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
qdesigner.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
5// designer
6#include "qdesigner.h"
11#include "mainwindow.h"
12#include <QtDesigner/abstractintegration.h>
13#include <QtDesigner/abstractformeditor.h>
14#include <qdesigner_propertysheet_p.h>
15
16#include <QtGui/qevent.h>
17#include <QtWidgets/qmessagebox.h>
18#include <QtGui/qicon.h>
19#include <QtWidgets/qerrormessage.h>
20#include <QtCore/qmetaobject.h>
21#include <QtCore/qdir.h>
22#include <QtCore/qfile.h>
23#include <QtCore/qlocale.h>
24#include <QtCore/qtextstream.h>
25#include <QtCore/qtimer.h>
26#include <QtCore/qtranslator.h>
27#include <QtCore/qfileinfo.h>
28#include <QtCore/qdebug.h>
29#include <QtCore/qcommandlineparser.h>
30#include <QtCore/qcommandlineoption.h>
31#include <QtCore/qvariant.h>
32
33#include <QtDesigner/QDesignerComponents>
34
35QT_BEGIN_NAMESPACE
36
37using namespace Qt::StringLiterals;
38
39static constexpr auto designerApplicationName = "Designer"_L1;
40static constexpr auto designerDisplayName = "Qt Widgets Designer"_L1;
41static constexpr auto designerWarningPrefix = "Designer: "_L1;
43
44static void designerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
45{
46 // Only Designer warnings are displayed as box
47 QDesigner *designerApp = qDesigner;
48 if (type != QtWarningMsg || !designerApp || !msg.startsWith(designerWarningPrefix)) {
49 previousMessageHandler(type, context, msg);
50 return;
51 }
52 designerApp->showErrorMessage(msg);
53}
54
55QDesigner::QDesigner(int &argc, char **argv)
57{
58 setOrganizationName(u"QtProject"_s);
59 QGuiApplication::setApplicationDisplayName(designerDisplayName);
60 setApplicationName(designerApplicationName);
61 QDesignerComponents::initializeResources();
62
63#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN)
64 setWindowIcon(QIcon(u":/qt-project.org/designer/images/designer.png"_s));
65#endif
66}
67
69{
70 delete m_workbench;
71 delete m_server;
72 delete m_client;
73}
74
75void QDesigner::showErrorMessage(const QString &message)
76{
77 // strip the prefix
78 const QString qMessage =
79 message.right(message.size() - int(designerWarningPrefix.size()));
80 // If there is no main window yet, just store the message.
81 // The QErrorMessage would otherwise be hidden by the main window.
82 if (m_mainWindow) {
83 showErrorMessageBox(qMessage);
84 } else {
85 const QMessageLogContext emptyContext;
86 previousMessageHandler(QtWarningMsg, emptyContext, message); // just in case we crash
87 m_initializationErrors += qMessage;
88 m_initializationErrors += u'\n';
89 }
90}
91
92void QDesigner::showErrorMessageBox(const QString &msg)
93{
94 // Manually suppress consecutive messages.
95 // This happens if for example sth is wrong with custom widget creation.
96 // The same warning will be displayed by Widget box D&D and form Drop
97 // while trying to create instance.
98 if (m_errorMessageDialog && m_lastErrorMessage == msg)
99 return;
100
101 if (!m_errorMessageDialog) {
102 m_lastErrorMessage.clear();
103 m_errorMessageDialog = new QErrorMessage(m_mainWindow);
104 const QString title = QCoreApplication::translate("QDesigner", "%1 - warning").arg(designerApplicationName);
105 m_errorMessageDialog->setWindowTitle(title);
106 m_errorMessageDialog->setMinimumSize(QSize(600, 250));
107 }
108 m_errorMessageDialog->showMessage(msg);
109 m_lastErrorMessage = msg;
110}
111
113{
114 return m_workbench;
115}
116
117static void showHelp(QCommandLineParser &parser, const QString &errorMessage = QString())
118{
119 QString text;
120 QTextStream str(&text);
121 str << "<html><head/><body>";
122 if (!errorMessage.isEmpty())
123 str << "<p>" << errorMessage << "</p>";
124 str << "<pre>" << parser.helpText().toHtmlEscaped() << "</pre></body></html>";
125 QMessageBox box(errorMessage.isEmpty() ? QMessageBox::Information : QMessageBox::Warning,
126 QGuiApplication::applicationDisplayName(), text,
127 QMessageBox::Ok);
128 box.setTextInteractionFlags(Qt::TextBrowserInteraction);
129 box.exec();
130}
131
132static inline QDesigner::ParseArgumentsResult
133 parseDesignerCommandLineArguments(QCommandLineParser &parser, Options *options,
134 QString *errorMessage)
135{
136 parser.setApplicationDescription(u"Qt Widgets Designer " QT_VERSION_STR "\n\nUI designer for QWidget-based applications."_s);
137 const QCommandLineOption helpOption = parser.addHelpOption();
138 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
139 const QCommandLineOption localSocketClientOption(u"local-client"_s,
140 u"Local socket client mode"_s,
141 u"server_name"_s);
142 parser.addOption(localSocketClientOption);
143 const QCommandLineOption tcpServerOption(u"server"_s, u"TCP Server mode (deprecated)"_s);
144 parser.addOption(tcpServerOption);
145 const QCommandLineOption tcpClientOption(u"client"_s, u"TCP Client mode (deprecated)"_s,
146 u"port"_s);
147 parser.addOption(tcpClientOption);
148 const QCommandLineOption webHelpOption(u"web-help"_s, u"Use the Web documentation"_s);
149 parser.addOption(webHelpOption);
150 const QCommandLineOption pythonHelpOption(u"python-help"_s, u"Use the Python documentation"_s);
151 parser.addOption(pythonHelpOption);
152 const QCommandLineOption resourceDirOption(u"resourcedir"_s,
153 u"Resource directory"_s,
154 u"directory"_s);
155 parser.addOption(resourceDirOption);
156 const QCommandLineOption internalDynamicPropertyOption(u"enableinternaldynamicproperties"_s,
157 u"Enable internal dynamic properties"_s);
158 parser.addOption(internalDynamicPropertyOption);
159 const QCommandLineOption pluginPathsOption(u"plugin-path"_s,
160 u"Default plugin path list"_s,
161 u"path"_s);
162 parser.addOption(pluginPathsOption);
163
164 const QCommandLineOption qtVersionOption(u"qt-version"_s,
165 u"Qt Version for writing .ui files"_s,
166 u"version"_s);
167 parser.addOption(qtVersionOption);
168
169 parser.addPositionalArgument(u"files"_s,
170 u"The UI files to open."_s);
171
172 if (!parser.parse(QCoreApplication::arguments())) {
173 *errorMessage = parser.errorText();
174 return QDesigner::ParseArgumentsError;
175 }
176
177 if (parser.isSet(helpOption))
178 return QDesigner::ParseArgumentsHelpRequested;
179 // There is no way to retrieve the complete help text from QCommandLineParser,
180 // so, call process() to display it.
181 if (parser.isSet(u"help-all"_s))
182 parser.process(QCoreApplication::arguments()); // exits
183 options->server = parser.isSet(tcpServerOption);
184 if (parser.isSet(localSocketClientOption)) {
185 options->localSocketServerName = parser.value(localSocketClientOption);
186 } else if (parser.isSet(tcpClientOption)) {
187 bool ok = false;
188 options->tcpClientPort = parser.value(tcpClientOption).toUShort(&ok);
189 if (!ok) {
190 *errorMessage = u"Non-numeric argument specified for -client"_s;
191 return QDesigner::ParseArgumentsError;
192 }
193 }
194 if (parser.isSet(webHelpOption))
196 else if (parser.isSet(pythonHelpOption))
198 if (parser.isSet(resourceDirOption))
199 options->resourceDir = parser.value(resourceDirOption);
200 const auto pluginPathValues = parser.values(pluginPathsOption);
201 for (const auto &pluginPath : pluginPathValues)
202 options->pluginPaths.append(pluginPath.split(QDir::listSeparator(), Qt::SkipEmptyParts));
203
204 if (parser.isSet(qtVersionOption))
205 options->qtVersion = QVersionNumber::fromString(parser.value(qtVersionOption));
206
207 options->enableInternalDynamicProperties = parser.isSet(internalDynamicPropertyOption);
208 options->files = parser.positionalArguments();
209 return QDesigner::ParseArgumentsSuccess;
210}
211
213{
214 QString errorMessage;
215 Options options;
216 QCommandLineParser parser;
217 const ParseArgumentsResult result = parseDesignerCommandLineArguments(parser, &options, &errorMessage);
218 if (result != ParseArgumentsSuccess) {
219 showHelp(parser, errorMessage);
220 return result;
221 }
222 // initialize the sub components
223 if (!options.localSocketServerName.isEmpty())
224 m_client = new QDesignerLocalSocketClient(options.localSocketServerName, this);
225 else if (options.tcpClientPort != 0)
226 m_client = new QDesignerTcpClient(options.tcpClientPort, this);
227 if (options.server) {
228 auto *server = new QDesignerTcpServer();
229 m_server = server;
230 printf("%d\n", server->serverPort());
231 fflush(stdout);
232 }
233 if (options.enableInternalDynamicProperties)
234 QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(true);
235
236 std::unique_ptr<QTranslator> designerTranslator(new QTranslator(this));
237 if (designerTranslator->load(QLocale(), u"designer"_s, u"_"_s, options.resourceDir)) {
238 installTranslator(designerTranslator.release());
239 std::unique_ptr<QTranslator> qtTranslator(new QTranslator(this));
240 if (qtTranslator->load(QLocale(), u"qt"_s, u"_"_s, options.resourceDir))
241 installTranslator(qtTranslator.release());
242 }
243
244 m_workbench = new QDesignerWorkbench(options);
245
246 emit initialized();
247 previousMessageHandler = qInstallMessageHandler(designerMessageHandler); // Warn when loading faulty forms
248 Q_ASSERT(previousMessageHandler);
249
250 bool suppressNewFormShow = m_workbench->readInBackup();
251
252 for (auto fileName : std::as_const(options.files)) {
253 // Ensure absolute paths for recent file list to be unique
254 const QFileInfo fi(fileName);
255 if (fi.exists() && fi.isRelative())
256 fileName = fi.absoluteFilePath();
257 m_workbench->readInForm(fileName);
258 }
259
260 if (m_workbench->formWindowCount() > 0)
261 suppressNewFormShow = true;
262
263 if (options.qtVersion.has_value()) {
264#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
265 m_workbench->core()->integration()->setQtVersion(options.qtVersion.value());
266#else
267 auto version = QVariant::fromValue(options.qtVersion.value());
268 m_workbench->core()->integration()->setProperty("qtVersion", version);
269#endif
270 }
271
272 // Show up error box with parent now if something went wrong
273 if (m_initializationErrors.isEmpty()) {
274 if (!isServerOrClientEnabled() && !suppressNewFormShow)
275 m_workbench->showNewForm();
276 } else {
277 showErrorMessageBox(m_initializationErrors);
278 m_initializationErrors.clear();
279 }
280 return result;
281}
282
284{
285 return m_server || m_client;
286}
287
288bool QDesigner::event(QEvent *ev)
289{
290 bool eaten = false;
291 switch (ev->type()) {
292 case QEvent::FileOpen:
293 m_workbench->readInForm(static_cast<QFileOpenEvent *>(ev)->file());
294 m_workbench->requestActivate();
295 eaten = true;
296 break;
297 case QEvent::Close: {
298 auto *closeEvent = static_cast<QCloseEvent *>(ev);
299 closeEvent->setAccepted(m_workbench->handleClose());
300 if (closeEvent->isAccepted()) {
301 // We're going down, make sure that we don't get our settings saved twice.
302 if (m_mainWindow)
303 m_mainWindow->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents);
304 QApplication::event(ev);
305 }
306 eaten = true;
307 break;
308 }
309 default:
310 eaten = QApplication::event(ev);
311 break;
312 }
313 return eaten;
314}
315
317{
318 m_mainWindow = tw;
319}
320
322{
323 return m_mainWindow;
324}
325
326QT_END_NAMESPACE
QDesignerFormEditorInterface * core() const
ParseArgumentsResult parseCommandLineArguments()
QDesigner(int &argc, char **argv)
Definition qdesigner.cpp:55
bool event(QEvent *ev) override
\reimp
void setMainWindow(MainWindowBase *tw)
QDesignerWorkbench * workbench() const
bool isServerOrClientEnabled() const
~QDesigner() override
Definition qdesigner.cpp:68
MainWindowBase * mainWindow() const
HelpClientType
Definition helpclient.h:17
static constexpr auto designerWarningPrefix
Definition qdesigner.cpp:41
static QDesigner::ParseArgumentsResult parseDesignerCommandLineArguments(QCommandLineParser &parser, Options *options, QString *errorMessage)
static void showHelp(QCommandLineParser &parser, const QString &errorMessage=QString())
static void designerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
Definition qdesigner.cpp:44
static constexpr auto designerApplicationName
Definition qdesigner.cpp:39
static QtMessageHandler previousMessageHandler
Definition qdesigner.cpp:42
static constexpr auto designerDisplayName
Definition qdesigner.cpp:40
#define qDesigner
Definition qdesigner.h:20
bool server
Definition qdesigner.h:37
bool enableInternalDynamicProperties
Definition qdesigner.h:39
HelpClientType helpMode
Definition qdesigner.h:40