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_actions.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
6#include "helpclient.h"
8#include <qdesigner_utils_p.h>
9#include "qdesigner.h"
13#include "mainwindow.h"
14#include "newform.h"
15#include "versiondialog.h"
18#include "appfontdialog.h"
19
20#include <pluginmanager_p.h>
21#include <qdesigner_formbuilder_p.h>
22#include <iconloader_p.h>
23#include <previewmanager_p.h>
24#include <codedialog_p.h>
25#include <qdesigner_formwindowmanager_p.h>
26
27// sdk
28#include <QtDesigner/abstractformeditor.h>
29#include <QtDesigner/abstractformwindow.h>
30#include <QtDesigner/abstractintegration.h>
31#include <QtDesigner/abstractlanguage.h>
32#include <QtDesigner/abstractmetadatabase.h>
33#include <QtDesigner/abstractformwindowmanager.h>
34#include <QtDesigner/abstractformwindowcursor.h>
35#include <QtDesigner/abstractformeditorplugin.h>
36#include <QtDesigner/qextensionmanager.h>
37
38#include <QtDesigner/private/shared_settings_p.h>
39#include <QtDesigner/private/formwindowbase_p.h>
40
41#include <QtWidgets/qstylefactory.h>
42#include <QtWidgets/qfiledialog.h>
43#include <QtWidgets/qmenu.h>
44#include <QtWidgets/qmessagebox.h>
45#include <QtWidgets/qmdisubwindow.h>
46#include <QtWidgets/qpushbutton.h>
47#include <QtWidgets/qstatusbar.h>
48
49#include <QtGui/qaction.h>
50#include <QtGui/qactiongroup.h>
51#include <QtGui/qevent.h>
52#include <QtGui/qicon.h>
53#include <QtGui/qimage.h>
54#include <QtGui/qpixmap.h>
55#include <QtGui/qscreen.h>
56#if defined(QT_PRINTSUPPORT_LIB) // Some platforms may not build QtPrintSupport
57# include <QtPrintSupport/qtprintsupportglobal.h>
58# if QT_CONFIG(printer) && QT_CONFIG(printdialog)
59# include <QtPrintSupport/qprinter.h>
60# include <QtPrintSupport/qprintdialog.h>
61# define HAS_PRINTER
62# endif
63#endif
64#include <QtGui/qpainter.h>
65#include <QtGui/qtransform.h>
66#include <QtGui/qcursor.h>
67
68#include <QtCore/qdir.h>
69#include <QtCore/qsize.h>
70#include <QtCore/qlibraryinfo.h>
71#include <QtCore/qbuffer.h>
72#include <QtCore/qpluginloader.h>
73#include <QtCore/qdebug.h>
74#include <QtCore/qtimer.h>
75#include <QtCore/qtextstream.h>
76#include <QtCore/qmetaobject.h>
77#include <QtCore/qfileinfo.h>
78#include <QtCore/qsavefile.h>
79#include <QtXml/qdom.h>
80
81#include <algorithm>
82#include <memory>
83#include <optional>
84
85QT_BEGIN_NAMESPACE
86
87using namespace Qt::StringLiterals;
88
89const char *QDesignerActions::defaultToolbarPropertyName = "__qt_defaultToolBarAction";
90
91//#ifdef Q_OS_MACOS
92# define NONMODAL_PREVIEW
93//#endif
94
95static QAction *createSeparator(QObject *parent)
96{
97 auto *rc = new QAction(parent);
98 rc->setSeparator(true);
99 return rc;
100}
101
102static QActionGroup *createActionGroup(QObject *parent, bool exclusive = false)
103{
104 auto *rc = new QActionGroup(parent);
105 rc->setExclusive(exclusive);
106 return rc;
107}
108
109static void fixActionContext(const QList<QAction *> &actions)
110{
111 for (QAction *a : actions)
112 a->setShortcutContext(Qt::ApplicationShortcut);
113}
114
115static inline QString savedMessage(const QString &fileName)
116{
117 return QDesignerActions::tr("Saved %1.").arg(fileName);
118}
119
120static QString fileDialogFilters(const QString &extension)
121{
122 return QDesignerActions::tr("Designer UI files (*.%1);;All Files (*)").arg(extension);
123}
124
125static QString fixResourceFileBackupPath(const QDesignerFormWindowInterface *fwi,
126 const QDir& backupDir);
127
128static QByteArray formWindowContents(const QDesignerFormWindowInterface *fw,
129 std::optional<QDir> alternativeDir = {})
130{
131 QString contents = alternativeDir.has_value()
132 ? fixResourceFileBackupPath(fw, alternativeDir.value()) : fw->contents();
133 if (const auto *fwb = qobject_cast<const qdesigner_internal::FormWindowBase *>(fw)) {
134 if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator)
135 contents.replace(u'\n', "\r\n"_L1);
136 }
137 return contents.toUtf8();
138}
139
140QFileDialog *createSaveAsDialog(QWidget *parent, const QString &dir, const QString &extension)
141{
142 auto *result = new QFileDialog(parent, QDesignerActions::tr("Save Form As"),
143 dir, fileDialogFilters(extension));
144 result->setAcceptMode(QFileDialog::AcceptSave);
145 result->setDefaultSuffix(extension);
146 return result;
147}
148
149QDesignerActions::QDesignerActions(const Options &options, QDesignerWorkbench *workbench)
150 : QObject(workbench),
151 m_workbench(workbench),
152 m_core(workbench->core()),
153 m_settings(workbench->core()),
154 m_helpClient(HelpClient::create(options.helpMode)),
155 m_backupTimer(new QTimer(this)),
156 m_fileActions(createActionGroup(this)),
157 m_recentFilesActions(createActionGroup(this)),
158 m_editActions(createActionGroup(this)),
159 m_formActions(createActionGroup(this)),
160 m_settingsActions(createActionGroup(this)),
161 m_windowActions(createActionGroup(this)),
162 m_toolActions(createActionGroup(this, true)),
163 m_editWidgetsAction(new QAction(tr("Edit Widgets"), this)),
164 m_newFormAction(new QAction(qdesigner_internal::createIconSet(QIcon::ThemeIcon::DocumentNew,
165 "filenew.png"_L1),
166 tr("&New..."), this)),
167 m_openFormAction(new QAction(qdesigner_internal::createIconSet(QIcon::ThemeIcon::DocumentOpen,
168 "fileopen.png"_L1),
169 tr("&Open..."), this)),
170 m_saveFormAction(new QAction(qdesigner_internal::createIconSet(QIcon::ThemeIcon::DocumentSave,
171 "filesave.png"_L1),
172 tr("&Save"), this)),
173 m_saveFormAsAction(new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSaveAs),
174 tr("Save &As..."), this)),
175 m_saveAllFormsAction(new QAction(tr("Save A&ll"), this)),
176 m_saveFormAsTemplateAction(new QAction(tr("Save As &Template..."), this)),
177 m_closeFormAction(new QAction(QIcon::fromTheme(QIcon::ThemeIcon::WindowClose),
178 tr("&Close"), this)),
179 m_savePreviewImageAction(new QAction(tr("Save &Image..."), this)),
180 m_printPreviewAction(new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentPrint),
181 tr("&Print..."), this)),
182 m_quitAction(new QAction(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit),
183 tr("&Quit"), this)),
184 m_viewCppCodeAction(new QAction(tr("View &C++ Code..."), this)),
185 m_viewPythonCodeAction(new QAction(tr("View &Python Code..."), this)),
186 m_minimizeAction(new QAction(tr("&Minimize"), this)),
187 m_bringAllToFrontSeparator(createSeparator(this)),
188 m_bringAllToFrontAction(new QAction(tr("Bring All to Front"), this)),
189 m_windowListSeparatorAction(createSeparator(this)),
190 m_preferencesAction(new QAction(tr("Preferences..."), this)),
191 m_appFontAction(new QAction(tr("Additional Fonts..."), this))
192{
193 Q_ASSERT(m_core != nullptr);
194 auto *ifwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager *>(m_core->formWindowManager());
195 Q_ASSERT(ifwm);
196 m_previewManager = ifwm->previewManager();
197 m_previewFormAction = ifwm->action(QDesignerFormWindowManagerInterface::DefaultPreviewAction);
198 m_styleActions = ifwm->actionGroup(QDesignerFormWindowManagerInterface::StyledPreviewActionGroup);
199 connect(ifwm, &QDesignerFormWindowManagerInterface::formWindowSettingsChanged,
200 this, &QDesignerActions::formWindowSettingsChanged);
201
202 m_editWidgetsAction->setObjectName(u"__qt_edit_widgets_action"_s);
203 m_newFormAction->setObjectName(u"__qt_new_form_action"_s);
204 m_openFormAction->setObjectName(u"__qt_open_form_action"_s);
205 m_saveFormAction->setObjectName(u"__qt_save_form_action"_s);
206 m_saveFormAsAction->setObjectName(u"__qt_save_form_as_action"_s);
207 m_saveAllFormsAction->setObjectName(u"__qt_save_all_forms_action"_s);
208 m_saveFormAsTemplateAction->setObjectName(u"__qt_save_form_as_template_action"_s);
209 m_closeFormAction->setObjectName(u"__qt_close_form_action"_s);
210 m_quitAction->setObjectName(u"__qt_quit_action"_s);
211 m_previewFormAction->setObjectName(u"__qt_preview_form_action"_s);
212 m_viewCppCodeAction->setObjectName(u"__qt_preview_cpp_code_action"_s);
213 m_viewPythonCodeAction->setObjectName(u"__qt_preview_python_code_action"_s);
214 m_minimizeAction->setObjectName(u"__qt_minimize_action"_s);
215 m_bringAllToFrontAction->setObjectName(u"__qt_bring_all_to_front_action"_s);
216 m_preferencesAction->setObjectName(u"__qt_preferences_action"_s);
217
218 m_helpActions = createHelpActions();
219
220 m_newFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
221 m_openFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
222 m_saveFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
223
224 QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager();
225 Q_ASSERT(formWindowManager != nullptr);
226
227//
228// file actions
229//
230 m_newFormAction->setShortcut(QKeySequence::New);
231 connect(m_newFormAction, &QAction::triggered, this, &QDesignerActions::createForm);
232 m_fileActions->addAction(m_newFormAction);
233
234 m_openFormAction->setShortcut(QKeySequence::Open);
235 connect(m_openFormAction, &QAction::triggered, this, &QDesignerActions::slotOpenForm);
236 m_fileActions->addAction(m_openFormAction);
237
238 m_fileActions->addAction(createRecentFilesMenu());
239 m_fileActions->addAction(createSeparator(this));
240
241 m_saveFormAction->setShortcut(QKeySequence::Save);
242 connect(m_saveFormAction, &QAction::triggered, this,
243 QOverload<>::of(&QDesignerActions::saveForm));
244 m_fileActions->addAction(m_saveFormAction);
245
246 connect(m_saveFormAsAction, &QAction::triggered, this,
247 QOverload<>::of(&QDesignerActions::saveFormAs));
248 m_fileActions->addAction(m_saveFormAsAction);
249
250#ifdef Q_OS_MACOS
251 m_saveAllFormsAction->setShortcut(tr("ALT+CTRL+S"));
252#else
253 m_saveAllFormsAction->setShortcut(tr("CTRL+SHIFT+S")); // Commonly "Save As" on Mac
254#endif
255 connect(m_saveAllFormsAction, &QAction::triggered, this, &QDesignerActions::saveAllForms);
256 m_fileActions->addAction(m_saveAllFormsAction);
257
258 connect(m_saveFormAsTemplateAction, &QAction::triggered, this, &QDesignerActions::saveFormAsTemplate);
259 m_fileActions->addAction(m_saveFormAsTemplateAction);
260
261 m_fileActions->addAction(createSeparator(this));
262
263 m_printPreviewAction->setShortcut(QKeySequence::Print);
264 connect(m_printPreviewAction, &QAction::triggered, this, &QDesignerActions::printPreviewImage);
265 m_fileActions->addAction(m_printPreviewAction);
266 m_printPreviewAction->setObjectName(u"__qt_print_action"_s);
267
268 connect(m_savePreviewImageAction, &QAction::triggered, this, &QDesignerActions::savePreviewImage);
269 m_savePreviewImageAction->setObjectName(u"__qt_saveimage_action"_s);
270 m_fileActions->addAction(m_savePreviewImageAction);
271 m_fileActions->addAction(createSeparator(this));
272
273 m_closeFormAction->setShortcut(QKeySequence::Close);
274 connect(m_closeFormAction, &QAction::triggered, this, &QDesignerActions::closeForm);
275 m_fileActions->addAction(m_closeFormAction);
276 updateCloseAction();
277
278 m_fileActions->addAction(createSeparator(this));
279
280 m_quitAction->setShortcuts(QKeySequence::Quit);
281 m_quitAction->setMenuRole(QAction::QuitRole);
282 connect(m_quitAction, &QAction::triggered, this, &QDesignerActions::shutdown);
283 m_fileActions->addAction(m_quitAction);
284
285//
286// edit actions
287//
288 QAction *undoAction = formWindowManager->action(QDesignerFormWindowManagerInterface::UndoAction);
289 undoAction->setObjectName(u"__qt_undo_action"_s);
290 undoAction->setShortcut(QKeySequence::Undo);
291 m_editActions->addAction(undoAction);
292
293 QAction *redoAction = formWindowManager->action(QDesignerFormWindowManagerInterface::RedoAction);
294 redoAction->setObjectName(u"__qt_redo_action"_s);
295 redoAction->setShortcut(QKeySequence::Redo);
296 m_editActions->addAction(redoAction);
297
298 m_editActions->addAction(createSeparator(this));
299
300#if QT_CONFIG(clipboard)
301 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::CutAction));
302 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::CopyAction));
303 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::PasteAction));
304#endif
305 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::DeleteAction));
306
307 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::SelectAllAction));
308
309 m_editActions->addAction(createSeparator(this));
310
311 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::LowerAction));
312 m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::RaiseAction));
313
314 formWindowManager->action(QDesignerFormWindowManagerInterface::LowerAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
315 formWindowManager->action(QDesignerFormWindowManagerInterface::RaiseAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
316
317//
318// edit mode actions
319//
320
321 m_editWidgetsAction->setCheckable(true);
322 QList<QKeySequence> shortcuts;
323 shortcuts.append(QKeySequence(Qt::Key_F3));
324 shortcuts.append(QKeySequence(Qt::Key_Escape));
325 m_editWidgetsAction->setShortcuts(shortcuts);
326 m_editWidgetsAction->setIcon(qdesigner_internal::createIconSet("widgettool.png"_L1));
327 connect(m_editWidgetsAction, &QAction::triggered, this, &QDesignerActions::editWidgetsSlot);
328 m_editWidgetsAction->setChecked(true);
329 m_editWidgetsAction->setEnabled(false);
330 m_editWidgetsAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
331 m_toolActions->addAction(m_editWidgetsAction);
332
333 connect(formWindowManager, &qdesigner_internal::QDesignerFormWindowManager::activeFormWindowChanged,
334 this, &QDesignerActions::activeFormWindowChanged);
335
336 const QObjectList builtinPlugins = QPluginLoader::staticInstances()
337 + m_core->pluginManager()->instances();
338 for (QObject *plugin : builtinPlugins) {
339 if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
340 if (QAction *action = formEditorPlugin->action()) {
341 m_toolActions->addAction(action);
342 action->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
343 action->setCheckable(true);
344 }
345 }
346 }
347
348 connect(m_preferencesAction, &QAction::triggered, this, &QDesignerActions::showPreferencesDialog);
349 m_preferencesAction->setMenuRole(QAction::PreferencesRole);
350 m_settingsActions->addAction(m_preferencesAction);
351
352 connect(m_appFontAction, &QAction::triggered, this, &QDesignerActions::showAppFontDialog);
353 m_settingsActions->addAction(m_appFontAction);
354//
355// form actions
356//
357
358 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::HorizontalLayoutAction));
359 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::VerticalLayoutAction));
360 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::SplitHorizontalAction));
361 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::SplitVerticalAction));
362 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::GridLayoutAction));
363 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::FormLayoutAction));
364 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::BreakLayoutAction));
365 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::AdjustSizeAction));
366 m_formActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::SimplifyLayoutAction));
367 m_formActions->addAction(createSeparator(this));
368
369 formWindowManager->action(QDesignerFormWindowManagerInterface::HorizontalLayoutAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
370 formWindowManager->action(QDesignerFormWindowManagerInterface::VerticalLayoutAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
371 formWindowManager->action(QDesignerFormWindowManagerInterface::SplitHorizontalAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
372 formWindowManager->action(QDesignerFormWindowManagerInterface::SplitVerticalAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
373 formWindowManager->action(QDesignerFormWindowManagerInterface::GridLayoutAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
374 formWindowManager->action(QDesignerFormWindowManagerInterface::FormLayoutAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
375 formWindowManager->action(QDesignerFormWindowManagerInterface::BreakLayoutAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
376 formWindowManager->action(QDesignerFormWindowManagerInterface::AdjustSizeAction)->setProperty(QDesignerActions::defaultToolbarPropertyName, true);
377
378 m_previewFormAction->setShortcut(tr("CTRL+R"));
379 m_formActions->addAction(m_previewFormAction);
380 connect(m_previewManager, &qdesigner_internal::PreviewManager::firstPreviewOpened,
381 this, &QDesignerActions::updateCloseAction);
382 connect(m_previewManager, &qdesigner_internal::PreviewManager::lastPreviewClosed,
383 this, &QDesignerActions::updateCloseAction);
384
385 connect(m_viewCppCodeAction, &QAction::triggered, this,
386 [this] () { this->viewCode(qdesigner_internal::UicLanguage::Cpp); });
387 connect(m_viewPythonCodeAction, &QAction::triggered, this,
388 [this] () { this->viewCode(qdesigner_internal::UicLanguage::Python); });
389
390 // Preview code only in Cpp/Python (uic)
391 if (qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core) == nullptr) {
392 m_formActions->addAction(m_viewCppCodeAction);
393 m_formActions->addAction(m_viewPythonCodeAction);
394 }
395
396 m_formActions->addAction(createSeparator(this));
397
398 m_formActions->addAction(ifwm->action(QDesignerFormWindowManagerInterface::FormWindowSettingsDialogAction));
399//
400// window actions
401//
402 m_minimizeAction->setEnabled(false);
403 m_minimizeAction->setCheckable(true);
404 m_minimizeAction->setShortcut(tr("CTRL+M"));
405 connect(m_minimizeAction, &QAction::triggered, m_workbench, &QDesignerWorkbench::toggleFormMinimizationState);
406 m_windowActions->addAction(m_minimizeAction);
407
408 m_windowActions->addAction(m_bringAllToFrontSeparator);
409 connect(m_bringAllToFrontAction, &QAction::triggered, m_workbench, &QDesignerWorkbench::bringAllToFront);
410 m_windowActions->addAction(m_bringAllToFrontAction);
411 m_windowActions->addAction(m_windowListSeparatorAction);
412
414
415//
416// connections
417//
418 fixActionContext(m_fileActions->actions());
419 fixActionContext(m_editActions->actions());
420 fixActionContext(m_toolActions->actions());
421 fixActionContext(m_formActions->actions());
422 fixActionContext(m_windowActions->actions());
423 fixActionContext(m_helpActions->actions());
424
425 activeFormWindowChanged(core()->formWindowManager()->activeFormWindow());
426
427 m_backupTimer->start(180000); // 3min
428 connect(m_backupTimer, &QTimer::timeout, this, &QDesignerActions::backupForms);
429
430 // Enable application font action
431 connect(formWindowManager, &QDesignerFormWindowManagerInterface::formWindowAdded,
432 this, &QDesignerActions::formWindowCountChanged);
433 connect(formWindowManager, &QDesignerFormWindowManagerInterface::formWindowRemoved,
434 this, &QDesignerActions::formWindowCountChanged);
435 formWindowCountChanged();
436}
437
438QActionGroup *QDesignerActions::createHelpActions()
439{
440 QActionGroup *helpActions = createActionGroup(this);
441
442#ifndef QT_JAMBI_BUILD
443 auto *mainHelpAction = new QAction(tr("Qt Widgets Designer &Help"), this);
444 mainHelpAction->setObjectName(u"__qt_designer_help_action"_s);
445 connect(mainHelpAction, &QAction::triggered, this, &QDesignerActions::showDesignerHelp);
446 mainHelpAction->setShortcut(Qt::CTRL | Qt::Key_Question);
447 helpActions->addAction(mainHelpAction);
448
449 helpActions->addAction(createSeparator(this));
450 auto *widgetHelp = new QAction(tr("Current Widget Help"), this);
451 widgetHelp->setObjectName(u"__qt_current_widget_help_action"_s);
452 widgetHelp->setShortcut(Qt::Key_F1);
453 connect(widgetHelp, &QAction::triggered, this, &QDesignerActions::showWidgetSpecificHelp);
454 helpActions->addAction(widgetHelp);
455
456#endif
457
458 helpActions->addAction(createSeparator(this));
459 auto *aboutPluginsAction = new QAction(tr("About Plugins"), this);
460 aboutPluginsAction->setObjectName(u"__qt_about_plugins_action"_s);
461 aboutPluginsAction->setMenuRole(QAction::ApplicationSpecificRole);
462 connect(aboutPluginsAction, &QAction::triggered,
463 m_core->formWindowManager(), &QDesignerFormWindowManagerInterface::showPluginDialog);
464 helpActions->addAction(aboutPluginsAction);
465
466 auto *aboutDesignerAction = new QAction(tr("About Qt Widgets Designer"), this);
467 aboutDesignerAction->setMenuRole(QAction::AboutRole);
468 aboutDesignerAction->setObjectName(u"__qt_about_designer_action"_s);
469 connect(aboutDesignerAction, &QAction::triggered, this, &QDesignerActions::aboutDesigner);
470 helpActions->addAction(aboutDesignerAction);
471
472 auto *aboutQtAction = new QAction(tr("About Qt"), this);
473 aboutQtAction->setMenuRole(QAction::AboutQtRole);
474 aboutQtAction->setObjectName(u"__qt_about_qt_action"_s);
475 connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt);
476 helpActions->addAction(aboutQtAction);
477 return helpActions;
478}
479
481{
482#ifdef HAS_PRINTER
483 delete m_printer;
484#endif
485}
486
488{
489 QDesignerLanguageExtension *lang
490 = qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core);
491 if (lang)
492 return lang->uiExtension();
493 return u"ui"_s;
494}
495
496QAction *QDesignerActions::createRecentFilesMenu()
497{
498 m_recentMenu = std::make_unique<QMenu>();
499
500 // Need to insert this into the QAction.
501 for (int i = 0; i < MaxRecentFiles; ++i) {
502 auto *recentAct = new QAction(this);
503 recentAct->setVisible(false);
504 connect(recentAct, &QAction::triggered, this, &QDesignerActions::openRecentForm);
505 m_recentFilesActions->addAction(recentAct);
506 m_recentMenu->addAction(recentAct);
507 }
508 updateRecentFileActions();
509 m_recentMenu->addSeparator();
510 auto *act = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::EditClear),
511 tr("Clear &Menu"), this);
512 act->setObjectName(u"__qt_action_clear_menu_"_s);
513 connect(act, &QAction::triggered, this, &QDesignerActions::clearRecentFiles);
514 m_recentFilesActions->addAction(act);
515 m_recentMenu->addAction(act);
516
517 act = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpenRecent),
518 tr("&Recent Forms"), this);
519 act->setMenu(m_recentMenu.get());
520 return act;
521}
522
523QActionGroup *QDesignerActions::toolActions() const
524{ return m_toolActions; }
525
527{ return m_workbench; }
528
529QDesignerFormEditorInterface *QDesignerActions::core() const
530{ return m_core; }
531
532QActionGroup *QDesignerActions::fileActions() const
533{ return m_fileActions; }
534
535QActionGroup *QDesignerActions::editActions() const
536{ return m_editActions; }
537
538QActionGroup *QDesignerActions::formActions() const
539{ return m_formActions; }
540
541QActionGroup *QDesignerActions::settingsActions() const
542{ return m_settingsActions; }
543
544QActionGroup *QDesignerActions::windowActions() const
545{ return m_windowActions; }
546
547QActionGroup *QDesignerActions::helpActions() const
548{ return m_helpActions; }
549
550QActionGroup *QDesignerActions::styleActions() const
551{ return m_styleActions; }
552
554{ return m_previewFormAction; }
555
557{ return m_viewCppCodeAction; }
558
559
560void QDesignerActions::editWidgetsSlot()
561{
562 QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
563 for (int i=0; i<formWindowManager->formWindowCount(); ++i) {
564 QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i);
565 formWindow->editWidgets();
566 }
567}
568
570{
571 showNewFormDialog(QString());
572}
573
574void QDesignerActions::showNewFormDialog(const QString &fileName)
575{
576 closePreview();
577 auto *dlg = new NewForm(workbench(), workbench()->core()->topLevel(), fileName);
578
579 dlg->setAttribute(Qt::WA_DeleteOnClose);
580 dlg->setAttribute(Qt::WA_ShowModal);
581
582 dlg->setGeometry(fixDialogRect(dlg->rect()));
583 dlg->exec();
584}
585
587{
588 openForm(core()->topLevel());
589}
590
592{
593 closePreview();
594 const QString extension = uiExtension();
595 const QStringList fileNames = QFileDialog::getOpenFileNames(parent, tr("Open Form"),
596 m_openDirectory, fileDialogFilters(extension), nullptr);
597
598 if (fileNames.isEmpty())
599 return false;
600
601 bool atLeastOne = false;
602 for (const QString &fileName : fileNames) {
603 if (readInForm(fileName) && !atLeastOne)
604 atLeastOne = true;
605 }
606
607 return atLeastOne;
608}
609
610bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw)
611{
612 const QString extension = uiExtension();
613
614 QString dir = fw->fileName();
615 if (dir.isEmpty()) {
616 do {
617 // Build untitled name
618 if (!m_saveDirectory.isEmpty()) {
619 dir = m_saveDirectory;
620 break;
621 }
622 if (!m_openDirectory.isEmpty()) {
623 dir = m_openDirectory;
624 break;
625 }
626 dir = QDir::current().absolutePath();
627 } while (false);
628 dir += QDir::separator();
629 dir += "untitled."_L1;
630 dir += extension;
631 }
632
633 std::unique_ptr<QFileDialog> saveAsDialog(createSaveAsDialog(fw, dir, extension));
634 if (saveAsDialog->exec() != QDialog::Accepted)
635 return false;
636
637 const QString saveFile = saveAsDialog->selectedFiles().constFirst();
638 saveAsDialog.reset(); // writeOutForm potentially shows other dialogs
639
640 fw->setFileName(saveFile);
641 return writeOutForm(fw, saveFile);
642}
643
644void QDesignerActions::saveForm()
645{
646 if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
647 if (saveForm(fw))
648 showStatusBarMessage(savedMessage(QFileInfo(fw->fileName()).fileName()));
649 }
650}
651
652void QDesignerActions::saveAllForms()
653{
654 QString fileNames;
655 QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
656 if (const int totalWindows = formWindowManager->formWindowCount()) {
657 const auto separator = ", "_L1;
658 for (int i = 0; i < totalWindows; ++i) {
659 QDesignerFormWindowInterface *fw = formWindowManager->formWindow(i);
660 if (fw && fw->isDirty()) {
661 formWindowManager->setActiveFormWindow(fw);
662 if (saveForm(fw)) {
663 if (!fileNames.isEmpty())
664 fileNames += separator;
665 fileNames += QFileInfo(fw->fileName()).fileName();
666 } else {
667 break;
668 }
669 }
670 }
671 }
672
673 if (!fileNames.isEmpty()) {
674 showStatusBarMessage(savedMessage(fileNames));
675 }
676}
677
678bool QDesignerActions::saveForm(QDesignerFormWindowInterface *fw)
679{
680 return fw->fileName().isEmpty() ? saveFormAs(fw) : writeOutForm(fw, fw->fileName());
681}
682
683void QDesignerActions::closeForm()
684{
685 if (m_previewManager->previewCount()) {
686 closePreview();
687 return;
688 }
689
690 if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow())
691 if (QWidget *parent = fw->parentWidget()) {
692 if (auto *mdiSubWindow = qobject_cast<QMdiSubWindow *>(parent->parentWidget())) {
693 mdiSubWindow->close();
694 } else {
695 parent->close();
696 }
697 }
698}
699
700void QDesignerActions::saveFormAs()
701{
702 if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
703 if (saveFormAs(fw))
704 showStatusBarMessage(savedMessage(fw->fileName()));
705 }
706}
707
708void QDesignerActions::saveFormAsTemplate()
709{
710 if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
711 SaveFormAsTemplate dlg(core(), fw, fw->window());
712 dlg.exec();
713 }
714}
715
717{
718 QMap<QString, QString> result = QDesignerSettings(m_core).backup();
719 for (auto it = result.begin(); it != result.end();) {
720 it.value() = QDir::cleanPath(it.value());
721 if (it.value().startsWith(m_backupPath) && QFile::exists(it.value()))
722 ++it;
723 else
724 it = result.erase(it);
725 }
726 return result;
727}
728
729void QDesignerActions::notImplementedYet()
730{
731 QMessageBox::information(core()->topLevel(), tr("Designer"), tr("Feature not implemented yet!"));
732}
733
734void QDesignerActions::closePreview()
735{
736 m_previewManager->closeAllPreviews();
737}
738
739void QDesignerActions::viewCode(qdesigner_internal::UicLanguage language)
740{
741 QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
742 if (!fw)
743 return;
744 QString errorMessage;
745 if (!qdesigner_internal::CodeDialog::showCodeDialog(fw, language, fw, &errorMessage))
746 QMessageBox::warning(fw, tr("Code generation failed"), errorMessage);
747}
748
749bool QDesignerActions::readInForm(const QString &fileName)
750{
751 QString fn = fileName;
752
753 // First make sure that we don't have this one open already.
754 QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
755 const int totalWindows = formWindowManager->formWindowCount();
756 for (int i = 0; i < totalWindows; ++i) {
757 QDesignerFormWindowInterface *w = formWindowManager->formWindow(i);
758 if (w->fileName() == fn) {
759 w->raise();
760 formWindowManager->setActiveFormWindow(w);
761 addRecentFile(fn);
762 return true;
763 }
764 }
765
766 // Otherwise load it.
767 do {
768 QString errorMessage;
769 if (workbench()->openForm(fn, &errorMessage)) {
770 addRecentFile(fn);
771 m_openDirectory = QFileInfo(fn).absolutePath();
772 return true;
773 }
774
775 // prompt to reload
776 QMessageBox box(QMessageBox::Warning, tr("Read error"),
777 tr("%1\nDo you want to update the file location or generate a new form?").arg(errorMessage),
778 QMessageBox::Cancel, core()->topLevel());
779
780 QPushButton *updateButton = box.addButton(tr("&Update"), QMessageBox::ActionRole);
781 QPushButton *newButton = box.addButton(tr("&New Form"), QMessageBox::ActionRole);
782 box.exec();
783 if (box.clickedButton() == box.button(QMessageBox::Cancel))
784 return false;
785
786 if (box.clickedButton() == updateButton) {
787 fn = QFileDialog::getOpenFileName(core()->topLevel(),
788 tr("Open Form"), m_openDirectory,
789 fileDialogFilters(uiExtension()), nullptr);
790
791 if (fn.isEmpty())
792 return false;
793 } else if (box.clickedButton() == newButton) {
794 // If the file does not exist, but its directory, is valid, open the template with the editor file name set to it.
795 // (called from command line).
796 QString newFormFileName;
797 const QFileInfo fInfo(fn);
798 if (!fInfo.exists()) {
799 // Normalize file name
800 const QString directory = fInfo.absolutePath();
801 if (QDir(directory).exists())
802 newFormFileName = directory + u'/' + fInfo.fileName();
803 }
804 showNewFormDialog(newFormFileName);
805 return false;
806 }
807 } while (true);
808 return true;
809}
810
811bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile, bool check)
812{
813 Q_ASSERT(fw && !saveFile.isEmpty());
814
815 if (check) {
816 const QStringList problems = fw->checkContents();
817 if (!problems.isEmpty())
818 QMessageBox::information(fw->window(), tr("Qt Widgets Designer"), problems.join("<br>"_L1));
819 }
820
821 m_workbench->updateBackup(fw);
822
823 QSaveFile f(saveFile);
824 while (!f.open(QFile::WriteOnly)) {
825 QMessageBox box(QMessageBox::Warning,
826 tr("Save Form?"),
827 tr("Could not open file"),
828 QMessageBox::NoButton, fw);
829
830 box.setWindowModality(Qt::WindowModal);
831 box.setInformativeText(tr("The file %1 could not be opened."
832 "\nReason: %2"
833 "\nWould you like to retry or select a different file?")
834 .arg(f.fileName(), f.errorString()));
835 QPushButton *retryButton = box.addButton(QMessageBox::Retry);
836 retryButton->setDefault(true);
837 QPushButton *switchButton = box.addButton(tr("Select New File"), QMessageBox::AcceptRole);
838 QPushButton *cancelButton = box.addButton(QMessageBox::Cancel);
839 box.exec();
840
841 if (box.clickedButton() == cancelButton)
842 return false;
843 if (box.clickedButton() == switchButton) {
844 std::unique_ptr<QFileDialog> saveAsDialog(
845 createSaveAsDialog(fw, QDir::currentPath(), uiExtension()));
846 if (saveAsDialog->exec() != QDialog::Accepted)
847 return false;
848
849 const QString fileName = saveAsDialog->selectedFiles().constFirst();
850 f.setFileName(fileName);
851 fw->setFileName(fileName);
852 }
853 // loop back around...
854 }
855 f.write(formWindowContents(fw));
856 if (!f.commit()) {
857 QMessageBox box(QMessageBox::Warning, tr("Save Form"),
858 tr("Could not write file"),
859 QMessageBox::Cancel, fw);
860 box.setWindowModality(Qt::WindowModal);
861 box.setInformativeText(tr("It was not possible to write the file %1 to disk."
862 "\nReason: %2")
863 .arg(f.fileName(), f.errorString()));
864 box.exec();
865 return false;
866 }
867 addRecentFile(saveFile);
868 m_saveDirectory = QFileInfo(f.fileName()).absolutePath();
869
870 fw->setDirty(false);
871 fw->parentWidget()->setWindowModified(false);
872 return true;
873}
874
875void QDesignerActions::shutdown()
876{
877 // Follow the idea from the Mac, i.e. send the Application a close event
878 // and if it's accepted, quit.
879 QCloseEvent ev;
880 QApplication::sendEvent(qDesigner, &ev);
881 if (ev.isAccepted())
882 qDesigner->quit();
883}
884
885void QDesignerActions::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow)
886{
887 const bool enable = formWindow != nullptr;
888 m_saveFormAction->setEnabled(enable);
889 m_saveFormAsAction->setEnabled(enable);
890 m_saveAllFormsAction->setEnabled(enable);
891 m_saveFormAsTemplateAction->setEnabled(enable);
892 m_closeFormAction->setEnabled(enable);
893 m_savePreviewImageAction->setEnabled(enable);
894 m_printPreviewAction->setEnabled(enable);
895
896 m_editWidgetsAction->setEnabled(enable);
897
898 m_previewFormAction->setEnabled(enable);
899 m_viewCppCodeAction->setEnabled(enable);
900 m_viewPythonCodeAction->setEnabled(enable);
901 m_styleActions->setEnabled(enable);
902}
903
904void QDesignerActions::formWindowSettingsChanged(QDesignerFormWindowInterface *fw)
905{
906 if (QDesignerFormWindow *window = m_workbench->findFormWindow(fw))
907 window->updateChanged();
908}
909
910void QDesignerActions::updateRecentFileActions()
911{
912 QStringList files = m_settings.recentFilesList();
913 auto existingEnd = std::remove_if(files.begin(), files.end(),
914 [] (const QString &f) { return !QFileInfo::exists(f); });
915 if (existingEnd != files.end()) {
916 files.erase(existingEnd, files.end());
917 m_settings.setRecentFilesList(files);
918 }
919
920 const auto recentFilesActs = m_recentFilesActions->actions();
921 qsizetype i = 0;
922 for (QAction *action : recentFilesActs) {
923 if (i < files.size()) {
924 const QString &file = files.at(i);
925 action->setText(QFileInfo(file).fileName());
926 action->setIconText(file);
927 action->setVisible(true);
928 } else {
929 action->setVisible(false);
930 }
931 ++i;
932 }
933}
934
935void QDesignerActions::openRecentForm()
936{
937 if (const auto *action = qobject_cast<const QAction *>(sender())) {
938 if (!readInForm(action->iconText()))
939 updateRecentFileActions(); // File doesn't exist, remove it from settings
940 }
941}
942
943void QDesignerActions::clearRecentFiles()
944{
945 m_settings.setRecentFilesList(QStringList());
946 updateRecentFileActions();
947}
948
950{
951 return m_recentFilesActions;
952}
953
954void QDesignerActions::addRecentFile(const QString &fileName)
955{
956 QStringList files = m_settings.recentFilesList();
957 files.removeAll(fileName);
958 files.prepend(fileName);
959 while (files.size() > MaxRecentFiles)
960 files.removeLast();
961
962 m_settings.setRecentFilesList(files);
963 updateRecentFileActions();
964}
965
967{
968 return m_openFormAction;
969}
970
972{
973 return m_closeFormAction;
974}
975
977{
978 return m_minimizeAction;
979}
980
981void QDesignerActions::showDesignerHelp()
982{
983 showHelp(m_helpClient->designerManualUrl() + "qtdesigner-manual.html"_L1);
984}
985
986void QDesignerActions::helpRequested(const QString &manual, const QString &document)
987{
988 showHelp(m_helpClient->documentUrl(manual) + document);
989}
990
991void QDesignerActions::showHelp(const QString &url)
992{
993 QString errorMessage;
994 if (!m_helpClient->showPage(url, &errorMessage))
995 QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage);
996}
997
998void QDesignerActions::aboutDesigner()
999{
1000 VersionDialog mb(core()->topLevel());
1001 mb.setWindowTitle(tr("About Qt Widgets Designer"));
1002 if (mb.exec()) {
1003 QMessageBox messageBox(QMessageBox::Information, u"Easter Egg"_s,
1004 u"Easter Egg"_s, QMessageBox::Ok, core()->topLevel());
1005 messageBox.setInformativeText(u"The Easter Egg has been removed."_s);
1006 messageBox.exec();
1007 }
1008}
1009
1011{
1012 return m_editWidgetsAction;
1013}
1014
1015void QDesignerActions::showWidgetSpecificHelp()
1016{
1017 const QString helpId = core()->integration()->contextHelpId();
1018
1019 if (helpId.isEmpty()) {
1020 showDesignerHelp();
1021 return;
1022 }
1023
1024 QString errorMessage;
1025 const bool rc = m_helpClient->activateIdentifier(helpId, &errorMessage);
1026 if (!rc)
1027 QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage);
1028}
1029
1030void QDesignerActions::updateCloseAction()
1031{
1032 if (m_previewManager->previewCount()) {
1033 m_closeFormAction->setText(tr("&Close Preview"));
1034 } else {
1035 m_closeFormAction->setText(tr("&Close"));
1036 }
1037}
1038
1039void QDesignerActions::backupForms()
1040{
1041 const int count = m_workbench->formWindowCount();
1042 if (!count || !ensureBackupDirectories())
1043 return;
1044
1045
1046 QMap<QString, QString> backupMap;
1047 QDir backupDir(m_backupPath);
1048 for (int i = 0; i < count; ++i) {
1049 QDesignerFormWindow *fw = m_workbench->formWindow(i);
1050 QDesignerFormWindowInterface *fwi = fw->editor();
1051
1052 QString formBackupName = m_backupPath + "/backup"_L1 + QString::number(i) + ".bak"_L1;
1053
1054 QString fwn = QDir::toNativeSeparators(fwi->fileName());
1055 if (fwn.isEmpty())
1056 fwn = fw->windowTitle();
1057
1058 backupMap.insert(fwn, formBackupName);
1059
1060 bool ok = false;
1061 QSaveFile file(formBackupName);
1062 if (file.open(QFile::WriteOnly)) {
1063 file.write(formWindowContents(fw->editor(), backupDir));
1064 ok = file.commit();
1065 }
1066 if (!ok) {
1067 backupMap.remove(fwn);
1068 qdesigner_internal::designerWarning(tr("The backup file %1 could not be written: %2").
1069 arg(QDir::toNativeSeparators(file.fileName()),
1070 file.errorString()));
1071 }
1072 }
1073
1074 if (!backupMap.isEmpty())
1075 m_settings.setBackup(backupMap);
1076}
1077
1078static QString fixResourceFileBackupPath(const QDesignerFormWindowInterface *fwi,
1079 const QDir& backupDir)
1080{
1081 const QString content = fwi->contents();
1082 QDomDocument domDoc(u"backup"_s);
1083 if(!domDoc.setContent(content))
1084 return content;
1085
1086 const QDomNodeList list = domDoc.elementsByTagName(u"resources"_s);
1087 if (list.isEmpty())
1088 return content;
1089
1090 for (int i = 0; i < list.count(); i++) {
1091 const QDomNode node = list.at(i);
1092 if (!node.isNull()) {
1093 const QDomElement element = node.toElement();
1094 if (!element.isNull() && element.tagName() == "resources"_L1) {
1095 QDomNode childNode = element.firstChild();
1096 while (!childNode.isNull()) {
1097 QDomElement childElement = childNode.toElement();
1098 if (!childElement.isNull() && childElement.tagName() == "include"_L1) {
1099 const QString attr = childElement.attribute(u"location"_s);
1100 const QString path = fwi->absoluteDir().absoluteFilePath(attr);
1101 childElement.setAttribute(u"location"_s, backupDir.relativeFilePath(path));
1102 }
1103 childNode = childNode.nextSibling();
1104 }
1105 }
1106 }
1107 }
1108
1109
1110 return domDoc.toString();
1111}
1112
1113QRect QDesignerActions::fixDialogRect(const QRect &rect) const
1114{
1115 QRect frameGeometry;
1116 const QRect availableGeometry = core()->topLevel()->screen()->geometry();
1117
1118 if (workbench()->mode() == DockedMode) {
1119 frameGeometry = core()->topLevel()->frameGeometry();
1120 } else
1121 frameGeometry = availableGeometry;
1122
1123 QRect dlgRect = rect;
1124 dlgRect.moveCenter(frameGeometry.center());
1125
1126 // make sure that parts of the dialog are not outside of screen
1127 dlgRect.moveBottom(qMin(dlgRect.bottom(), availableGeometry.bottom()));
1128 dlgRect.moveRight(qMin(dlgRect.right(), availableGeometry.right()));
1129 dlgRect.moveLeft(qMax(dlgRect.left(), availableGeometry.left()));
1130 dlgRect.moveTop(qMax(dlgRect.top(), availableGeometry.top()));
1131
1132 return dlgRect;
1133}
1134
1135void QDesignerActions::showStatusBarMessage(const QString &message) const
1136{
1137 if (workbench()->mode() == DockedMode) {
1138 QStatusBar *bar = qDesigner->mainWindow()->statusBar();
1139 if (bar && !bar->isHidden())
1140 bar->showMessage(message, 3000);
1141 }
1142}
1143
1145{
1146 m_bringAllToFrontSeparator->setVisible(visible);
1147 m_bringAllToFrontAction->setVisible(visible);
1148}
1149
1151{
1152 m_windowListSeparatorAction->setVisible(visible);
1153}
1154
1155bool QDesignerActions::ensureBackupDirectories() {
1156
1157 if (m_backupPath.isEmpty()) // create names
1158 m_backupPath = qdesigner_internal::dataDirectory() + u"/backup"_s;
1159
1160 // ensure directories
1161 const QDir backupDir(m_backupPath);
1162
1163 if (!backupDir.exists()) {
1164 if (!backupDir.mkpath(m_backupPath)) {
1165 qdesigner_internal::designerWarning(tr("The backup directory %1 could not be created.")
1166 .arg(QDir::toNativeSeparators(m_backupPath)));
1167 return false;
1168 }
1169 }
1170 return true;
1171}
1172
1173void QDesignerActions::showPreferencesDialog()
1174{
1175 {
1176 PreferencesDialog preferencesDialog(workbench()->core(), m_core->topLevel());
1177 preferencesDialog.exec();
1178 } // Make sure the preference dialog is destroyed before switching UI modes.
1179 m_workbench->applyUiSettings();
1180}
1181
1182void QDesignerActions::showAppFontDialog()
1183{
1184 if (!m_appFontDialog) // Might get deleted when switching ui modes
1185 m_appFontDialog = new AppFontDialog(core()->topLevel());
1186 m_appFontDialog->show();
1187 m_appFontDialog->raise();
1188}
1189
1190QPixmap QDesignerActions::createPreviewPixmap(QDesignerFormWindowInterface *fw)
1191{
1192 const QCursor oldCursor = core()->topLevel()->cursor();
1193 core()->topLevel()->setCursor(Qt::WaitCursor);
1194
1195 QString errorMessage;
1196 const QPixmap pixmap = m_previewManager->createPreviewPixmap(fw, QString(), &errorMessage);
1197 core()->topLevel()->setCursor(oldCursor);
1198 if (pixmap.isNull()) {
1199 QMessageBox::warning(fw, tr("Preview failed"), errorMessage);
1200 }
1201 return pixmap;
1202}
1203
1204qdesigner_internal::PreviewConfiguration QDesignerActions::previewConfiguration()
1205{
1206 qdesigner_internal::PreviewConfiguration pc;
1208 if (settings.isCustomPreviewConfigurationEnabled())
1209 pc = settings.customPreviewConfiguration();
1210 return pc;
1211}
1212
1213void QDesignerActions::savePreviewImage()
1214{
1215 const char *format = "png";
1216
1217 QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
1218 if (!fw)
1219 return;
1220
1221 QImage image;
1222 const QString extension = QString::fromLatin1(format);
1223 const QString filter = tr("Image files (*.%1)").arg(extension);
1224
1225 QString suggestion = fw->fileName();
1226 if (!suggestion.isEmpty())
1227 suggestion = QFileInfo(suggestion).baseName() + u'.' + extension;
1228
1229 QFileDialog dialog(fw, tr("Save Image"), suggestion, filter);
1230 dialog.setAcceptMode(QFileDialog::AcceptSave);
1231 dialog.setDefaultSuffix(extension);
1232
1233 do {
1234 if (dialog.exec() != QDialog::Accepted)
1235 break;
1236 const QString fileName = dialog.selectedFiles().constFirst();
1237
1238 if (image.isNull()) {
1239 const QPixmap pixmap = createPreviewPixmap(fw);
1240 if (pixmap.isNull())
1241 break;
1242
1243 image = pixmap.toImage();
1244 }
1245
1246 if (image.save(fileName, format)) {
1247 showStatusBarMessage(tr("Saved image %1.").arg(QFileInfo(fileName).fileName()));
1248 break;
1249 }
1250
1251 QMessageBox box(QMessageBox::Warning, tr("Save Image"),
1252 tr("The file %1 could not be written.").arg( fileName),
1253 QMessageBox::Retry|QMessageBox::Cancel, fw);
1254 if (box.exec() == QMessageBox::Cancel)
1255 break;
1256 } while (true);
1257}
1258
1259void QDesignerActions::formWindowCountChanged()
1260{
1261 const bool enabled = m_core->formWindowManager()->formWindowCount() == 0;
1262 /* Disable the application font action if there are form windows open
1263 * as the reordering of the fonts sets font properties to 'changed'
1264 * and overloaded fonts are not updated. */
1265 static const QString disabledTip = tr("Please close all forms to enable the loading of additional fonts.");
1266 m_appFontAction->setEnabled(enabled);
1267 m_appFontAction->setStatusTip(enabled ? QString() : disabledTip);
1268}
1269
1270void QDesignerActions::printPreviewImage()
1271{
1272#ifdef HAS_PRINTER
1273 QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
1274 if (!fw)
1275 return;
1276
1277 if (!m_printer)
1278 m_printer = new QPrinter(QPrinter::HighResolution);
1279
1280 m_printer->setFullPage(false);
1281
1282 // Grab the image to be able to a suggest suitable orientation
1283 const QPixmap pixmap = createPreviewPixmap(fw);
1284 if (pixmap.isNull())
1285 return;
1286
1287 const QSizeF pixmapSize = pixmap.size();
1288
1289 m_printer->setPageOrientation(pixmapSize.width() > pixmapSize.height() ?
1290 QPageLayout::Landscape : QPageLayout::Portrait);
1291
1292 // Printer parameters
1293 QPrintDialog dialog(m_printer, fw);
1294 if (!dialog.exec())
1295 return;
1296
1297 const QCursor oldCursor = core()->topLevel()->cursor();
1298 core()->topLevel()->setCursor(Qt::WaitCursor);
1299 // Estimate of required scaling to make form look the same on screen and printer.
1300 const double suggestedScaling = static_cast<double>(m_printer->physicalDpiX()) / static_cast<double>(fw->physicalDpiX());
1301
1302 QPainter painter(m_printer);
1303 painter.setRenderHint(QPainter::SmoothPixmapTransform);
1304
1305 // Clamp to page
1306 const QRectF page = painter.viewport();
1307 const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height());
1308 const double scaling = qMin(suggestedScaling, maxScaling);
1309
1310 const double xOffset = page.left() + qMax(0.0, (page.size().width() - scaling * pixmapSize.width()) / 2.0);
1311 const double yOffset = page.top() + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0);
1312
1313 // Draw.
1314 painter.translate(xOffset, yOffset);
1315 painter.scale(scaling, scaling);
1316 painter.drawPixmap(0, 0, pixmap);
1317 core()->topLevel()->setCursor(oldCursor);
1318
1319 showStatusBarMessage(tr("Printed %1.").arg(QFileInfo(fw->fileName()).fileName()));
1320#endif // HAS_PRINTER
1321}
1322
1323QT_END_NAMESPACE
QActionGroup * helpActions() const
QActionGroup * fileActions() const
QActionGroup * settingsActions() const
QAction * minimizeAction() const
QActionGroup * styleActions() const
QMap< QString, QString > pendingBackups() const
QActionGroup * editActions() const
QString uiExtension() const
QActionGroup * formActions() const
bool openForm(QWidget *parent)
QDesignerFormEditorInterface * core() const
QActionGroup * toolActions() const
QAction * previewFormAction() const
QActionGroup * windowActions() const
QAction * closeFormAction() const
void setWindowListSeparatorVisible(bool visible)
bool saveForm(QDesignerFormWindowInterface *fw)
QAction * editWidgets() const
QAction * openFormAction() const
QAction * viewCodeAction() const
QDesignerWorkbench * workbench() const
static const char * defaultToolbarPropertyName
void setBringAllToFrontVisible(bool visible)
QActionGroup * recentFilesActions() const
QDesignerFormWindowInterface * editor() const
QDesignerSettings(QDesignerFormEditorInterface *core)
QDesignerFormEditorInterface * core() const
QDesignerFormWindow * formWindow(int index) const
void updateBackup(QDesignerFormWindowInterface *fwi)
friend class QWidget
Definition qpainter.h:432
Auxiliary methods to store/retrieve settings.
QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message)
#define qDesigner
Definition qdesigner.h:20
static QByteArray formWindowContents(const QDesignerFormWindowInterface *fw, std::optional< QDir > alternativeDir={})
static QString fixResourceFileBackupPath(const QDesignerFormWindowInterface *fwi, const QDir &backupDir)
static QString fileDialogFilters(const QString &extension)
static QString savedMessage(const QString &fileName)
static QAction * createSeparator(QObject *parent)
QFileDialog * createSaveAsDialog(QWidget *parent, const QString &dir, const QString &extension)
static QActionGroup * createActionGroup(QObject *parent, bool exclusive=false)
static void fixActionContext(const QList< QAction * > &actions)