1
/****************************************************************************
2
**
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** Contact: Nokia Corporation (qt-info@nokia.com)
5
**
6
** This file is part of the Qt Designer of the Qt Toolkit.
7
**
8
** $QT_BEGIN_LICENSE:LGPL$
9
** No Commercial Usage
10
** This file contains pre-release code and may not be distributed.
11
** You may use this file in accordance with the terms and conditions
12
** contained in the either Technology Preview License Agreement or the
13
** Beta Release License Agreement.
14
**
15
** GNU Lesser General Public License Usage
16
** Alternatively, this file may be used under the terms of the GNU Lesser
17
** General Public License version 2.1 as published by the Free Software
18
** Foundation and appearing in the file LICENSE.LGPL included in the
19
** packaging of this file.  Please review the following information to
20
** ensure the GNU Lesser General Public License version 2.1 requirements
21
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22
**
23
** In addition, as a special exception, Nokia gives you certain
24
** additional rights. These rights are described in the Nokia Qt LGPL
25
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26
** package.
27
**
28
** GNU General Public License Usage
29
** Alternatively, this file may be used under the terms of the GNU
30
** General Public License version 3.0 as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL included in the
32
** packaging of this file.  Please review the following information to
33
** ensure the GNU General Public License version 3.0 requirements will be
34
** met: http://www.gnu.org/copyleft/gpl.html.
35
**
36
** If you are unsure which license is appropriate for your use, please
37
** contact the sales department at http://www.qtsoftware.com/contact.
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qdesigner_actions.h"
43
#include "designer_enums.h"
44
#include "qdesigner.h"
45
#include "qdesigner_workbench.h"
46
#include "qdesigner_formwindow.h"
47
#include "newform.h"
48
#include "versiondialog.h"
49
#include "saveformastemplate.h"
50
#include "qdesigner_toolwindow.h"
51
#include "preferencesdialog.h"
52
#include "appfontdialog.h"
53
54
#include <pluginmanager_p.h>
55
#include <qdesigner_formbuilder_p.h>
56
#include <qdesigner_utils_p.h>
57
#include <iconloader_p.h>
58
#include <qsimpleresource_p.h>
59
#include <previewmanager_p.h>
60
#include <codedialog_p.h>
61
#include <qdesigner_formwindowmanager_p.h>
62
#include "qdesigner_integration_p.h"
63
64
// sdk
65
#include <QtDesigner/QDesignerFormEditorInterface>
66
#include <QtDesigner/QDesignerFormWindowInterface>
67
#include <QtDesigner/QDesignerLanguageExtension>
68
#include <QtDesigner/QDesignerMetaDataBaseInterface>
69
#include <QtDesigner/QDesignerFormWindowManagerInterface>
70
#include <QtDesigner/QDesignerFormWindowCursorInterface>
71
#include <QtDesigner/QDesignerFormEditorPluginInterface>
72
#include <QtDesigner/QExtensionManager>
73
74
#include <QtDesigner/private/shared_settings_p.h>
75
#include <QtDesigner/private/formwindowbase_p.h>
76
77
#include <QtGui/QAction>
78
#include <QtGui/QActionGroup>
79
#include <QtGui/QStyleFactory>
80
#include <QtGui/QCloseEvent>
81
#include <QtGui/QFileDialog>
82
#include <QtGui/QMenu>
83
#include <QtGui/QMessageBox>
84
#include <QtGui/QPushButton>
85
#include <QtGui/QIcon>
86
#include <QtGui/QImage>
87
#include <QtGui/QPixmap>
88
#include <QtGui/QMdiSubWindow>
89
#include <QtGui/QPrintDialog>
90
#include <QtGui/QPainter>
91
#include <QtGui/QTransform>
92
#include <QtGui/QCursor>
93
#include <QtCore/QSizeF>
94
95
#include <QtCore/QLibraryInfo>
96
#include <QtCore/QBuffer>
97
#include <QtCore/QPluginLoader>
98
#include <QtCore/qdebug.h>
99
#include <QtCore/QTimer>
100
#include <QtCore/QMetaObject>
101
#include <QtCore/QFileInfo>
102
#include <QtGui/QStatusBar>
103
#include <QtGui/QDesktopWidget>
104
#include <QtXml/QDomDocument>
105
106
QT_BEGIN_NAMESPACE
107
108
using namespace qdesigner_internal;
109
110
//#ifdef Q_WS_MAC
111
#  define NONMODAL_PREVIEW
112
//#endif
113
114
static QAction *createSeparator(QObject *parent) {
115
    QAction * rc = new QAction(parent);
116
    rc->setSeparator(true);
117
    return rc;
118
}
119
120
static QActionGroup *createActionGroup(QObject *parent, bool exclusive = false) {
121
    QActionGroup * rc = new QActionGroup(parent);
122
    rc->setExclusive(exclusive);
123
    return rc;
124
}
125
126
static inline QString savedMessage(const QString &fileName)
127
{
128
    return QDesignerActions::tr("Saved %1.").arg(fileName);
129
}
130
131
// Prompt for a file and make sure an extension is added
132
// unless the user explicitly specifies another one.
133
134
static QString getSaveFileNameWithExtension(QWidget *parent, const QString &title, QString dir, const QString &filter, const QString &extension)
135
{
136
    const QChar dot = QLatin1Char('.');
137
138
    QString saveFile;
139
    while (true) {
140
        saveFile = QFileDialog::getSaveFileName(parent, title, dir, filter, 0, QFileDialog::DontConfirmOverwrite);
141
        if (saveFile.isEmpty())
142
            return saveFile;
143
144
        const QFileInfo fInfo(saveFile);
145
        if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) {
146
            saveFile += dot;
147
            saveFile += extension;
148
        }
149
150
        const QFileInfo fi(saveFile);
151
        if (!fi.exists())
152
            break;
153
154
        const QString prompt = QDesignerActions::tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName());
155
        if (QMessageBox::warning(parent, title, prompt, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
156
            break;
157
158
        dir = saveFile;
159
    }
160
    return saveFile;
161
}
162
163
QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench)
164
    : QObject(workbench),
165
      m_workbench(workbench),
166
      m_core(workbench->core()),
167
      m_settings(workbench->core()),
168
      m_backupTimer(new QTimer(this)),
169
      m_fileActions(createActionGroup(this)),
170
      m_recentFilesActions(createActionGroup(this)),
171
      m_editActions(createActionGroup(this)),
172
      m_formActions(createActionGroup(this)),
173
      m_settingsActions(createActionGroup(this)),
174
      m_windowActions(createActionGroup(this)),
175
      m_toolActions(createActionGroup(this, true)),
176
      m_helpActions(0),
177
      m_styleActions(0),
178
      m_editWidgetsAction(new QAction(tr("Edit Widgets"), this)),
179
      m_newFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filenew.png")), tr("&New..."), this)),
180
      m_openFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("fileopen.png")), tr("&Open..."), this)),
181
      m_saveFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filesave.png")), tr("&Save"), this)),
182
      m_saveFormAsAction(new QAction(tr("Save &As..."), this)),
183
      m_saveAllFormsAction(new QAction(tr("Save A&ll"), this)),
184
      m_saveFormAsTemplateAction(new QAction(tr("Save As &Template..."), this)),
185
      m_closeFormAction(new QAction(tr("&Close"), this)),
186
      m_savePreviewImageAction(new QAction(tr("Save &Image..."), this)),
187
      m_printPreviewAction(new QAction(tr("&Print..."), this)),
188
      m_quitAction(new QAction(tr("&Quit"), this)),
189
      m_previewFormAction(0),
190
      m_viewCodeAction(new QAction(tr("View &Code..."), this)),
191
      m_minimizeAction(new QAction(tr("&Minimize"), this)),
192
      m_bringAllToFrontSeparator(createSeparator(this)),
193
      m_bringAllToFrontAction(new QAction(tr("Bring All to Front"), this)),
194
      m_windowListSeparatorAction(createSeparator(this)),
195
      m_preferencesAction(new QAction(tr("Preferences..."), this)),
196
      m_appFontAction(new QAction(tr("Additional Fonts..."), this)),
197
      m_appFontDialog(0),
198
#ifndef QT_NO_PRINTER
199
      m_printer(0),
200
#endif
201
      m_previewManager(0)
202
{
203
    m_newFormAction->setIcon(QIcon::fromTheme("document-new", m_newFormAction->icon()));
204
    m_openFormAction->setIcon(QIcon::fromTheme("document-open", m_openFormAction->icon()));
205
    m_saveFormAction->setIcon(QIcon::fromTheme("document-save", m_saveFormAction->icon()));
206
207
    Q_ASSERT(m_core != 0);
208
    qdesigner_internal::QDesignerFormWindowManager *ifwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager *>(m_core->formWindowManager());
209
    Q_ASSERT(ifwm);
210
    m_previewManager = ifwm->previewManager();
211
    m_previewFormAction = ifwm->actionDefaultPreview();
212
    m_styleActions = ifwm->actionGroupPreviewInStyle();
213
    connect(ifwm, SIGNAL(formWindowSettingsChanged(QDesignerFormWindowInterface*)),
214
            this, SLOT(formWindowSettingsChanged(QDesignerFormWindowInterface*)));
215
216
    m_editWidgetsAction->setObjectName(QLatin1String("__qt_edit_widgets_action"));
217
    m_newFormAction->setObjectName(QLatin1String("__qt_new_form_action"));
218
    m_openFormAction->setObjectName(QLatin1String("__qt_open_form_action"));
219
    m_saveFormAction->setObjectName(QLatin1String("__qt_save_form_action"));
220
    m_saveFormAsAction->setObjectName(QLatin1String("__qt_save_form_as_action"));
221
    m_saveAllFormsAction->setObjectName(QLatin1String("__qt_save_all_forms_action"));
222
    m_saveFormAsTemplateAction->setObjectName(QLatin1String("__qt_save_form_as_template_action"));
223
    m_closeFormAction->setObjectName(QLatin1String("__qt_close_form_action"));
224
    m_quitAction->setObjectName(QLatin1String("__qt_quit_action"));
225
    m_previewFormAction->setObjectName(QLatin1String("__qt_preview_form_action"));
226
    m_viewCodeAction->setObjectName(QLatin1String("__qt_preview_code_action"));
227
    m_minimizeAction->setObjectName(QLatin1String("__qt_minimize_action"));
228
    m_bringAllToFrontAction->setObjectName(QLatin1String("__qt_bring_all_to_front_action"));
229
    m_preferencesAction->setObjectName(QLatin1String("__qt_preferences_action"));
230
231
    m_helpActions = createHelpActions();
232
233
    QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager();
234
    Q_ASSERT(formWindowManager != 0);
235
236
//
237
// file actions
238
//
239
    m_newFormAction->setShortcut(QKeySequence::New);
240
    connect(m_newFormAction, SIGNAL(triggered()), this, SLOT(createForm()));
241
    m_fileActions->addAction(m_newFormAction);
242
243
    m_openFormAction->setShortcut(QKeySequence::Open);
244
    connect(m_openFormAction, SIGNAL(triggered()), this, SLOT(slotOpenForm()));
245
    m_fileActions->addAction(m_openFormAction);
246
247
    m_fileActions->addAction(createRecentFilesMenu());
248
    m_fileActions->addAction(createSeparator(this));
249
250
    m_saveFormAction->setShortcut(QKeySequence::Save);
251
    connect(m_saveFormAction, SIGNAL(triggered()), this, SLOT(saveForm()));
252
    m_fileActions->addAction(m_saveFormAction);
253
254
    connect(m_saveFormAsAction, SIGNAL(triggered()), this, SLOT(saveFormAs()));
255
    m_fileActions->addAction(m_saveFormAsAction);
256
257
#ifdef Q_OS_MAC
258
    m_saveAllFormsAction->setShortcut(tr("ALT+CTRL+S"));
259
#else
260
    m_saveAllFormsAction->setShortcut(tr("CTRL+SHIFT+S")); // Commonly "Save As" on Mac
261
#endif
262
    connect(m_saveAllFormsAction, SIGNAL(triggered()), this, SLOT(saveAllForms()));
263
    m_fileActions->addAction(m_saveAllFormsAction);
264
265
    connect(m_saveFormAsTemplateAction, SIGNAL(triggered()), this, SLOT(saveFormAsTemplate()));
266
    m_fileActions->addAction(m_saveFormAsTemplateAction);
267
268
    m_fileActions->addAction(createSeparator(this));
269
270
    m_printPreviewAction->setShortcut(QKeySequence::Print);
271
    connect(m_printPreviewAction,  SIGNAL(triggered()), this, SLOT(printPreviewImage()));
272
    m_fileActions->addAction(m_printPreviewAction);
273
    m_printPreviewAction->setObjectName(QLatin1String("__qt_print_action"));
274
275
    connect(m_savePreviewImageAction,  SIGNAL(triggered()), this, SLOT(savePreviewImage()));
276
    m_savePreviewImageAction->setObjectName(QLatin1String("__qt_saveimage_action"));
277
    m_fileActions->addAction(m_savePreviewImageAction);
278
    m_fileActions->addAction(createSeparator(this));
279
280
    m_closeFormAction->setShortcut(QKeySequence::Close);
281
    connect(m_closeFormAction, SIGNAL(triggered()), this, SLOT(closeForm()));
282
    m_fileActions->addAction(m_closeFormAction);
283
    updateCloseAction();
284
285
    m_fileActions->addAction(createSeparator(this));
286
287
    m_quitAction->setShortcuts(QKeySequence::Quit);
288
    m_quitAction->setMenuRole(QAction::QuitRole);
289
    connect(m_quitAction, SIGNAL(triggered()), this, SLOT(shutdown()));
290
    m_fileActions->addAction(m_quitAction);
291
292
//
293
// edit actions
294
//
295
    QAction *undoAction = formWindowManager->actionUndo();
296
    undoAction->setObjectName(QLatin1String("__qt_undo_action"));
297
    undoAction->setShortcut(QKeySequence::Undo);
298
    m_editActions->addAction(undoAction);
299
300
    QAction *redoAction = formWindowManager->actionRedo();
301
    redoAction->setObjectName(QLatin1String("__qt_redo_action"));
302
    redoAction->setShortcut(QKeySequence::Redo);
303
    m_editActions->addAction(redoAction);
304
305
    m_editActions->addAction(createSeparator(this));
306
307
    m_editActions->addAction(formWindowManager->actionCut());
308
    m_editActions->addAction(formWindowManager->actionCopy());
309
    m_editActions->addAction(formWindowManager->actionPaste());
310
    m_editActions->addAction(formWindowManager->actionDelete());
311
312
    m_editActions->addAction(formWindowManager->actionSelectAll());
313
314
    m_editActions->addAction(createSeparator(this));
315
316
    m_editActions->addAction(formWindowManager->actionLower());
317
    m_editActions->addAction(formWindowManager->actionRaise());
318
319
//
320
// edit mode actions
321
//
322
323
    m_editWidgetsAction->setCheckable(true);
324
    QList<QKeySequence> shortcuts;
325
    shortcuts.append(QKeySequence(Qt::Key_F3));
326
#if QT_VERSION >= 0x040900 // "ESC" switching to edit mode: Activate once item delegates handle shortcut overrides for ESC.
327
    shortcuts.append(QKeySequence(Qt::Key_Escape));
328
#endif
329
    m_editWidgetsAction->setShortcuts(shortcuts);
330
    QIcon fallback(m_core->resourceLocation() + QLatin1String("/widgettool.png"));
331
    m_editWidgetsAction->setIcon(QIcon::fromTheme("designer-edit-widget", fallback));
332
    connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot()));
333
    m_editWidgetsAction->setChecked(true);
334
    m_editWidgetsAction->setEnabled(false);
335
    m_toolActions->addAction(m_editWidgetsAction);
336
337
    connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)),
338
                this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*)));
339
340
    QList<QObject*> builtinPlugins = QPluginLoader::staticInstances();
341
    builtinPlugins += m_core->pluginManager()->instances();
342
    foreach (QObject *plugin, builtinPlugins) {
343
        if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
344
            if (QAction *action = formEditorPlugin->action()) {
345
                m_toolActions->addAction(action);
346
                action->setCheckable(true);
347
            }
348
        }
349
    }
350
351
    connect(m_preferencesAction, SIGNAL(triggered()),  this, SLOT(showPreferencesDialog()));
352
    m_preferencesAction->setMenuRole(QAction::PreferencesRole);
353
    m_settingsActions->addAction(m_preferencesAction);
354
355
    connect(m_appFontAction, SIGNAL(triggered()),  this, SLOT(showAppFontDialog()));
356
    m_appFontAction->setMenuRole(QAction::PreferencesRole);
357
    m_settingsActions->addAction(m_appFontAction);
358
//
359
// form actions
360
//
361
362
    m_formActions->addAction(formWindowManager->actionHorizontalLayout());
363
    m_formActions->addAction(formWindowManager->actionVerticalLayout());
364
    m_formActions->addAction(formWindowManager->actionSplitHorizontal());
365
    m_formActions->addAction(formWindowManager->actionSplitVertical());
366
    m_formActions->addAction(formWindowManager->actionGridLayout());
367
    m_formActions->addAction(formWindowManager->actionFormLayout());
368
    m_formActions->addAction(formWindowManager->actionBreakLayout());
369
    m_formActions->addAction(formWindowManager->actionAdjustSize());
370
    m_formActions->addAction(formWindowManager->actionSimplifyLayout());
371
    m_formActions->addAction(createSeparator(this));
372
373
    m_previewFormAction->setShortcut(tr("CTRL+R"));
374
    m_formActions->addAction(m_previewFormAction);
375
    connect(m_previewManager, SIGNAL(firstPreviewOpened()), this, SLOT(updateCloseAction()));
376
    connect(m_previewManager, SIGNAL(lastPreviewClosed()), this, SLOT(updateCloseAction()));
377
378
    connect(m_viewCodeAction, SIGNAL(triggered()), this, SLOT(viewCode()));
379
    // Preview code only in Cpp
380
    if (qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core) == 0)
381
        m_formActions->addAction(m_viewCodeAction);
382
383
    m_formActions->addAction(createSeparator(this));
384
385
    m_formActions->addAction(ifwm->actionShowFormWindowSettingsDialog());
386
//
387
// window actions
388
//
389
    m_minimizeAction->setEnabled(false);
390
    m_minimizeAction->setCheckable(true);
391
    m_minimizeAction->setShortcut(tr("CTRL+M"));
392
    connect(m_minimizeAction, SIGNAL(triggered()), m_workbench, SLOT(toggleFormMinimizationState()));
393
    m_windowActions->addAction(m_minimizeAction);
394
395
    m_windowActions->addAction(m_bringAllToFrontSeparator);
396
    connect(m_bringAllToFrontAction, SIGNAL(triggered()), m_workbench, SLOT(bringAllToFront()));
397
    m_windowActions->addAction(m_bringAllToFrontAction);
398
    m_windowActions->addAction(m_windowListSeparatorAction);
399
400
    setWindowListSeparatorVisible(false);
401
402
//
403
// connections
404
//
405
    fixActionContext();
406
    activeFormWindowChanged(core()->formWindowManager()->activeFormWindow());
407
408
    m_backupTimer->start(180000); // 3min
409
    connect(m_backupTimer, SIGNAL(timeout()), this, SLOT(backupForms()));
410
411
    // Enable application font action
412
    connect(formWindowManager, SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged()));
413
    connect(formWindowManager, SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged()));
414
    formWindowCountChanged();
415
}
416
417
QActionGroup *QDesignerActions::createHelpActions()
418
{
419
    QActionGroup *helpActions = createActionGroup(this);
420
421
#ifndef QT_JAMBI_BUILD
422
    QAction *mainHelpAction = new QAction(tr("Qt Designer &Help"), this);
423
    mainHelpAction->setObjectName(QLatin1String("__qt_designer_help_action"));
424
    connect(mainHelpAction, SIGNAL(triggered()), this, SLOT(showDesignerHelp()));
425
    mainHelpAction->setShortcut(Qt::CTRL + Qt::Key_Question);
426
    helpActions->addAction(mainHelpAction);
427
428
    helpActions->addAction(createSeparator(this));
429
    QAction *widgetHelp = new QAction(tr("Current Widget Help"), this);
430
    widgetHelp->setObjectName(QLatin1String("__qt_current_widget_help_action"));
431
    widgetHelp->setShortcut(Qt::Key_F1);
432
    connect(widgetHelp, SIGNAL(triggered()), this, SLOT(showWidgetSpecificHelp()));
433
    helpActions->addAction(widgetHelp);
434
435
    helpActions->addAction(createSeparator(this));
436
    QAction *whatsNewAction = new QAction(tr("What's New in Qt Designer?"), this);
437
    whatsNewAction->setObjectName(QLatin1String("__qt_whats_new_in_qt_designer_action"));
438
    connect(whatsNewAction, SIGNAL(triggered()), this, SLOT(showWhatsNew()));
439
    helpActions->addAction(whatsNewAction);
440
#endif
441
442
    helpActions->addAction(createSeparator(this));
443
    QAction *aboutPluginsAction = new QAction(tr("About Plugins"), this);
444
    aboutPluginsAction->setObjectName(QLatin1String("__qt_about_plugins_action"));
445
    aboutPluginsAction->setMenuRole(QAction::ApplicationSpecificRole);
446
    connect(aboutPluginsAction, SIGNAL(triggered()), m_core->formWindowManager(), SLOT(aboutPlugins()));
447
    helpActions->addAction(aboutPluginsAction);
448
449
    QAction *aboutDesignerAction = new QAction(tr("About Qt Designer"), this);
450
    aboutDesignerAction->setMenuRole(QAction::AboutRole);
451
    aboutDesignerAction->setObjectName(QLatin1String("__qt_about_designer_action"));
452
    connect(aboutDesignerAction, SIGNAL(triggered()), this, SLOT(aboutDesigner()));
453
    helpActions->addAction(aboutDesignerAction);
454
455
    QAction *aboutQtAction = new QAction(tr("About Qt"), this);
456
    aboutQtAction->setMenuRole(QAction::AboutQtRole);
457
    aboutQtAction->setObjectName(QLatin1String("__qt_about_qt_action"));
458
    connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
459
    helpActions->addAction(aboutQtAction);
460
    return helpActions;
461
}
462
463
QDesignerActions::~QDesignerActions()
464
{
465
#ifndef QT_NO_PRINTER
466
    delete m_printer;
467
#endif
468
}
469
470
QString QDesignerActions::uiExtension() const
471
{
472
    QDesignerLanguageExtension *lang
473
        = qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core);
474
    if (lang)
475
        return lang->uiExtension();
476
    return QLatin1String("ui");
477
}
478
479
QAction *QDesignerActions::createRecentFilesMenu()
480
{
481
    QMenu *menu = new QMenu;
482
    QAction *act;
483
    // Need to insert this into the QAction.
484
    for (int i = 0; i < MaxRecentFiles; ++i) {
485
        act = new QAction(this);
486
        act->setVisible(false);
487
        connect(act, SIGNAL(triggered()), this, SLOT(openRecentForm()));
488
        m_recentFilesActions->addAction(act);
489
        menu->addAction(act);
490
    }
491
    updateRecentFileActions();
492
    menu->addSeparator();
493
    act = new QAction(tr("Clear &Menu"), this);
494
    act->setObjectName(QLatin1String("__qt_action_clear_menu_"));
495
    connect(act, SIGNAL(triggered()), this, SLOT(clearRecentFiles()));
496
    m_recentFilesActions->addAction(act);
497
    menu->addAction(act);
498
499
    act = new QAction(tr("&Recent Forms"), this);
500
    act->setMenu(menu);
501
    return act;
502
}
503
504
QActionGroup *QDesignerActions::toolActions() const
505
{ return m_toolActions; }
506
507
QDesignerWorkbench *QDesignerActions::workbench() const
508
{ return m_workbench; }
509
510
QDesignerFormEditorInterface *QDesignerActions::core() const
511
{ return m_core; }
512
513
QActionGroup *QDesignerActions::fileActions() const
514
{ return m_fileActions; }
515
516
QActionGroup *QDesignerActions::editActions() const
517
{ return m_editActions; }
518
519
QActionGroup *QDesignerActions::formActions() const
520
{ return m_formActions; }
521
522
QActionGroup *QDesignerActions::settingsActions() const
523
{  return m_settingsActions; }
524
525
QActionGroup *QDesignerActions::windowActions() const
526
{ return m_windowActions; }
527
528
QActionGroup *QDesignerActions::helpActions() const
529
{ return m_helpActions; }
530
531
QActionGroup *QDesignerActions::styleActions() const
532
{ return m_styleActions; }
533
534
QAction *QDesignerActions::previewFormAction() const
535
{ return m_previewFormAction; }
536
537
QAction *QDesignerActions::viewCodeAction() const
538
{ return m_viewCodeAction; }
539
540
541
void QDesignerActions::editWidgetsSlot()
542
{
543
    QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
544
    for (int i=0; i<formWindowManager->formWindowCount(); ++i) {
545
        QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i);
546
        formWindow->editWidgets();
547
    }
548
}
549
550
void QDesignerActions::createForm()
551
{
552
    showNewFormDialog(QString());
553
}
554
555
void QDesignerActions::showNewFormDialog(const QString &fileName)
556
{
557
    closePreview();
558
    NewForm *dlg = new NewForm(workbench(), workbench()->core()->topLevel(), fileName);
559
560
    dlg->setAttribute(Qt::WA_DeleteOnClose);
561
    dlg->setAttribute(Qt::WA_ShowModal);
562
563
    dlg->setGeometry(fixDialogRect(dlg->rect()));
564
    dlg->exec();
565
}
566
567
void QDesignerActions::slotOpenForm()
568
{
569
    openForm(core()->topLevel());
570
}
571
572
bool QDesignerActions::openForm(QWidget *parent)
573
{
574
    closePreview();
575
    const QString extension = uiExtension();
576
    const QStringList fileNames = QFileDialog::getOpenFileNames(parent, tr("Open Form"),
577
        m_openDirectory, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet);
578
579
    if (fileNames.isEmpty())
580
        return false;
581
582
    bool atLeastOne = false;
583
    foreach (QString fileName, fileNames) {
584
        if (readInForm(fileName) && !atLeastOne)
585
            atLeastOne = true;
586
    }
587
588
    return atLeastOne;
589
}
590
591
bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw)
592
{
593
    const QString extension = uiExtension();
594
595
    QString dir = fw->fileName();
596
    if (dir.isEmpty()) {
597
        do {
598
            // Build untitled name
599
            if (!m_saveDirectory.isEmpty()) {
600
                dir = m_saveDirectory;
601
                break;
602
            }
603
            if (!m_openDirectory.isEmpty()) {
604
                dir = m_openDirectory;
605
                break;
606
            }
607
            dir = QDir::current().absolutePath();
608
        } while (false);
609
        dir += QDir::separator();
610
        dir += QLatin1String("untitled.");
611
        dir += extension;
612
    }
613
614
    const  QString saveFile = getSaveFileNameWithExtension(fw, tr("Save Form As"), dir, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), extension);
615
    if (saveFile.isEmpty())
616
        return false;
617
618
    fw->setFileName(saveFile);
619
    return writeOutForm(fw, saveFile);
620
}
621
622
void QDesignerActions::saveForm()
623
{
624
    if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
625
        if (saveForm(fw))
626
            showStatusBarMessage(savedMessage(QFileInfo(fw->fileName()).fileName()));
627
    }
628
}
629
630
void QDesignerActions::saveAllForms()
631
{
632
    QString fileNames;
633
    QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
634
    if (const int totalWindows = formWindowManager->formWindowCount()) {
635
        const QString separator = QLatin1String(", ");
636
        for (int i = 0; i < totalWindows; ++i) {
637
            QDesignerFormWindowInterface *fw = formWindowManager->formWindow(i);
638
            if (fw && fw->isDirty()) {
639
                formWindowManager->setActiveFormWindow(fw);
640
                if (saveForm(fw)) {
641
                    if (!fileNames.isEmpty())
642
                        fileNames += separator;
643
                    fileNames += QFileInfo(fw->fileName()).fileName();
644
                } else {
645
                    break;
646
                }
647
            }
648
        }
649
    }
650
651
    if (!fileNames.isEmpty()) {
652
        showStatusBarMessage(savedMessage(fileNames));
653
    }
654
}
655
656
bool QDesignerActions::saveForm(QDesignerFormWindowInterface *fw)
657
{
658
    bool ret;
659
    if (fw->fileName().isEmpty())
660
        ret = saveFormAs(fw);
661
    else
662
        ret =  writeOutForm(fw, fw->fileName());
663
    return ret;
664
}
665
666
void QDesignerActions::closeForm()
667
{
668
    if (m_previewManager->previewCount()) {
669
        closePreview();
670
        return;
671
    }
672
673
    if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow())
674
        if (QWidget *parent = fw->parentWidget()) {
675
            if (QMdiSubWindow *mdiSubWindow = qobject_cast<QMdiSubWindow *>(parent->parentWidget())) {
676
                mdiSubWindow->close();
677
            } else {
678
                parent->close();
679
            }
680
        }
681
}
682
683
void QDesignerActions::saveFormAs()
684
{
685
    if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
686
        if (saveFormAs(fw))
687
            showStatusBarMessage(savedMessage(fw->fileName()));
688
    }
689
}
690
691
void QDesignerActions::saveFormAsTemplate()
692
{
693
    if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) {
694
        SaveFormAsTemplate dlg(core(), fw, fw->window());
695
        dlg.exec();
696
    }
697
}
698
699
void QDesignerActions::notImplementedYet()
700
{
701
    QMessageBox::information(core()->topLevel(), tr("Designer"), tr("Feature not implemented yet!"));
702
}
703
704
void QDesignerActions::closePreview()
705
{
706
    m_previewManager->closeAllPreviews();
707
}
708
709
void  QDesignerActions::viewCode()
710
{
711
    QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
712
    if (!fw)
713
        return;
714
    QString errorMessage;
715
    if (!qdesigner_internal::CodeDialog::showCodeDialog(fw, fw, &errorMessage))
716
        QMessageBox::warning(fw, tr("Code generation failed"), errorMessage);
717
}
718
719
void QDesignerActions::fixActionContext()
720
{
721
    QList<QAction*> actions;
722
    actions += m_fileActions->actions();
723
    actions += m_editActions->actions();
724
    actions += m_toolActions->actions();
725
    actions += m_formActions->actions();
726
    actions += m_windowActions->actions();
727
    actions += m_helpActions->actions();
728
729
    foreach (QAction *a, actions) {
730
        a->setShortcutContext(Qt::ApplicationShortcut);
731
    }
732
}
733
734
bool QDesignerActions::readInForm(const QString &fileName)
735
{
736
    QString fn = fileName;
737
738
    // First make sure that we don't have this one open already.
739
    QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager();
740
    const int totalWindows = formWindowManager->formWindowCount();
741
    for (int i = 0; i < totalWindows; ++i) {
742
        QDesignerFormWindowInterface *w = formWindowManager->formWindow(i);
743
        if (w->fileName() == fn) {
744
            w->raise();
745
            formWindowManager->setActiveFormWindow(w);
746
            addRecentFile(fn);
747
            return true;
748
        }
749
    }
750
751
    // Otherwise load it.
752
    do {
753
        QString errorMessage;
754
        if (workbench()->openForm(fn, &errorMessage)) {
755
            addRecentFile(fn);
756
            m_openDirectory = QFileInfo(fn).absolutePath();
757
            return true;
758
        } else {
759
            // prompt to reload
760
            QMessageBox box(QMessageBox::Warning, tr("Read error"),
761
                            tr("%1\nDo you want to update the file location or generate a new form?").arg(errorMessage),
762
                            QMessageBox::Cancel, core()->topLevel());
763
764
            QPushButton *updateButton = box.addButton(tr("&Update"), QMessageBox::ActionRole);
765
            QPushButton *newButton    = box.addButton(tr("&New Form"), QMessageBox::ActionRole);
766
            box.exec();
767
            if (box.clickedButton() == box.button(QMessageBox::Cancel))
768
                return false;
769
770
            if (box.clickedButton() == updateButton) {
771
                const QString extension = uiExtension();
772
                fn = QFileDialog::getOpenFileName(core()->topLevel(),
773
                                                  tr("Open Form"), m_openDirectory,
774
                                                  tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet);
775
776
                if (fn.isEmpty())
777
                    return false;
778
            } else if (box.clickedButton() == newButton) {
779
                // If the file does not exist, but its directory, is valid, open the template with the editor file name set to it.
780
                // (called from command line).
781
                QString newFormFileName;
782
                const  QFileInfo fInfo(fn);
783
                if (!fInfo.exists()) {
784
                    // Normalize file name
785
                    const QString directory = fInfo.absolutePath();
786
                    if (QDir(directory).exists()) {
787
                        newFormFileName = directory;
788
                        newFormFileName  += QLatin1Char('/');
789
                        newFormFileName  += fInfo.fileName();
790
                    }
791
                }
792
                showNewFormDialog(newFormFileName);
793
                return false;
794
            }
795
        }
796
    } while (true);
797
    return true;
798
}
799
800
static QString createBackup(const QString &fileName)
801
{
802
    const QString suffix = QLatin1String(".bak");
803
    QString backupFile = fileName + suffix;
804
    QFileInfo fi(backupFile);
805
    int i = 0;
806
    while (fi.exists()) {
807
        backupFile = fileName + suffix + QString::number(++i);
808
        fi.setFile(backupFile);
809
    }
810
811
    if (QFile::copy(fileName, backupFile))
812
        return backupFile;
813
    return QString();
814
}
815
816
static void removeBackup(const QString &backupFile)
817
{
818
    if (!backupFile.isEmpty())
819
        QFile::remove(backupFile);
820
}
821
822
bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile)
823
{
824
    Q_ASSERT(fw && !saveFile.isEmpty());
825
826
    QString backupFile;
827
    QFileInfo fi(saveFile);
828
    if (fi.exists())
829
        backupFile = createBackup(saveFile);
830
831
    QString contents = fw->contents();
832
    if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fw)) {
833
        if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator)
834
            contents.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
835
    }
836
    const QByteArray utf8Array = contents.toUtf8();
837
    m_workbench->updateBackup(fw);
838
839
    QFile f(saveFile);
840
    while (!f.open(QFile::WriteOnly)) {
841
        QMessageBox box(QMessageBox::Warning,
842
                        tr("Save Form?"),
843
                        tr("Could not open file"),
844
                        QMessageBox::NoButton, fw);
845
846
        box.setWindowModality(Qt::WindowModal);
847
        box.setInformativeText(tr("The file %1 could not be opened."
848
                               "\nReason: %2"
849
                               "\nWould you like to retry or select a different file?")
850
                                .arg(f.fileName()).arg(f.errorString()));
851
        QPushButton *retryButton = box.addButton(QMessageBox::Retry);
852
        retryButton->setDefault(true);
853
        QPushButton *switchButton = box.addButton(tr("Select New File"), QMessageBox::AcceptRole);
854
        QPushButton *cancelButton = box.addButton(QMessageBox::Cancel);
855
        box.exec();
856
857
        if (box.clickedButton() == cancelButton) {
858
            removeBackup(backupFile);
859
            return false;
860
        } else if (box.clickedButton() == switchButton) {
861
            QString extension = uiExtension();
862
            const QString fileName = QFileDialog::getSaveFileName(fw, tr("Save Form As"),
863
                                                                  QDir::current().absolutePath(),
864
                                                                  QLatin1String("*.") + extension);
865
            if (fileName.isEmpty()) {
866
                removeBackup(backupFile);
867
                return false;
868
            }
869
            if (f.fileName() != fileName) {
870
                removeBackup(backupFile);
871
                fi.setFile(fileName);
872
                backupFile = QString();
873
                if (fi.exists())
874
                    backupFile = createBackup(fileName);
875
            }
876
            f.setFileName(fileName);
877
            fw->setFileName(fileName);
878
        }
879
        // loop back around...
880
    }
881
    while (f.write(utf8Array, utf8Array.size()) != utf8Array.size()) {
882
        QMessageBox box(QMessageBox::Warning, tr("Save Form?"),
883
                        tr("Could not write file"),
884
                        QMessageBox::Retry|QMessageBox::Cancel, fw);
885
        box.setWindowModality(Qt::WindowModal);
886
        box.setInformativeText(tr("It was not possible to write the entire file %1 to disk."
887
                                "\nReason:%2\nWould you like to retry?")
888
                                .arg(f.fileName()).arg(f.errorString()));
889
        box.setDefaultButton(QMessageBox::Retry);
890
        switch (box.exec()) {
891
        case QMessageBox::Retry:
892
            f.resize(0);
893
            break;
894
        default:
895
            return false;
896
        }
897
    }
898
    f.close();
899
    removeBackup(backupFile);
900
    addRecentFile(saveFile);
901
    m_saveDirectory = QFileInfo(f).absolutePath();
902
903
    fw->setDirty(false);
904
    fw->parentWidget()->setWindowModified(false);
905
    return true;
906
}
907
908
void QDesignerActions::shutdown()
909
{
910
    // Follow the idea from the Mac, i.e. send the Application a close event
911
    // and if it's accepted, quit.
912
    QCloseEvent ev;
913
    QApplication::sendEvent(qDesigner, &ev);
914
    if (ev.isAccepted())
915
        qDesigner->quit();
916
}
917
918
void QDesignerActions::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow)
919
{
920
    const bool enable = formWindow != 0;
921
    m_saveFormAction->setEnabled(enable);
922
    m_saveFormAsAction->setEnabled(enable);
923
    m_saveAllFormsAction->setEnabled(enable);
924
    m_saveFormAsTemplateAction->setEnabled(enable);
925
    m_closeFormAction->setEnabled(enable);
926
    m_savePreviewImageAction->setEnabled(enable);
927
    m_printPreviewAction->setEnabled(enable);
928
929
    m_editWidgetsAction->setEnabled(enable);
930
931
    m_previewFormAction->setEnabled(enable);
932
    m_viewCodeAction->setEnabled(enable);
933
    m_styleActions->setEnabled(enable);
934
}
935
936
void QDesignerActions::formWindowSettingsChanged(QDesignerFormWindowInterface *fw)
937
{
938
    if (QDesignerFormWindow *window = m_workbench->findFormWindow(fw))
939
        window->updateChanged();
940
}
941
942
void QDesignerActions::updateRecentFileActions()
943
{
944
    QStringList files = m_settings.recentFilesList();
945
    const int originalSize = files.size();
946
    int numRecentFiles = qMin(files.size(), int(MaxRecentFiles));
947
    const QList<QAction *> recentFilesActs = m_recentFilesActions->actions();
948
949
    for (int i = 0; i < numRecentFiles; ++i) {
950
        const QFileInfo fi(files[i]);
951
        // If the file doesn't exist anymore, just remove it from the list so
952
        // people don't get confused.
953
        if (!fi.exists()) {
954
            files.removeAt(i);
955
            --i;
956
            numRecentFiles = qMin(files.size(), int(MaxRecentFiles));
957
            continue;
958
        }
959
        const QString text = fi.fileName();
960
        recentFilesActs[i]->setText(text);
961
        recentFilesActs[i]->setIconText(files[i]);
962
        recentFilesActs[i]->setVisible(true);
963
    }
964
965
    for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
966
        recentFilesActs[j]->setVisible(false);
967
968
    // If there's been a change, right it back
969
    if (originalSize != files.size())
970
        m_settings.setRecentFilesList(files);
971
}
972
973
void QDesignerActions::openRecentForm()
974
{
975
    if (const QAction *action = qobject_cast<const QAction *>(sender())) {
976
        if (!readInForm(action->iconText()))
977
            updateRecentFileActions(); // File doesn't exist, remove it from settings
978
    }
979
}
980
981
void QDesignerActions::clearRecentFiles()
982
{
983
    m_settings.setRecentFilesList(QStringList());
984
    updateRecentFileActions();
985
}
986
987
QActionGroup *QDesignerActions::recentFilesActions() const
988
{
989
    return m_recentFilesActions;
990
}
991
992
void QDesignerActions::addRecentFile(const QString &fileName)
993
{
994
    QStringList files = m_settings.recentFilesList();
995
    files.removeAll(fileName);
996
    files.prepend(fileName);
997
    while (files.size() > MaxRecentFiles)
998
        files.removeLast();
999
1000
    m_settings.setRecentFilesList(files);
1001
    updateRecentFileActions();
1002
}
1003
1004
QAction *QDesignerActions::openFormAction() const
1005
{
1006
    return  m_openFormAction;
1007
}
1008
1009
QAction *QDesignerActions::closeFormAction() const
1010
{
1011
    return m_closeFormAction;
1012
}
1013
1014
QAction *QDesignerActions::minimizeAction() const
1015
{
1016
    return m_minimizeAction;
1017
}
1018
1019
void QDesignerActions::showDesignerHelp()
1020
{
1021
    QString url = AssistantClient::designerManualUrl();
1022
    url += QLatin1String("designer-manual.html");
1023
    showHelp(url);
1024
}
1025
1026
void QDesignerActions::showWhatsNew()
1027
{
1028
    QString url = AssistantClient::qtReferenceManualUrl();
1029
    url += QLatin1String("qt4-designer.html");
1030
    showHelp(url);
1031
}
1032
1033
void QDesignerActions::helpRequested(const QString &manual, const QString &document)
1034
{
1035
    QString url = AssistantClient::documentUrl(manual);
1036
    url += document;
1037
    showHelp(url);
1038
}
1039
1040
void QDesignerActions::showHelp(const QString &url)
1041
{
1042
    QString errorMessage;
1043
    if (!m_assistantClient.showPage(url, &errorMessage))
1044
        QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage);
1045
}
1046
1047
void QDesignerActions::aboutDesigner()
1048
{
1049
    VersionDialog mb(core()->topLevel());
1050
    mb.setWindowTitle(tr("About Qt Designer"));
1051
    if (mb.exec()) {
1052
        QMessageBox messageBox(QMessageBox::Information, QLatin1String("Easter Egg"),
1053
                               QLatin1String("Easter Egg"), QMessageBox::Ok, core()->topLevel());
1054
        messageBox.setInformativeText(QLatin1String("The Easter Egg has been removed."));
1055
        messageBox.exec();
1056
    }
1057
}
1058
1059
QAction *QDesignerActions::editWidgets() const
1060
{
1061
    return m_editWidgetsAction;
1062
}
1063
1064
void QDesignerActions::showWidgetSpecificHelp()
1065
{
1066
    QString helpId;
1067
    if (const qdesigner_internal::QDesignerIntegration *integration = qobject_cast<qdesigner_internal::QDesignerIntegration *>(core()->integration()))
1068
        helpId = integration->contextHelpId();
1069
1070
    if (helpId.isEmpty()) {
1071
        showDesignerHelp();
1072
        return;
1073
    }
1074
1075
    QString errorMessage;
1076
    const bool rc = m_assistantClient.activateIdentifier(helpId, &errorMessage);
1077
    if (!rc)
1078
        QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage);
1079
}
1080
1081
void QDesignerActions::updateCloseAction()
1082
{
1083
    if (m_previewManager->previewCount()) {
1084
        m_closeFormAction->setText(tr("&Close Preview"));
1085
    } else {
1086
        m_closeFormAction->setText(tr("&Close"));
1087
    }
1088
}
1089
1090
void QDesignerActions::backupForms()
1091
{
1092
    const int count = m_workbench->formWindowCount();
1093
    if (!count || !ensureBackupDirectories())
1094
        return;
1095
1096
1097
    QStringList tmpFiles;
1098
    QMap<QString, QString> backupMap;
1099
    QDir backupDir(m_backupPath);
1100
    const bool warningsEnabled = qdesigner_internal::QSimpleResource::setWarningsEnabled(false);
1101
    for (int i = 0; i < count; ++i) {
1102
        QDesignerFormWindow *fw = m_workbench->formWindow(i);
1103
        QDesignerFormWindowInterface *fwi = fw->editor();
1104
1105
        QString formBackupName;
1106
        QTextStream(&formBackupName) << m_backupPath << QDir::separator()
1107
                                     << QLatin1String("backup") << i << QLatin1String(".bak");
1108
1109
        QString fwn = QDir::convertSeparators(fwi->fileName());
1110
        if (fwn.isEmpty())
1111
            fwn = fw->windowTitle();
1112
1113
        backupMap.insert(fwn, formBackupName);
1114
1115
        QFile file(formBackupName.replace(m_backupPath, m_backupTmpPath));
1116
        if (file.open(QFile::WriteOnly)){
1117
            QString contents = fixResourceFileBackupPath(fwi, backupDir);
1118
            if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fwi)) {
1119
                if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator)
1120
                    contents.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
1121
            }
1122
            const QByteArray utf8Array = contents.toUtf8();
1123
            if (file.write(utf8Array, utf8Array.size()) != utf8Array.size()) {
1124
                backupMap.remove(fwn);
1125
                qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(file.fileName()));
1126
            } else
1127
                tmpFiles.append(formBackupName);
1128
1129
            file.close();
1130
        }
1131
    }
1132
    qdesigner_internal::QSimpleResource::setWarningsEnabled(warningsEnabled);
1133
    if(!tmpFiles.isEmpty()) {
1134
        const QStringList backupFiles = backupDir.entryList(QDir::Files);
1135
        if(!backupFiles.isEmpty()) {
1136
            QStringListIterator it(backupFiles);
1137
            while (it.hasNext())
1138
                backupDir.remove(it.next());
1139
        }
1140
1141
        QStringListIterator it(tmpFiles);
1142
        while (it.hasNext()) {
1143
            const QString tmpName = it.next();
1144
            QString name(tmpName);
1145
            name.replace(m_backupTmpPath, m_backupPath);
1146
            QFile tmpFile(tmpName);
1147
            if (!tmpFile.copy(name))
1148
                qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(name));
1149
            tmpFile.remove();
1150
        }
1151
1152
        m_settings.setBackup(backupMap);
1153
    }
1154
}
1155
1156
QString QDesignerActions::fixResourceFileBackupPath(QDesignerFormWindowInterface *fwi, const QDir& backupDir)
1157
{
1158
    const QString content = fwi->contents();
1159
    QDomDocument domDoc(QLatin1String("backup"));
1160
    if(!domDoc.setContent(content))
1161
        return content;
1162
1163
    const QDomNodeList list = domDoc.elementsByTagName(QLatin1String("resources"));
1164
    if (list.isEmpty())
1165
        return content;
1166
1167
    for (int i = 0; i < list.count(); i++) {
1168
        const QDomNode node = list.at(i);
1169
        if (!node.isNull()) {
1170
            const QDomElement element = node.toElement();
1171
            if(!element.isNull() && element.tagName() == QLatin1String("resources")) {
1172
                QDomNode childNode = element.firstChild();
1173
                while (!childNode.isNull()) {
1174
                    QDomElement childElement = childNode.toElement();
1175
                    if(!childElement.isNull() && childElement.tagName() == QLatin1String("include")) {
1176
                        const QString attr = childElement.attribute(QLatin1String("location"));
1177
                        const QString path = fwi->absoluteDir().absoluteFilePath(attr);
1178
                        childElement.setAttribute(QLatin1String("location"), backupDir.relativeFilePath(path));
1179
                    }
1180
                    childNode = childNode.nextSibling();
1181
                }
1182
            }
1183
        }
1184
    }
1185
1186
1187
    return domDoc.toString();
1188
}
1189
1190
QRect QDesignerActions::fixDialogRect(const QRect &rect) const
1191
{
1192
    QRect frameGeometry;
1193
    const QRect availableGeometry = QApplication::desktop()->availableGeometry(core()->topLevel());
1194
1195
    if (workbench()->mode() == DockedMode) {
1196
        frameGeometry = core()->topLevel()->frameGeometry();
1197
    } else
1198
        frameGeometry = availableGeometry;
1199
1200
    QRect dlgRect = rect;
1201
    dlgRect.moveCenter(frameGeometry.center());
1202
1203
    // make sure that parts of the dialog are not outside of screen
1204
    dlgRect.moveBottom(qMin(dlgRect.bottom(), availableGeometry.bottom()));
1205
    dlgRect.moveRight(qMin(dlgRect.right(), availableGeometry.right()));
1206
    dlgRect.moveLeft(qMax(dlgRect.left(), availableGeometry.left()));
1207
    dlgRect.moveTop(qMax(dlgRect.top(), availableGeometry.top()));
1208
1209
    return dlgRect;
1210
}
1211
1212
void QDesignerActions::showStatusBarMessage(const QString &message) const
1213
{
1214
    if (workbench()->mode() == DockedMode) {
1215
        QStatusBar *bar = qDesigner->mainWindow()->statusBar();
1216
        if (bar && !bar->isHidden())
1217
            bar->showMessage(message, 3000);
1218
    }
1219
}
1220
1221
void QDesignerActions::setBringAllToFrontVisible(bool visible)
1222
{
1223
      m_bringAllToFrontSeparator->setVisible(visible);
1224
      m_bringAllToFrontAction->setVisible(visible);
1225
}
1226
1227
void QDesignerActions::setWindowListSeparatorVisible(bool visible)
1228
{
1229
    m_windowListSeparatorAction->setVisible(visible);
1230
}
1231
1232
bool QDesignerActions::ensureBackupDirectories() {
1233
1234
    if (m_backupPath.isEmpty()) {
1235
        // create names
1236
        m_backupPath = QDir::homePath();
1237
        m_backupPath += QDir::separator();
1238
        m_backupPath += QLatin1String(".designer");
1239
        m_backupPath += QDir::separator();
1240
        m_backupPath += QLatin1String("backup");
1241
        m_backupPath = QDir::convertSeparators(m_backupPath );
1242
1243
        m_backupTmpPath = m_backupPath;
1244
        m_backupTmpPath += QDir::separator();
1245
        m_backupTmpPath += QLatin1String("tmp");
1246
        m_backupTmpPath = QDir::convertSeparators(m_backupTmpPath);
1247
    }
1248
1249
    // ensure directories
1250
    const QDir backupDir(m_backupPath);
1251
    const QDir backupTmpDir(m_backupTmpPath);
1252
1253
    if (!backupDir.exists()) {
1254
        if (!backupDir.mkpath(m_backupPath)) {
1255
            qdesigner_internal::designerWarning(tr("The backup directory %1 could not be created.").arg(m_backupPath));
1256
            return false;
1257
        }
1258
    }
1259
    if (!backupTmpDir.exists()) {
1260
        if (!backupTmpDir.mkpath(m_backupTmpPath)) {
1261
            qdesigner_internal::designerWarning(tr("The temporary backup directory %1 could not be created.").arg(m_backupTmpPath));
1262
            return false;
1263
        }
1264
    }
1265
    return true;
1266
}
1267
1268
void QDesignerActions::showPreferencesDialog()
1269
{
1270
    PreferencesDialog preferencesDialog(workbench()->core(), m_core->topLevel());
1271
    preferencesDialog.exec();
1272
}
1273
1274
void QDesignerActions::showAppFontDialog()
1275
{
1276
    if (!m_appFontDialog) // Might get deleted when switching ui modes
1277
        m_appFontDialog = new AppFontDialog(core()->topLevel());
1278
    m_appFontDialog->show();
1279
    m_appFontDialog->raise();
1280
}
1281
1282
QPixmap QDesignerActions::createPreviewPixmap(QDesignerFormWindowInterface *fw)
1283
{
1284
    const QCursor oldCursor = core()->topLevel()->cursor();
1285
    core()->topLevel()->setCursor(Qt::WaitCursor);
1286
1287
    QString errorMessage;
1288
    const QPixmap pixmap = m_previewManager->createPreviewPixmap(fw, QString(), &errorMessage);
1289
    core()->topLevel()->setCursor(oldCursor);
1290
    if (pixmap.isNull()) {
1291
        QMessageBox::warning(fw, tr("Preview failed"), errorMessage);
1292
    }
1293
    return pixmap;
1294
}
1295
1296
qdesigner_internal::PreviewConfiguration QDesignerActions::previewConfiguration()
1297
{
1298
    qdesigner_internal::PreviewConfiguration pc;
1299
    QDesignerSharedSettings settings(core());
1300
    if (settings.isCustomPreviewConfigurationEnabled())
1301
        pc = settings.customPreviewConfiguration();
1302
    return pc;
1303
}
1304
1305
void QDesignerActions::savePreviewImage()
1306
{
1307
    const char *format = "png";
1308
1309
    QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
1310
    if (!fw)
1311
        return;
1312
1313
    QImage image;
1314
    const QString extension = QString::fromAscii(format);
1315
    const QString filter = tr("Image files (*.%1)").arg(extension);
1316
1317
    QString suggestion = fw->fileName();
1318
    if (!suggestion.isEmpty()) {
1319
        suggestion = QFileInfo(suggestion).baseName();
1320
        suggestion += QLatin1Char('.');
1321
        suggestion += extension;
1322
    }
1323
    do {
1324
        const QString fileName  = getSaveFileNameWithExtension(fw, tr("Save Image"), suggestion, filter, extension);
1325
        if (fileName.isEmpty())
1326
            break;
1327
1328
        if (image.isNull()) {
1329
            const QPixmap pixmap = createPreviewPixmap(fw);
1330
            if (pixmap.isNull())
1331
                break;
1332
1333
            image = pixmap.toImage();
1334
        }
1335
1336
        if (image.save(fileName, format)) {
1337
            showStatusBarMessage(tr("Saved image %1.").arg(QFileInfo(fileName).fileName()));
1338
            break;
1339
        }
1340
1341
        QMessageBox box(QMessageBox::Warning, tr("Save Image"),
1342
                        tr("The file %1 could not be written.").arg( fileName),
1343
                        QMessageBox::Retry|QMessageBox::Cancel, fw);
1344
        if (box.exec() == QMessageBox::Cancel)
1345
            break;
1346
    } while (true);
1347
}
1348
1349
void QDesignerActions::formWindowCountChanged()
1350
{
1351
    const bool enabled = m_core->formWindowManager()->formWindowCount() == 0;
1352
    /* Disable the application font action if there are form windows open
1353
     * as the reordering of the fonts sets font properties to 'changed'
1354
     * and overloaded fonts are not updated. */
