OSDN Git Service

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