OSDN Git Service

core: use a class derived from QList<int> instead of a QList<int> for Core::Context
[qt-creator-jp/qt-creator-jp.git] / src / plugins / designer / formeditorw.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "formeditorw.h"
31 #include "formwindoweditor.h"
32 #include "designerconstants.h"
33 #include "settingsmanager.h"
34 #include "settingspage.h"
35 #include "editorwidget.h"
36 #include "editordata.h"
37 #include "qtcreatorintegration.h"
38 #include "designerxmleditor.h"
39 #include "designercontext.h"
40 #include "editorwidget.h"
41 #include "resourcehandler.h"
42 #include <widgethost.h>
43
44 #include <coreplugin/editortoolbar.h>
45 #include <coreplugin/designmode.h>
46 #include <coreplugin/coreconstants.h>
47 #include <coreplugin/icore.h>
48 #include <coreplugin/helpmanager.h>
49 #include <coreplugin/uniqueidmanager.h>
50 #include <coreplugin/actionmanager/actionmanager.h>
51 #include <coreplugin/actionmanager/actioncontainer.h>
52 #include <coreplugin/actionmanager/command.h>
53 #include <coreplugin/editormanager/editormanager.h>
54 #include <texteditor/texteditorsettings.h>
55 #include <extensionsystem/pluginmanager.h>
56 #include <utils/qtcassert.h>
57
58 #include <QtDesigner/QDesignerFormEditorPluginInterface>
59 #include "qt_private/pluginmanager_p.h"
60
61 #include "qt_private/iconloader_p.h"  // createIconSet
62 #include "qt_private/qdesigner_formwindowmanager_p.h"
63 #include "qt_private/formwindowbase_p.h"
64 #include <QtDesigner/QDesignerFormEditorInterface>
65 #include <QtDesigner/QDesignerComponents>
66
67 #include <QtDesigner/QDesignerWidgetBoxInterface>
68 #include <QtDesigner/abstractobjectinspector.h>
69 #include <QtDesigner/QDesignerPropertyEditorInterface>
70 #include <QtDesigner/QDesignerActionEditorInterface>
71 #include <QtDesigner/QDesignerFormEditorInterface>
72
73 #include <QtGui/QAction>
74 #include <QtGui/QActionGroup>
75 #include <QtGui/QApplication>
76 #include <QtGui/QCursor>
77 #include <QtGui/QDockWidget>
78 #include <QtGui/QMenu>
79 #include <QtGui/QMainWindow>
80 #include <QtGui/QMessageBox>
81 #include <QtGui/QKeySequence>
82 #include <QtGui/QPrintDialog>
83 #include <QtGui/QPrinter>
84 #include <QtGui/QPainter>
85 #include <QtGui/QStyle>
86 #include <QtGui/QToolBar>
87 #include <QtGui/QVBoxLayout>
88
89 #include <QtCore/QDebug>
90 #include <QtCore/QSettings>
91 #include <QtCore/QSignalMapper>
92 #include <QtCore/QPluginLoader>
93 #include <QtCore/QTime>
94
95 static const char settingsGroup[] = "Designer";
96
97 #ifdef Q_OS_MAC
98     enum { osMac = 1 };
99 #else
100     enum { osMac = 0 };
101 #endif
102
103 /* Actions of the designer plugin:
104  * Designer provides a toolbar which is subject to a context change (to
105  * "edit mode" context) when it is focused.
106  * In order to prevent its actions from being disabled/hidden by that context
107  * change, the actions are registered on the global context. In currentEditorChanged(),
108  * the ones that are present in the global edit menu are set visible/invisible manually.
109  * The designer context is currently used for Cut/Copy/Paste, etc. */
110
111 static inline QIcon designerIcon(const QString &iconName)
112 {
113     const QIcon icon = qdesigner_internal::createIconSet(iconName);
114     if (icon.isNull())
115         qWarning() << "Unable to locate " << iconName;
116     return icon;
117 }
118
119 // Create a menu separator
120 static inline QAction *createSeparator(QObject *parent,
121                                  Core::ActionManager *am,
122                                  const Core::Context &context,
123                                  Core::ActionContainer *container,
124                                  const QString &name = QString(),
125                                  const QString &group = QString())
126 {
127     QAction *actSeparator = new QAction(parent);
128     actSeparator->setSeparator(true);
129     Core::Command *command = am->registerAction(actSeparator, name, context);
130     container->addAction(command, group);
131     return actSeparator;
132 }
133
134 using namespace Designer::Constants;
135
136 namespace Designer {
137 namespace Internal {
138
139 // --------- FormEditorW
140
141 FormEditorW *FormEditorW::m_self = 0;
142
143 FormEditorW::FormEditorW() :
144     m_formeditor(QDesignerComponents::createFormEditor(0)),
145     m_integration(0),
146     m_fwm(0),
147     m_core(Core::ICore::instance()),
148     m_initStage(RegisterPlugins),
149     m_actionGroupEditMode(0),
150     m_actionPrint(0),
151     m_actionPreview(0),
152     m_actionGroupPreviewInStyle(0),
153     m_actionAboutPlugins(0),
154     m_shortcutMapper(new QSignalMapper(this)),
155     m_context(0),
156     m_modeWidget(0),
157     m_editorWidget(0),
158     m_designMode(0),
159     m_editorToolBar(0),
160     m_toolBar(0)
161 {
162     if (Designer::Constants::Internal::debug)
163         qDebug() << Q_FUNC_INFO;
164     QTC_ASSERT(!m_self, return);
165     m_self = this;
166     QTC_ASSERT(m_core, return);
167
168     qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount,
169           static_cast<QWidget *>(0));
170
171     m_formeditor->setTopLevel(qobject_cast<QWidget *>(m_core->editorManager()));
172     m_formeditor->setSettingsManager(new SettingsManager());
173
174     m_fwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager*>(m_formeditor->formWindowManager());
175     QTC_ASSERT(m_fwm, return);
176
177     Core::UniqueIDManager *idMan = Core::UniqueIDManager::instance();
178     m_contexts << idMan->uniqueIdentifier(QLatin1String(Designer::Constants::C_FORMEDITOR));
179
180     setupActions();
181
182     foreach (QDesignerOptionsPageInterface *designerPage, m_formeditor->optionsPages()) {
183         SettingsPage *settingsPage = new SettingsPage(designerPage);
184         ExtensionSystem::PluginManager::instance()->addObject(settingsPage);
185         m_settingsPages.append(settingsPage);
186     }
187
188     connect(m_core->editorManager(), SIGNAL(currentEditorChanged(Core::IEditor *)),
189             this, SLOT(currentEditorChanged(Core::IEditor *)));
190     connect(m_shortcutMapper, SIGNAL(mapped(QObject *)),
191             this, SLOT(updateShortcut(QObject *)));
192 }
193
194 FormEditorW::~FormEditorW()
195 {
196     if (m_context)
197         m_core->removeContextObject(m_context);
198     if (m_initStage == FullyInitialized) {
199         if (QSettings *s = m_core->settings()) {
200             m_core->settings()->beginGroup(settingsGroup);
201             m_editorWidget->saveSettings(s);
202             s->endGroup();
203         }
204
205         m_designMode->unregisterDesignWidget(m_modeWidget);
206         delete m_modeWidget;
207         m_modeWidget = 0;
208     }
209
210     delete m_formeditor;
211     foreach (SettingsPage *settingsPage, m_settingsPages) {
212         ExtensionSystem::PluginManager::instance()->removeObject(settingsPage);
213         delete settingsPage;
214     }
215     delete m_integration;
216
217     m_self = 0;
218 }
219
220 // Add an actioon to toggle the view state of a dock window
221 void FormEditorW::addDockViewAction(Core::ActionManager *am,
222                                     Core::ActionContainer *viewMenu,
223                                     int index, const Core::Context &context,
224                                     const QString &title, const QString &id)
225 {
226     if (const QDockWidget *dw = m_editorWidget->designerDockWidgets()[index]) {
227         QAction *action = dw->toggleViewAction();
228         action->setText(title);
229         Core::Command *cmd = addToolAction(action, am, context, id, viewMenu, QString());
230         cmd->setAttribute(Core::Command::CA_Hide);
231     }
232 }
233
234 void FormEditorW::setupViewActions()
235 {
236     // Populate "View" menu of form editor menu
237     Core::ActionManager *am = m_core->actionManager();
238     Core::ActionContainer *viewMenu = am->actionContainer(QLatin1String(Core::Constants::M_WINDOW_VIEWS));
239     QTC_ASSERT(viewMenu, return)
240
241     addDockViewAction(am, viewMenu, WidgetBoxSubWindow, m_contexts,
242                       tr("Widget box"), QLatin1String("FormEditor.WidgetBox"));
243
244     addDockViewAction(am, viewMenu, ObjectInspectorSubWindow, m_contexts,
245                       tr("Object Inspector"), QLatin1String("FormEditor.ObjectInspector"));
246
247     addDockViewAction(am, viewMenu, PropertyEditorSubWindow, m_contexts,
248                       tr("Property Editor"), QLatin1String("FormEditor.PropertyEditor"));
249
250     addDockViewAction(am, viewMenu, SignalSlotEditorSubWindow, m_contexts,
251                       tr("Signals && Slots Editor"), QLatin1String("FormEditor.SignalsAndSlotsEditor"));
252
253     addDockViewAction(am, viewMenu, ActionEditorSubWindow, m_contexts,
254                       tr("Action Editor"), QLatin1String("FormEditor.ActionEditor"));
255     // Lock/Reset
256     Core::Command *cmd = addToolAction(m_editorWidget->menuSeparator1(), am, m_contexts, QLatin1String("FormEditor.SeparatorLock"), viewMenu, QString());
257     cmd->setAttribute(Core::Command::CA_Hide);
258
259     cmd = addToolAction(m_editorWidget->toggleLockedAction(), am, m_contexts, QLatin1String("FormEditor.Locked"), viewMenu, QString());
260     cmd->setAttribute(Core::Command::CA_Hide);
261
262     cmd = addToolAction(m_editorWidget->menuSeparator2(), am, m_contexts, QLatin1String("FormEditor.SeparatorReset"), viewMenu, QString());
263     cmd->setAttribute(Core::Command::CA_Hide);
264
265     cmd = addToolAction(m_editorWidget->resetLayoutAction(), am, m_contexts, QLatin1String("FormEditor.ResetToDefaultLayout"), viewMenu, QString());
266     connect(m_editorWidget, SIGNAL(resetLayout()), m_editorWidget, SLOT(resetToDefaultLayout()));
267     cmd->setAttribute(Core::Command::CA_Hide);
268 }
269
270 void FormEditorW::fullInit()
271 {
272     QTC_ASSERT(m_initStage == RegisterPlugins, return);
273     QTime *initTime = 0;
274     if (Designer::Constants::Internal::debug) {
275         initTime = new QTime;
276         initTime->start();
277     }
278
279     QDesignerComponents::createTaskMenu(m_formeditor, parent());
280     QDesignerComponents::initializePlugins(designerEditor());
281     QDesignerComponents::initializeResources();
282     initDesignerSubWindows();
283     m_integration = new QtCreatorIntegration(m_formeditor, this);
284     m_formeditor->setIntegration(m_integration);
285     // Connect Qt Designer help request to HelpManager.
286     connect(m_integration, SIGNAL(creatorHelpRequested(QUrl)),
287         Core::HelpManager::instance(), SIGNAL(helpRequested(QUrl)));
288
289     /**
290      * This will initialize our TabOrder, Signals and slots and Buddy editors.
291      */
292     QList<QObject*> plugins = QPluginLoader::staticInstances();
293     plugins += m_formeditor->pluginManager()->instances();
294     foreach (QObject *plugin, plugins) {
295         if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
296             if (!formEditorPlugin->isInitialized())
297                 formEditorPlugin->initialize(m_formeditor);
298         }
299     }
300
301     if (m_actionAboutPlugins)
302         m_actionAboutPlugins->setEnabled(true);
303
304     if (Designer::Constants::Internal::debug) {
305         qDebug() << Q_FUNC_INFO << initTime->elapsed() << "ms";
306         delete initTime;
307     }
308
309     connect(m_core->editorManager()->instance(), SIGNAL(editorsClosed(QList<Core::IEditor*>)),
310             SLOT(closeFormEditorsForXmlEditors(QList<Core::IEditor*>)));
311     // Nest toolbar and editor widget
312     m_editorWidget = new EditorWidget(this);
313     QSettings *settings = m_core->settings();
314     settings->beginGroup(settingsGroup);
315     m_editorWidget->restoreSettings(settings);
316     settings->endGroup();
317
318     m_editorToolBar = createEditorToolBar();
319     m_toolBar = Core::EditorManager::createToolBar();
320     m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone);
321     m_toolBar->setNavigationVisible(false);
322     m_toolBar->addCenterToolBar(m_editorToolBar);
323
324     m_designMode = ExtensionSystem::PluginManager::instance()->getObject<Core::DesignMode>();
325     m_modeWidget = new QWidget;
326     m_modeWidget->setObjectName(QLatin1String("DesignerModeWidget"));
327     QVBoxLayout *layout = new QVBoxLayout;
328     layout->setMargin(0);
329     layout->setSpacing(0);
330     layout->addWidget(m_toolBar);
331     layout->addWidget(m_editorWidget);
332     m_modeWidget->setLayout(layout);
333
334     Core::UniqueIDManager *idMan = Core::UniqueIDManager::instance();
335     int editorManagerContext = idMan->uniqueIdentifier(QLatin1String(Core::Constants::C_EDITORMANAGER));
336
337     Core::Context designerContexts = m_contexts;
338     designerContexts.append(Core::Context(editorManagerContext));
339     m_context = new DesignerContext(designerContexts, m_modeWidget, this);
340     m_core->addContextObject(m_context);
341
342     m_designMode->registerDesignWidget(m_modeWidget, QStringList(QLatin1String(FORM_MIMETYPE)), m_contexts);
343
344     setupViewActions();
345
346     m_initStage = FullyInitialized;
347 }
348
349 void FormEditorW::initDesignerSubWindows()
350 {
351     qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount, static_cast<QWidget*>(0));
352
353     QDesignerWidgetBoxInterface *wb = QDesignerComponents::createWidgetBox(m_formeditor, 0);
354     wb->setWindowTitle(tr("Widget Box"));
355     wb->setObjectName(QLatin1String("WidgetBox"));
356     m_formeditor->setWidgetBox(wb);
357     m_designerSubWindows[WidgetBoxSubWindow] = wb;
358
359     QDesignerObjectInspectorInterface *oi = QDesignerComponents::createObjectInspector(m_formeditor, 0);
360     oi->setWindowTitle(tr("Object Inspector"));
361     oi->setObjectName(QLatin1String("ObjectInspector"));
362     m_formeditor->setObjectInspector(oi);
363     m_designerSubWindows[ObjectInspectorSubWindow] = oi;
364
365     QDesignerPropertyEditorInterface *pe = QDesignerComponents::createPropertyEditor(m_formeditor, 0);
366     pe->setWindowTitle(tr("Property Editor"));
367     pe->setObjectName(QLatin1String("PropertyEditor"));
368     m_formeditor->setPropertyEditor(pe);
369     m_designerSubWindows[PropertyEditorSubWindow] = pe;
370
371     QWidget *se = QDesignerComponents::createSignalSlotEditor(m_formeditor, 0);
372     se->setWindowTitle(tr("Signals && Slots Editor"));
373     se->setObjectName(QLatin1String("SignalsAndSlotsEditor"));
374     m_designerSubWindows[SignalSlotEditorSubWindow] = se;
375
376     QDesignerActionEditorInterface *ae = QDesignerComponents::createActionEditor(m_formeditor, 0);
377     ae->setWindowTitle(tr("Action Editor"));
378     ae->setObjectName(QLatin1String("ActionEditor"));
379     m_formeditor->setActionEditor(ae);
380     m_designerSubWindows[ActionEditorSubWindow] = ae;
381 }
382
383 void FormEditorW::ensureInitStage(InitializationStage s)
384 {
385     if (Designer::Constants::Internal::debug)
386         qDebug() << Q_FUNC_INFO << s;
387     if (!m_self)
388         m_self = new FormEditorW;
389     if (m_self->m_initStage >= s)
390         return;
391     QApplication::setOverrideCursor(Qt::WaitCursor);
392     m_self->fullInit();
393     QApplication::restoreOverrideCursor();
394 }
395
396 FormEditorW *FormEditorW::instance()
397 {
398     ensureInitStage(FullyInitialized);
399     return m_self;
400 }
401
402 void FormEditorW::deleteInstance()
403 {
404     delete m_self;
405 }
406
407 void FormEditorW::setupActions()
408 {
409     Core::ActionManager *am = m_core->actionManager();
410     Core::Command *command;
411
412     //menus
413     Core::ActionContainer *medit =
414         am->actionContainer(Core::Constants::M_EDIT);
415     Core::ActionContainer *mtools =
416         am->actionContainer(Core::Constants::M_TOOLS);
417
418     Core::ActionContainer *mformtools =
419         am->createMenu(M_FORMEDITOR);
420     mformtools->menu()->setTitle(tr("For&m Editor"));
421     mtools->addMenu(mformtools);
422
423     //overridden actions
424     bindShortcut(am->registerAction(m_fwm->actionUndo(), Core::Constants::UNDO, m_contexts), m_fwm->actionUndo());
425     bindShortcut(am->registerAction(m_fwm->actionRedo(), Core::Constants::REDO, m_contexts), m_fwm->actionRedo());
426     bindShortcut(am->registerAction(m_fwm->actionCut(), Core::Constants::CUT, m_contexts), m_fwm->actionCut());
427     bindShortcut(am->registerAction(m_fwm->actionCopy(), Core::Constants::COPY, m_contexts), m_fwm->actionCopy());
428     bindShortcut(am->registerAction(m_fwm->actionPaste(), Core::Constants::PASTE, m_contexts), m_fwm->actionPaste());
429     bindShortcut(am->registerAction(m_fwm->actionSelectAll(), Core::Constants::SELECTALL, m_contexts), m_fwm->actionSelectAll());
430
431     m_actionPrint = new QAction(this);
432     bindShortcut(am->registerAction(m_actionPrint, Core::Constants::PRINT, m_contexts), m_actionPrint);
433     connect(m_actionPrint, SIGNAL(triggered()), this, SLOT(print()));
434
435     //'delete' action. Do not set a shortcut as Designer handles
436     // the 'Delete' key by event filter. Setting a shortcut triggers
437     // buggy behaviour on Mac (Pressing Delete in QLineEdit removing the widget).
438     command = am->registerAction(m_fwm->actionDelete(), QLatin1String("FormEditor.Edit.Delete"), m_contexts);
439     bindShortcut(command, m_fwm->actionDelete());
440     command->setAttribute(Core::Command::CA_Hide);
441     medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE);
442
443     m_actionGroupEditMode = new QActionGroup(this);
444     m_actionGroupEditMode->setExclusive(true);
445     connect(m_actionGroupEditMode, SIGNAL(triggered(QAction*)), this, SLOT(activateEditMode(QAction*)));
446
447     m_modeActionSeparator = new QAction(this);
448     m_modeActionSeparator->setSeparator(true);
449     command = am->registerAction(m_modeActionSeparator, QLatin1String("FormEditor.Sep.ModeActions"), m_contexts);
450     medit->addAction(command, Core::Constants::G_EDIT_OTHER);
451
452     m_toolActionIds.push_back(QLatin1String("FormEditor.WidgetEditor"));
453     createEditModeAction(m_actionGroupEditMode, m_contexts, am, medit,
454                          tr("Edit Widgets"), m_toolActionIds.back(),
455                          EditModeWidgetEditor, QLatin1String("widgettool.png"), tr("F3"));
456
457     m_toolActionIds.push_back(QLatin1String("FormEditor.SignalsSlotsEditor"));
458     createEditModeAction(m_actionGroupEditMode, m_contexts, am, medit,
459                          tr("Edit Signals/Slots"), m_toolActionIds.back(),
460                          EditModeSignalsSlotEditor, QLatin1String("signalslottool.png"), tr("F4"));
461
462     m_toolActionIds.push_back(QLatin1String("FormEditor.BuddyEditor"));
463     createEditModeAction(m_actionGroupEditMode, m_contexts, am, medit,
464                          tr("Edit Buddies"), m_toolActionIds.back(),
465                          EditModeBuddyEditor, QLatin1String("buddytool.png"));
466
467     m_toolActionIds.push_back(QLatin1String("FormEditor.TabOrderEditor"));
468     createEditModeAction(m_actionGroupEditMode, m_contexts, am, medit,
469                          tr("Edit Tab Order"),  m_toolActionIds.back(),
470                          EditModeTabOrderEditor, QLatin1String("tabordertool.png"));
471
472     //tool actions
473     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutHorizontally"));
474     const QString horizLayoutShortcut = osMac ? tr("Meta+H") : tr("Ctrl+H");
475     addToolAction(m_fwm->actionHorizontalLayout(), am, m_contexts,
476                   m_toolActionIds.back(), mformtools, horizLayoutShortcut);
477
478     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutVertically"));
479     const QString vertLayoutShortcut = osMac ? tr("Meta+L") : tr("Ctrl+L");
480     addToolAction(m_fwm->actionVerticalLayout(), am, m_contexts,
481                   m_toolActionIds.back(),  mformtools, vertLayoutShortcut);
482
483     m_toolActionIds.push_back(QLatin1String("FormEditor.SplitHorizontal"));
484     addToolAction(m_fwm->actionSplitHorizontal(), am, m_contexts,
485                   m_toolActionIds.back(), mformtools);
486
487     m_toolActionIds.push_back(QLatin1String("FormEditor.SplitVertical"));
488     addToolAction(m_fwm->actionSplitVertical(), am, m_contexts,
489                   m_toolActionIds.back(), mformtools);
490
491     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutForm"));
492     addToolAction(m_fwm->actionFormLayout(), am, m_contexts,
493                   m_toolActionIds.back(),  mformtools);
494
495     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutGrid"));
496     const QString gridShortcut = osMac ? tr("Meta+G") : tr("Ctrl+G");
497     addToolAction(m_fwm->actionGridLayout(), am, m_contexts,
498                   m_toolActionIds.back(),  mformtools, gridShortcut);
499
500     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutBreak"));
501     addToolAction(m_fwm->actionBreakLayout(), am, m_contexts,
502                   m_toolActionIds.back(), mformtools);
503
504     m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutAdjustSize"));
505     const QString adjustShortcut = osMac ? tr("Meta+J") : tr("Ctrl+J");
506     addToolAction(m_fwm->actionAdjustSize(), am, m_contexts,
507                   m_toolActionIds.back(),  mformtools, adjustShortcut);
508
509     m_toolActionIds.push_back(QLatin1String("FormEditor.SimplifyLayout"));
510     addToolAction(m_fwm->actionSimplifyLayout(), am, m_contexts,
511                   m_toolActionIds.back(),  mformtools);
512
513     createSeparator(this, am, m_contexts, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator1"));
514
515     addToolAction(m_fwm->actionLower(), am, m_contexts,
516                   QLatin1String("FormEditor.Lower"), mformtools);
517
518     addToolAction(m_fwm->actionRaise(), am, m_contexts,
519                   QLatin1String("FormEditor.Raise"), mformtools);
520
521     // Commands that do not go into the editor toolbar
522     createSeparator(this, am, m_contexts, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator2"));
523
524     m_actionPreview = m_fwm->actionDefaultPreview();
525     QTC_ASSERT(m_actionPreview, return);
526     addToolAction(m_actionPreview,  am,  m_contexts,
527                    QLatin1String("FormEditor.Preview"), mformtools, tr("Ctrl+Alt+R"));
528
529     // Preview in style...
530     m_actionGroupPreviewInStyle = m_fwm->actionGroupPreviewInStyle();
531     mformtools->addMenu(createPreviewStyleMenu(am, m_actionGroupPreviewInStyle));
532
533     // Form settings
534     createSeparator(this, am, m_contexts,  medit, QLatin1String("FormEditor.Edit.Separator2"), Core::Constants::G_EDIT_OTHER);
535
536     createSeparator(this, am, m_contexts, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator3"));
537     QAction *actionFormSettings = m_fwm->actionShowFormWindowSettingsDialog();
538     addToolAction(actionFormSettings, am, m_contexts, QLatin1String("FormEditor.FormSettings"), mformtools);
539
540     createSeparator(this, am, m_contexts, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator4"));
541     m_actionAboutPlugins = new QAction(tr("About Qt Designer plugins...."), this);
542     addToolAction(m_actionAboutPlugins,  am,  m_contexts,
543                    QLatin1String("FormEditor.AboutPlugins"), mformtools);
544     connect(m_actionAboutPlugins,  SIGNAL(triggered()), m_fwm, SLOT(aboutPlugins()));
545     m_actionAboutPlugins->setEnabled(false);
546
547     // FWM
548     connect(m_fwm, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface *)), this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface *)));
549 }
550
551 QToolBar *FormEditorW::createEditorToolBar() const
552 {
553     QToolBar *editorToolBar = new QToolBar;
554     Core::ActionManager *am = m_core->actionManager();
555     const QStringList::const_iterator cend = m_toolActionIds.constEnd();
556     for (QStringList::const_iterator it = m_toolActionIds.constBegin(); it != cend; ++it) {
557         Core::Command *cmd = am->command(*it);
558         QTC_ASSERT(cmd, continue);
559         QAction *action = cmd->action();
560         if (!action->icon().isNull()) // Simplify grid has no action yet
561             editorToolBar->addAction(action);
562     }
563     const int size = editorToolBar->style()->pixelMetric(QStyle::PM_SmallIconSize);
564     editorToolBar->setIconSize(QSize(size, size));
565     editorToolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
566     return editorToolBar;
567 }
568
569 Core::ActionContainer *FormEditorW::createPreviewStyleMenu(Core::ActionManager *am,
570                                                             QActionGroup *actionGroup)
571 {
572     const QString menuId = QLatin1String(M_FORMEDITOR_PREVIEW);
573     Core::ActionContainer *menuPreviewStyle = am->createMenu(menuId);
574     menuPreviewStyle->menu()->setTitle(tr("Preview in"));
575
576     // The preview menu is a list of invisible actions for the embedded design
577     // device profiles (integer data) followed by a separator and the styles
578     // (string data). Make device profiles update their text and hide them
579     // in the configuration dialog.
580     const QList<QAction*> actions = actionGroup->actions();
581
582     const QString deviceProfilePrefix = QLatin1String("DeviceProfile");
583     const QChar dot = QLatin1Char('.');
584
585     foreach (QAction* a, actions) {
586         QString name = menuId;
587         name += dot;
588         const QVariant data = a->data();
589         const bool isDeviceProfile = data.type() == QVariant::Int;
590         if (isDeviceProfile) {
591             name += deviceProfilePrefix;
592             name += dot;
593         }
594         name += data.toString();
595         Core::Command *command = am->registerAction(a, name, m_contexts);
596         bindShortcut(command, a);
597         if (isDeviceProfile) {
598             command->setAttribute(Core::Command::CA_UpdateText);
599             command->setAttribute(Core::Command::CA_NonConfigureable);
600         }
601         menuPreviewStyle->addAction(command);
602     }
603     return menuPreviewStyle;
604 }
605
606 void FormEditorW::saveSettings(QSettings *s)
607 {
608     s->beginGroup(settingsGroup);
609     m_editorWidget->saveSettings(s);
610     s->endGroup();
611 }
612
613 void FormEditorW::critical(const QString &errorMessage)
614 {
615     QMessageBox::critical(m_core->mainWindow(), tr("Designer"),  errorMessage);
616 }
617
618 // Apply the command shortcut to the action and connects to the command's keySequenceChanged signal
619 void FormEditorW::bindShortcut(Core::Command *command, QAction *action)
620 {
621     m_commandToDesignerAction.insert(command, action);
622     connect(command, SIGNAL(keySequenceChanged()),
623             m_shortcutMapper, SLOT(map()));
624     m_shortcutMapper->setMapping(command, command);
625     updateShortcut(command);
626 }
627
628 // Create an action to activate a designer tool
629 QAction *FormEditorW::createEditModeAction(QActionGroup *ag,
630                                      const Core::Context &context,
631                                      Core::ActionManager *am,
632                                      Core::ActionContainer *medit,
633                                      const QString &actionName,
634                                      const QString &name,
635                                      int toolNumber,
636                                      const QString &iconName,
637                                      const QString &keySequence)
638 {
639     QAction *rc = new QAction(actionName, ag);
640     rc->setCheckable(true);
641     if (!iconName.isEmpty())
642          rc->setIcon(designerIcon(iconName));
643     Core::Command *command = am->registerAction(rc, name, context);
644     command->setAttribute(Core::Command::CA_Hide);
645     if (!keySequence.isEmpty())
646         command->setDefaultKeySequence(QKeySequence(keySequence));
647     bindShortcut(command, rc);
648     medit->addAction(command, Core::Constants::G_EDIT_OTHER);
649     rc->setData(toolNumber);
650     ag->addAction(rc);
651     return rc;
652 }
653
654 // Create a tool action
655 Core::Command *FormEditorW::addToolAction(QAction *a, Core::ActionManager *am,
656                                           const Core::Context &context, const QString &name,
657                                           Core::ActionContainer *c1, const QString &keySequence)
658 {
659     Core::Command *command = am->registerAction(a, name, context);
660     if (!keySequence.isEmpty())
661         command->setDefaultKeySequence(QKeySequence(keySequence));
662     if (!a->isSeparator())
663         bindShortcut(command, a);
664     c1->addAction(command);
665     return command;
666 }
667
668 EditorData FormEditorW::createEditor(QWidget *parent)
669 {
670     if (Designer::Constants::Internal::debug)
671         qDebug() << "FormEditorW::createEditor";
672     // Create and associate form and text editor.
673     EditorData data;
674     m_fwm->closeAllPreviews();
675     qdesigner_internal::FormWindowBase *form = qobject_cast<qdesigner_internal::FormWindowBase *>(m_fwm->createFormWindow(0));
676     QTC_ASSERT(form, return data);
677     connect(form, SIGNAL(toolChanged(int)), this, SLOT(toolChanged(int)));
678     ResourceHandler *resourceHandler = new ResourceHandler(form);
679     form->setDesignerGrid(qdesigner_internal::FormWindowBase::defaultDesignerGrid());
680     qdesigner_internal::FormWindowBase::setupDefaultAction(form);
681     data.widgetHost = new SharedTools::WidgetHost( /* parent */ 0, form);
682     DesignerXmlEditor *xmlEditor = new DesignerXmlEditor(form, parent);
683     TextEditor::TextEditorSettings::instance()->initializeEditor(xmlEditor);
684     data.formWindowEditor = xmlEditor->designerEditor();
685     connect(data.widgetHost, SIGNAL(formWindowSizeChanged(int,int)),
686             xmlEditor, SIGNAL(changed()));
687     connect(data.formWindowEditor->file(), SIGNAL(changed()),
688             resourceHandler, SLOT(updateResources()));
689     m_editorWidget->add(data);
690
691     m_toolBar->addEditor(xmlEditor->editableInterface());
692
693     return data;
694 }
695
696 void FormEditorW::updateShortcut(QObject *command)
697 {
698     Core::Command *c = qobject_cast<Core::Command *>(command);
699     if (!c)
700         return;
701     QAction *a = m_commandToDesignerAction.value(c);
702     if (!a)
703         return;
704     a->setShortcut(c->action()->shortcut());
705 }
706
707 void FormEditorW::currentEditorChanged(Core::IEditor *editor)
708 {
709     if (Designer::Constants::Internal::debug)
710         qDebug() << Q_FUNC_INFO << editor << " of " << m_fwm->formWindowCount();
711
712     if (editor && editor->id() == QLatin1String(Constants::K_DESIGNER_XML_EDITOR_ID)) {
713         FormWindowEditor *xmlEditor = qobject_cast<FormWindowEditor *>(editor);
714         QTC_ASSERT(xmlEditor, return);
715         ensureInitStage(FullyInitialized);
716         SharedTools::WidgetHost *fw = m_editorWidget->formWindowEditorForXmlEditor(xmlEditor);
717         QTC_ASSERT(fw, return)
718         m_editorWidget->setVisibleEditor(xmlEditor);
719         m_fwm->setActiveFormWindow(fw->formWindow());
720     }
721 }
722
723 void FormEditorW::activeFormWindowChanged(QDesignerFormWindowInterface *afw)
724 {
725     if (Designer::Constants::Internal::debug)
726         qDebug() << Q_FUNC_INFO << afw << " of " << m_fwm->formWindowCount();
727
728     m_fwm->closeAllPreviews();
729     m_actionPreview->setEnabled(afw != 0);
730     m_actionGroupPreviewInStyle->setEnabled(afw != 0);
731 }
732
733 EditorData FormEditorW::activeEditor() const
734 {
735     if (m_editorWidget)
736         return m_editorWidget->activeEditor();
737     return EditorData();
738 }
739
740 void FormEditorW::activateEditMode(int id)
741 {
742     if (const int count = m_fwm->formWindowCount())
743         for (int i = 0; i <  count; i++)
744              m_fwm->formWindow(i)->setCurrentTool(id);
745 }
746
747 void FormEditorW::activateEditMode(QAction* a)
748 {
749     activateEditMode(a->data().toInt());
750 }
751
752 void FormEditorW::toolChanged(int t)
753 {
754     typedef QList<QAction *> ActionList;
755     if (const QAction *currentAction = m_actionGroupEditMode->checkedAction())
756         if (currentAction->data().toInt() == t)
757             return;
758     const ActionList actions = m_actionGroupEditMode->actions();
759     const ActionList::const_iterator cend = actions.constEnd();
760     for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
761         if ( (*it)->data().toInt() == t) {
762             (*it)->setChecked(true);
763             break;
764         }
765 }
766
767 void FormEditorW::closeFormEditorsForXmlEditors(QList<Core::IEditor*> editors)
768 {
769     foreach(Core::IEditor *editor, editors) {
770         m_editorWidget->removeFormWindowEditor(editor);
771     }
772 }
773
774 void FormEditorW::print()
775 {
776     // Printing code courtesy of designer_actions.cpp
777     QDesignerFormWindowInterface *fw = m_fwm->activeFormWindow();
778     if (!fw)
779         return;
780
781     const bool oldFullPage =  m_core->printer()->fullPage();
782     const QPrinter::Orientation oldOrientation =  m_core->printer()->orientation ();
783     m_core->printer()->setFullPage(false);
784     do {
785
786         // Grab the image to be able to a suggest suitable orientation
787         QString errorMessage;
788         const QPixmap pixmap = m_fwm->createPreviewPixmap(&errorMessage);
789         if (pixmap.isNull()) {
790             critical(tr("The image could not be created: %1").arg(errorMessage));
791             break;
792         }
793
794         const QSizeF pixmapSize = pixmap.size();
795         m_core->printer()->setOrientation( pixmapSize.width() > pixmapSize.height() ?  QPrinter::Landscape :  QPrinter::Portrait);
796
797         // Printer parameters
798         QPrintDialog dialog(m_core->printer(), fw);
799         if (!dialog.exec())
800            break;
801
802         const QCursor oldCursor = m_core->mainWindow()->cursor();
803         m_core->mainWindow()->setCursor(Qt::WaitCursor);
804         // Estimate of required scaling to make form look the same on screen and printer.
805         const double suggestedScaling = static_cast<double>(m_core->printer()->physicalDpiX()) /  static_cast<double>(fw->physicalDpiX());
806
807         QPainter painter(m_core->printer());
808         painter.setRenderHint(QPainter::SmoothPixmapTransform);
809
810         // Clamp to page
811         const QRectF page =  painter.viewport();
812         const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height());
813         const double scaling = qMin(suggestedScaling, maxScaling);
814
815         const double xOffset = page.left() + qMax(0.0, (page.size().width()  - scaling * pixmapSize.width())  / 2.0);
816         const double yOffset = page.top()  + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0);
817
818         // Draw.
819         painter.translate(xOffset, yOffset);
820         painter.scale(scaling, scaling);
821         painter.drawPixmap(0, 0, pixmap);
822         m_core->mainWindow()->setCursor(oldCursor);
823
824     } while (false);
825     m_core->printer()->setFullPage(oldFullPage);
826     m_core->printer()->setOrientation(oldOrientation);
827 }
828
829 } // namespace Internal
830 } // namespace Designer