1355
    static const QString disabledTip = tr("Please close all forms to enable the loading of additional fonts.");
1356
    m_appFontAction->setEnabled(enabled);
1357
    m_appFontAction->setStatusTip(enabled ? QString() : disabledTip);
1358
}
1359
1360
void QDesignerActions::printPreviewImage()
1361
{
1362
#ifndef QT_NO_PRINTER
1363
    QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow();
1364
    if (!fw)
1365
        return;
1366
1367
    if (!m_printer)
1368
        m_printer = new QPrinter(QPrinter::HighResolution);
1369
1370
    m_printer->setFullPage(false);
1371
1372
    // Grab the image to be able to a suggest suitable orientation
1373
    const QPixmap pixmap = createPreviewPixmap(fw);
1374
    if (pixmap.isNull())
1375
        return;
1376
1377
    const QSizeF pixmapSize = pixmap.size();
1378
    m_printer->setOrientation( pixmapSize.width() > pixmapSize.height() ?  QPrinter::Landscape :  QPrinter::Portrait);
1379
1380
    // Printer parameters
1381
    QPrintDialog dialog(m_printer, fw);
1382
    if (!dialog.exec())
1383
        return;
1384
1385
    const QCursor oldCursor = core()->topLevel()->cursor();
1386
    core()->topLevel()->setCursor(Qt::WaitCursor);
1387
    // Estimate of required scaling to make form look the same on screen and printer.
1388
    const double suggestedScaling = static_cast<double>(m_printer->physicalDpiX()) /  static_cast<double>(fw->physicalDpiX());
1389
1390
    QPainter painter(m_printer);
1391
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
1392
1393
    // Clamp to page
1394
    const QRectF page =  painter.viewport();
1395
    const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height());
1396
    const double scaling = qMin(suggestedScaling, maxScaling);
1397
1398
    const double xOffset = page.left() + qMax(0.0, (page.size().width()  - scaling * pixmapSize.width())  / 2.0);
1399
    const double yOffset = page.top()  + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0);
1400
1401
    // Draw.
1402
    painter.translate(xOffset, yOffset);
1403
    painter.scale(scaling, scaling);
1404
    painter.drawPixmap(0, 0, pixmap);
1405
    core()->topLevel()->setCursor(oldCursor);
1406
1407
    showStatusBarMessage(tr("Printed %1.").arg(QFileInfo(fw->fileName()).fileName()));
1408
#endif
1409
}
1410
1411
QT_END_NAMESPACE