formeditorw.cpp 32.4 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** 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
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30 31 32
#include "formeditorw.h"
#include "formwindoweditor.h"
#include "designerconstants.h"
33
#include "faketoolbar.h"
con's avatar
con committed
34 35 36
#include "settingsmanager.h"
#include "settingspage.h"
#include "editorwidget.h"
37
#include "editordata.h"
38
#include "qtcreatorintegration.h"
Lasse Holmstedt's avatar
Lasse Holmstedt committed
39 40
#include "designerxmleditor.h"
#include "designercontext.h"
41
#include "editorwidget.h"
con's avatar
con committed
42

Lasse Holmstedt's avatar
Lasse Holmstedt committed
43 44
#include <coreplugin/modemanager.h>
#include <coreplugin/designmode.h>
con's avatar
con committed
45
#include <coreplugin/coreconstants.h>
46
#include <coreplugin/icore.h>
con's avatar
con committed
47
#include <coreplugin/uniqueidmanager.h>
48
#include <coreplugin/actionmanager/actionmanager.h>
con's avatar
con committed
49
#include <coreplugin/editormanager/editormanager.h>
50
#include <texteditor/texteditorsettings.h>
51
#include <extensionsystem/pluginmanager.h>
hjk's avatar
hjk committed
52
#include <utils/qtcassert.h>
con's avatar
con committed
53 54

#include <QtDesigner/QDesignerFormEditorPluginInterface>
Roberto Raggi's avatar
Roberto Raggi committed
55
#include "qt_private/pluginmanager_p.h"
con's avatar
con committed
56

Roberto Raggi's avatar
Roberto Raggi committed
57 58 59
#include "qt_private/iconloader_p.h"  // createIconSet
#include "qt_private/qdesigner_formwindowmanager_p.h"
#include "qt_private/formwindowbase_p.h"
con's avatar
con committed
60 61 62 63 64 65 66
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerComponents>

#include <QtDesigner/QDesignerWidgetBoxInterface>
#include <QtDesigner/abstractobjectinspector.h>
#include <QtDesigner/QDesignerPropertyEditorInterface>
#include <QtDesigner/QDesignerActionEditorInterface>
67
#include <QtDesigner/QDesignerFormEditorInterface>
con's avatar
con committed
68 69 70 71 72

#include <QtGui/QAction>
#include <QtGui/QActionGroup>
#include <QtGui/QApplication>
#include <QtGui/QCursor>
con's avatar
con committed
73
#include <QtGui/QDockWidget>
con's avatar
con committed
74 75 76 77 78 79 80 81 82
#include <QtGui/QMenu>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QKeySequence>
#include <QtGui/QPrintDialog>
#include <QtGui/QPrinter>
#include <QtGui/QPainter>
#include <QtGui/QStyle>
#include <QtGui/QToolBar>
83
#include <QtGui/QVBoxLayout>
con's avatar
con committed
84 85 86

#include <QtCore/QDebug>
#include <QtCore/QSettings>
87 88 89
#include <QtCore/QSignalMapper>
#include <QtCore/QPluginLoader>
#include <QtCore/QTime>
con's avatar
con committed
90

91
static const char settingsGroup[] = "Designer";
con's avatar
con committed
92

93 94 95 96 97 98 99 100
#ifdef Q_OS_MAC
    enum { osMac = 1 };
#else
    enum { osMac = 0 };
#endif

/* Actions of the designer plugin:
 * Designer provides a toolbar which is subject to a context change (to
Tobias Hunger's avatar
Tobias Hunger committed
101
 * "edit mode" context) when it is focused.
102 103 104 105 106
 * In order to prevent its actions from being disabled/hidden by that context
 * change, the actions are registered on the global context. In currentEditorChanged(),
 * the ones that are present in the global edit menu are set visible/invisible manually.
 * The designer context is currently used for Cut/Copy/Paste, etc. */

con's avatar
con committed
107 108 109 110 111 112 113 114
static inline QIcon designerIcon(const QString &iconName)
{
    const QIcon icon = qdesigner_internal::createIconSet(iconName);
    if (icon.isNull())
        qWarning() << "Unable to locate " << iconName;
    return icon;
}

115 116
// Create a menu separator
static inline QAction *createSeparator(QObject *parent,
117
                                 Core::ActionManager *am,
con's avatar
con committed
118
                                 const QList<int> &context,
119
                                 Core::ActionContainer *container,
con's avatar
con committed
120 121 122 123 124
                                 const QString &name = QString(),
                                 const QString &group = QString())
{
    QAction *actSeparator = new QAction(parent);
    actSeparator->setSeparator(true);
con's avatar
con committed
125
    Core::Command *command = am->registerAction(actSeparator, name, context);
con's avatar
con committed
126 127 128 129 130 131
    container->addAction(command, group);
    return actSeparator;
}

using namespace Designer::Constants;

132 133
namespace Designer {
namespace Internal {
con's avatar
con committed
134 135 136

// --------- FormEditorW

con's avatar
con committed
137 138 139 140 141 142
FormEditorW *FormEditorW::m_self = 0;

FormEditorW::FormEditorW() :
    m_formeditor(QDesignerComponents::createFormEditor(0)),
    m_integration(0),
    m_fwm(0),
143
    m_core(Core::ICore::instance()),
con's avatar
con committed
144
    m_initStage(RegisterPlugins),
145
    m_viewMenu(0),
con's avatar
con committed
146
    m_actionGroupEditMode(0),
147 148 149
    m_actionPrint(0),
    m_actionPreview(0),
    m_actionGroupPreviewInStyle(0),
150
    m_actionAboutPlugins(0),
Lasse Holmstedt's avatar
Lasse Holmstedt committed
151 152
    m_shortcutMapper(new QSignalMapper(this)),
    m_context(0),
153 154
    m_modeWidget(0),
    m_editorWidget(0),
Lasse Holmstedt's avatar
Lasse Holmstedt committed
155
    m_designMode(0)
con's avatar
con committed
156
{
157
    if (Designer::Constants::Internal::debug)
con's avatar
con committed
158
        qDebug() << Q_FUNC_INFO;
hjk's avatar
hjk committed
159
    QTC_ASSERT(!m_self, return);
con's avatar
con committed
160
    m_self = this;
hjk's avatar
hjk committed
161
    QTC_ASSERT(m_core, return);
con's avatar
con committed
162 163 164 165 166 167 168 169

    qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount,
          static_cast<QWidget *>(0));

    m_formeditor->setTopLevel(qobject_cast<QWidget *>(m_core->editorManager()));
    m_formeditor->setSettingsManager(new SettingsManager());

    m_fwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager*>(m_formeditor->formWindowManager());
hjk's avatar
hjk committed
170
    QTC_ASSERT(m_fwm, return);
con's avatar
con committed
171

172 173 174 175 176
    Core::UniqueIDManager *idMan = Core::UniqueIDManager::instance();
    m_contexts << idMan->uniqueIdentifier(QLatin1String(Designer::Constants::C_FORMEDITOR))
               << idMan->uniqueIdentifier(QLatin1String(Core::Constants::C_EDITORMANAGER))
               << idMan->uniqueIdentifier(QLatin1String(Core::Constants::C_DESIGN_MODE));

con's avatar
con committed
177 178 179 180 181 182 183 184 185 186
    setupActions();

    foreach (QDesignerOptionsPageInterface *designerPage, m_formeditor->optionsPages()) {
        SettingsPage *settingsPage = new SettingsPage(designerPage);
        ExtensionSystem::PluginManager::instance()->addObject(settingsPage);
        m_settingsPages.append(settingsPage);
    }

    connect(m_core->editorManager(), SIGNAL(currentEditorChanged(Core::IEditor *)),
            this, SLOT(currentEditorChanged(Core::IEditor *)));
187 188
    connect(m_shortcutMapper, SIGNAL(mapped(QObject *)),
            this, SLOT(updateShortcut(QObject *)));
con's avatar
con committed
189 190 191 192
}

FormEditorW::~FormEditorW()
{
193 194
    if (m_context)
        m_core->removeContextObject(m_context);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
195
    if (m_initStage == FullyInitialized) {
196 197 198 199 200
        if (QSettings *s = m_core->settings()) {
            m_core->settings()->beginGroup(settingsGroup);
            m_editorWidget->saveSettings(s);
            s->endGroup();
        }
Lasse Holmstedt's avatar
Lasse Holmstedt committed
201

202 203 204 205
        m_designMode->unregisterDesignWidget(m_modeWidget);
        delete m_modeWidget;
        m_modeWidget = 0;
    }
con's avatar
con committed
206 207 208 209 210 211

    delete m_formeditor;
    foreach (SettingsPage *settingsPage, m_settingsPages) {
        ExtensionSystem::PluginManager::instance()->removeObject(settingsPage);
        delete settingsPage;
    }
Lasse Holmstedt's avatar
Lasse Holmstedt committed
212 213
    delete m_integration;

214 215 216
    m_self = 0;
}

217
// Add an actioon to toggle the view state of a dock window
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
void FormEditorW::addDockViewAction(Core::ActionManager *am,
                                    int index, const QList<int> &context,
                                    const QString &title, const QString &id)
{
    if (const QDockWidget *dw = m_editorWidget->designerDockWidgets()[index]) {
        QAction *action = dw->toggleViewAction();
        action->setText(title);
        addToolAction(action, am, context, id, m_viewMenu, QString());
    }
}

void FormEditorW::setupViewActions()
{
    // Populate "View" menu of form editor menu
    Core::ActionManager *am = m_core->actionManager();
    QList<int> globalcontext;
    globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);

    addDockViewAction(am, WidgetBoxSubWindow, globalcontext,
                      tr("Widget box"), QLatin1String("FormEditor.WidgetBox"));
Lasse Holmstedt's avatar
Lasse Holmstedt committed
238

239 240
    addDockViewAction(am, ObjectInspectorSubWindow, globalcontext,
                      tr("Object Inspector"), QLatin1String("FormEditor.ObjectInspector"));
Lasse Holmstedt's avatar
Lasse Holmstedt committed
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    addDockViewAction(am, PropertyEditorSubWindow, globalcontext,
                      tr("Property Editor"), QLatin1String("FormEditor.PropertyEditor"));

    addDockViewAction(am, SignalSlotEditorSubWindow, globalcontext,
                      tr("Signals && Slots Editor"), QLatin1String("FormEditor.SignalsAndSlotsEditor"));

    addDockViewAction(am, ActionEditorSubWindow, globalcontext,
                      tr("Action Editor"), QLatin1String("FormEditor.ActionEditor"));

    createSeparator(this, am, globalcontext, m_viewMenu, QLatin1String("FormEditor.Menu.Tools.Views.SeparatorLock"));

    m_lockAction = new QAction(tr("Locked"), this);
    m_lockAction->setCheckable(true);
    addToolAction(m_lockAction, am, globalcontext, QLatin1String("FormEditor.Locked"), m_viewMenu, QString());
    connect(m_lockAction, SIGNAL(toggled(bool)), m_editorWidget, SLOT(setLocked(bool)));

    createSeparator(this, am, globalcontext, m_viewMenu, QLatin1String("FormEditor.Menu.Tools.Views.SeparatorReset"));

    m_resetLayoutAction = new QAction(tr("Reset to Default Layout"), this);
    m_lockAction->setChecked(m_editorWidget->isLocked());
    connect(m_resetLayoutAction, SIGNAL(triggered()), m_editorWidget, SLOT(resetToDefaultLayout()));
    addToolAction(m_resetLayoutAction, am, globalcontext, QLatin1String("FormEditor.ResetToDefaultLayout"), m_viewMenu, QString());
con's avatar
con committed
264 265 266 267
}

void FormEditorW::fullInit()
{
hjk's avatar
hjk committed
268
    QTC_ASSERT(m_initStage == RegisterPlugins, return);
con's avatar
con committed
269
    QTime *initTime = 0;
270
    if (Designer::Constants::Internal::debug) {
con's avatar
con committed
271 272 273 274 275 276 277 278
        initTime = new QTime;
        initTime->start();
    }

    QDesignerComponents::createTaskMenu(m_formeditor, parent());
    QDesignerComponents::initializePlugins(designerEditor());
    QDesignerComponents::initializeResources();
    initDesignerSubWindows();
279
    m_integration = new QtCreatorIntegration(m_formeditor, this);
con's avatar
con committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293
    m_formeditor->setIntegration(m_integration);

    /**
     * This will initialize our TabOrder, Signals and slots and Buddy editors.
     */
    QList<QObject*> plugins = QPluginLoader::staticInstances();
    plugins += m_formeditor->pluginManager()->instances();
    foreach (QObject *plugin, plugins) {
        if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) {
            if (!formEditorPlugin->isInitialized())
                formEditorPlugin->initialize(m_formeditor);
        }
    }

294 295 296
    if (m_actionAboutPlugins)
        m_actionAboutPlugins->setEnabled(true);

297
    if (Designer::Constants::Internal::debug) {
con's avatar
con committed
298 299 300
        qDebug() << Q_FUNC_INFO << initTime->elapsed() << "ms";
        delete initTime;
    }
301

Lasse Holmstedt's avatar
Lasse Holmstedt committed
302 303
    connect(m_core->editorManager()->instance(), SIGNAL(editorsClosed(QList<Core::IEditor*>)),
            SLOT(closeFormEditorsForXmlEditors(QList<Core::IEditor*>)));
304 305 306 307 308 309
    // Nest toolbar and editor widget
    m_editorWidget = new EditorWidget(this);
    QSettings *settings = m_core->settings();
    settings->beginGroup(settingsGroup);
    m_editorWidget->restoreSettings(settings);
    settings->endGroup();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
310 311

    m_designMode = ExtensionSystem::PluginManager::instance()->getObject<Core::DesignMode>();
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    m_modeWidget = new QWidget;
    m_modeWidget->setObjectName(QLatin1String("DesignerModeWidget"));
    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(0);
    layout->setSpacing(0);

    layout->addWidget(new FakeToolBar(createEditorToolBar()));
    layout->addWidget(m_editorWidget);
    m_modeWidget->setLayout(layout);

    m_context = new DesignerContext(m_contexts, m_modeWidget, this);
    m_core->addContextObject(m_context);

    m_designMode->registerDesignWidget(m_modeWidget, QStringList(QLatin1String(FORM_MIMETYPE)));

    setupViewActions();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
328

con's avatar
con committed
329 330 331 332 333 334 335 336
    m_initStage = FullyInitialized;
}

void FormEditorW::initDesignerSubWindows()
{
    qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount, static_cast<QWidget*>(0));

    QDesignerWidgetBoxInterface *wb = QDesignerComponents::createWidgetBox(m_formeditor, 0);
con's avatar
con committed
337
    wb->setWindowTitle(tr("Widget Box"));
con's avatar
con committed
338 339 340 341
    m_formeditor->setWidgetBox(wb);
    m_designerSubWindows[WidgetBoxSubWindow] = wb;

    QDesignerObjectInspectorInterface *oi = QDesignerComponents::createObjectInspector(m_formeditor, 0);
con's avatar
con committed
342
    oi->setWindowTitle(tr("Object Inspector"));
con's avatar
con committed
343 344 345 346
    m_formeditor->setObjectInspector(oi);
    m_designerSubWindows[ObjectInspectorSubWindow] = oi;

    QDesignerPropertyEditorInterface *pe = QDesignerComponents::createPropertyEditor(m_formeditor, 0);
con's avatar
con committed
347
    pe->setWindowTitle(tr("Property Editor"));
con's avatar
con committed
348 349 350 351
    m_formeditor->setPropertyEditor(pe);
    m_designerSubWindows[PropertyEditorSubWindow] = pe;

    QWidget *se = QDesignerComponents::createSignalSlotEditor(m_formeditor, 0);
con's avatar
con committed
352
    se->setWindowTitle(tr("Signals & Slots Editor"));
con's avatar
con committed
353 354 355
    m_designerSubWindows[SignalSlotEditorSubWindow] = se;

    QDesignerActionEditorInterface *ae = QDesignerComponents::createActionEditor(m_formeditor, 0);
con's avatar
con committed
356
    ae->setWindowTitle(tr("Action Editor"));
con's avatar
con committed
357 358 359 360 361 362
    m_formeditor->setActionEditor(ae);
    m_designerSubWindows[ActionEditorSubWindow] = ae;
}

void FormEditorW::ensureInitStage(InitializationStage s)
{
363
    if (Designer::Constants::Internal::debug)
con's avatar
con committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
        qDebug() << Q_FUNC_INFO << s;
    if (!m_self)
        m_self = new FormEditorW;
    if (m_self->m_initStage >= s)
        return;
    QApplication::setOverrideCursor(Qt::WaitCursor);
    m_self->fullInit();
    QApplication::restoreOverrideCursor();
}

FormEditorW *FormEditorW::instance()
{
    ensureInitStage(FullyInitialized);
    return m_self;
}

void FormEditorW::deleteInstance()
{
    delete m_self;
}

void FormEditorW::setupActions()
{
387
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
388
    Core::Command *command;
con's avatar
con committed
389 390

    //menus
391
    Core::ActionContainer *medit =
con's avatar
con committed
392
        am->actionContainer(Core::Constants::M_EDIT);
393
    Core::ActionContainer *mtools =
con's avatar
con committed
394 395
        am->actionContainer(Core::Constants::M_TOOLS);

396
    Core::ActionContainer *mformtools =
con's avatar
con committed
397
        am->createMenu(M_FORMEDITOR);
Friedemann Kleint's avatar
Friedemann Kleint committed
398
    mformtools->menu()->setTitle(tr("For&m Editor"));
con's avatar
con committed
399 400 401
    mtools->addMenu(mformtools);

    //overridden actions
402 403 404 405 406 407
    bindShortcut(am->registerAction(m_fwm->actionUndo(), Core::Constants::UNDO, m_contexts), m_fwm->actionUndo());
    bindShortcut(am->registerAction(m_fwm->actionRedo(), Core::Constants::REDO, m_contexts), m_fwm->actionRedo());
    bindShortcut(am->registerAction(m_fwm->actionCut(), Core::Constants::CUT, m_contexts), m_fwm->actionCut());
    bindShortcut(am->registerAction(m_fwm->actionCopy(), Core::Constants::COPY, m_contexts), m_fwm->actionCopy());
    bindShortcut(am->registerAction(m_fwm->actionPaste(), Core::Constants::PASTE, m_contexts), m_fwm->actionPaste());
    bindShortcut(am->registerAction(m_fwm->actionSelectAll(), Core::Constants::SELECTALL, m_contexts), m_fwm->actionSelectAll());
con's avatar
con committed
408 409

    m_actionPrint = new QAction(this);
410
    bindShortcut(am->registerAction(m_actionPrint, Core::Constants::PRINT, m_contexts), m_actionPrint);
con's avatar
con committed
411 412 413
    connect(m_actionPrint, SIGNAL(triggered()), this, SLOT(print()));

    //'delete' action
414
    command = am->registerAction(m_fwm->actionDelete(), QLatin1String("FormEditor.Edit.Delete"), m_contexts);
con's avatar
con committed
415
    command->setDefaultKeySequence(QKeySequence::Delete);
416
    bindShortcut(command, m_fwm->actionDelete());
con's avatar
con committed
417
    command->setAttribute(Core::Command::CA_Hide);
con's avatar
con committed
418 419
    medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

420 421 422
    QList<int> globalcontext;
    globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);

con's avatar
con committed
423 424 425 426
    m_actionGroupEditMode = new QActionGroup(this);
    m_actionGroupEditMode->setExclusive(true);
    connect(m_actionGroupEditMode, SIGNAL(triggered(QAction*)), this, SLOT(activateEditMode(QAction*)));

con's avatar
con committed
427 428 429 430 431
    m_modeActionSeparator = new QAction(this);
    m_modeActionSeparator->setSeparator(true);
    command = am->registerAction(m_modeActionSeparator, QLatin1String("FormEditor.Sep.ModeActions"), globalcontext);
    medit->addAction(command, Core::Constants::G_EDIT_OTHER);

con's avatar
con committed
432
    m_toolActionIds.push_back(QLatin1String("FormEditor.WidgetEditor"));
433
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
434
                         tr("Edit widgets"), m_toolActionIds.back(),
con's avatar
con committed
435 436 437
                         EditModeWidgetEditor, QLatin1String("widgettool.png"), tr("F3"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.SignalsSlotsEditor"));
438
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
439
                         tr("Edit signals/slots"), m_toolActionIds.back(),
con's avatar
con committed
440 441 442
                         EditModeSignalsSlotEditor, QLatin1String("signalslottool.png"), tr("F4"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.BuddyEditor"));
443
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
444
                         tr("Edit buddies"), m_toolActionIds.back(),
con's avatar
con committed
445 446 447
                         EditModeBuddyEditor, QLatin1String("buddytool.png"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.TabOrderEditor"));
448
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
449
                         tr("Edit tab order"),  m_toolActionIds.back(),
con's avatar
con committed
450 451 452 453
                         EditModeTabOrderEditor, QLatin1String("tabordertool.png"));

    //tool actions
    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutHorizontally"));
454 455 456 457
    const QString horizLayoutShortcut = osMac ? tr("Meta+H") : tr("Ctrl+H");
    addToolAction(m_fwm->actionHorizontalLayout(), am, globalcontext,
                  m_toolActionIds.back(), mformtools, horizLayoutShortcut);

con's avatar
con committed
458
    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutVertically"));
459 460 461
    const QString vertLayoutShortcut = osMac ? tr("Meta+L") : tr("Ctrl+L");
    addToolAction(m_fwm->actionVerticalLayout(), am, globalcontext,
                  m_toolActionIds.back(),  mformtools, vertLayoutShortcut);
con's avatar
con committed
462 463

    m_toolActionIds.push_back(QLatin1String("FormEditor.SplitHorizontal"));
464
    addToolAction(m_fwm->actionSplitHorizontal(), am, globalcontext,
con's avatar
con committed
465 466 467
                  m_toolActionIds.back(), mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.SplitVertical"));
468
    addToolAction(m_fwm->actionSplitVertical(), am, globalcontext,
con's avatar
con committed
469 470 471
                  m_toolActionIds.back(), mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutForm"));
472
    addToolAction(m_fwm->actionFormLayout(), am, globalcontext,
con's avatar
con committed
473 474 475
                  m_toolActionIds.back(),  mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutGrid"));
476 477 478
    const QString gridShortcut = osMac ? tr("Meta+G") : tr("Ctrl+G");
    addToolAction(m_fwm->actionGridLayout(), am, globalcontext,
                  m_toolActionIds.back(),  mformtools, gridShortcut);
con's avatar
con committed
479 480

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutBreak"));
481
    addToolAction(m_fwm->actionBreakLayout(), am, globalcontext,
con's avatar
con committed
482 483 484
                  m_toolActionIds.back(), mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutAdjustSize"));
485 486 487
    const QString adjustShortcut = osMac ? tr("Meta+J") : tr("Ctrl+J");
    addToolAction(m_fwm->actionAdjustSize(), am, globalcontext,
                  m_toolActionIds.back(),  mformtools, adjustShortcut);
con's avatar
con committed
488 489

    m_toolActionIds.push_back(QLatin1String("FormEditor.SimplifyLayout"));
490
    addToolAction(m_fwm->actionSimplifyLayout(), am, globalcontext,
con's avatar
con committed
491 492
                  m_toolActionIds.back(),  mformtools);

493
    createSeparator(this, am, m_contexts, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator1"));
con's avatar
con committed
494

495
    addToolAction(m_fwm->actionLower(), am, globalcontext,
con's avatar
con committed
496 497
                  QLatin1String("FormEditor.Lower"), mformtools);

498
    addToolAction(m_fwm->actionRaise(), am, globalcontext,
con's avatar
con committed
499 500 501
                  QLatin1String("FormEditor.Raise"), mformtools);

    // Commands that do not go into the editor toolbar
502
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator2"));
con's avatar
con committed
503 504

    m_actionPreview = m_fwm->actionDefaultPreview();
hjk's avatar
hjk committed
505
    QTC_ASSERT(m_actionPreview, return);
506
    addToolAction(m_actionPreview,  am,  globalcontext,
con's avatar
con committed
507 508 509 510 511 512 513
                   QLatin1String("FormEditor.Preview"), mformtools, tr("Ctrl+Alt+R"));

    // Preview in style...
    m_actionGroupPreviewInStyle = m_fwm->actionGroupPreviewInStyle();
    mformtools->addMenu(createPreviewStyleMenu(am, m_actionGroupPreviewInStyle));

    // Form settings
514
    createSeparator(this, am, m_contexts,  medit, QLatin1String("FormEditor.Edit.Separator2"), Core::Constants::G_EDIT_OTHER);
con's avatar
con committed
515

516
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator3"));
con's avatar
con committed
517
    QAction *actionFormSettings = m_fwm->actionShowFormWindowSettingsDialog();
518 519
    addToolAction(actionFormSettings, am, globalcontext, QLatin1String("FormEditor.FormSettings"), mformtools);

520 521 522 523 524 525 526
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator4"));
    m_actionAboutPlugins = new QAction(tr("About Qt Designer plugins...."), this);
    addToolAction(m_actionAboutPlugins,  am,  globalcontext,
                   QLatin1String("FormEditor.AboutPlugins"), mformtools);
    connect(m_actionAboutPlugins,  SIGNAL(triggered()), m_fwm, SLOT(aboutPlugins()));
    m_actionAboutPlugins->setEnabled(false);

527 528 529 530 531 532 533
    // Views. Populated later on.
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.SeparatorViews"));

    m_viewMenu = am->createMenu(QLatin1String(M_FORMEDITOR_VIEWS));
    m_viewMenu->menu()->setTitle(tr("Views"));
    mformtools->addMenu(m_viewMenu);

con's avatar
con committed
534 535 536 537 538 539
    // FWM
    connect(m_fwm, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface *)), this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface *)));
}

QToolBar *FormEditorW::createEditorToolBar() const
{
540
    QToolBar *editorToolBar = new QToolBar;
541
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
542 543
    const QStringList::const_iterator cend = m_toolActionIds.constEnd();
    for (QStringList::const_iterator it = m_toolActionIds.constBegin(); it != cend; ++it) {
con's avatar
con committed
544
        Core::Command *cmd = am->command(*it);
hjk's avatar
hjk committed
545
        QTC_ASSERT(cmd, continue);
con's avatar
con committed
546 547
        QAction *action = cmd->action();
        if (!action->icon().isNull()) // Simplify grid has no action yet
548
            editorToolBar->addAction(action);
con's avatar
con committed
549
    }
550 551 552 553
    const int size = editorToolBar->style()->pixelMetric(QStyle::PM_SmallIconSize);
    editorToolBar->setIconSize(QSize(size, size));
    editorToolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    return editorToolBar;
con's avatar
con committed
554 555
}

556
Core::ActionContainer *FormEditorW::createPreviewStyleMenu(Core::ActionManager *am,
con's avatar
con committed
557 558 559
                                                            QActionGroup *actionGroup)
{
    const QString menuId = QLatin1String(M_FORMEDITOR_PREVIEW);
560
    Core::ActionContainer *menuPreviewStyle = am->createMenu(menuId);
con's avatar
con committed
561 562 563 564 565 566 567 568 569 570 571
    menuPreviewStyle->menu()->setTitle(tr("Preview in"));

    // The preview menu is a list of invisible actions for the embedded design
    // device profiles (integer data) followed by a separator and the styles
    // (string data). Make device profiles update their text and hide them
    // in the configuration dialog.
    const QList<QAction*> actions = actionGroup->actions();

    const QString deviceProfilePrefix = QLatin1String("DeviceProfile");
    const QChar dot = QLatin1Char('.');

hjk's avatar
hjk committed
572
    foreach (QAction* a, actions) {
con's avatar
con committed
573 574 575 576 577 578 579 580 581
        QString name = menuId;
        name += dot;
        const QVariant data = a->data();
        const bool isDeviceProfile = data.type() == QVariant::Int;
        if (isDeviceProfile) {
            name += deviceProfilePrefix;
            name += dot;
        }
        name += data.toString();
582
        Core::Command *command = am->registerAction(a, name, m_contexts);
583
        bindShortcut(command, a);
con's avatar
con committed
584
        if (isDeviceProfile) {
con's avatar
con committed
585 586
            command->setAttribute(Core::Command::CA_UpdateText);
            command->setAttribute(Core::Command::CA_NonConfigureable);
con's avatar
con committed
587 588 589 590 591 592 593 594 595
        }
        menuPreviewStyle->addAction(command);
    }
    return menuPreviewStyle;
}

void FormEditorW::saveSettings(QSettings *s)
{
    s->beginGroup(settingsGroup);
596
    m_editorWidget->saveSettings(s);
597
    s->endGroup();
con's avatar
con committed
598 599 600 601 602 603 604
}

void FormEditorW::critical(const QString &errorMessage)
{
    QMessageBox::critical(m_core->mainWindow(), tr("Designer"),  errorMessage);
}

605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
// Apply the command shortcut to the action and connects to the command's keySequenceChanged signal
void FormEditorW::bindShortcut(Core::Command *command, QAction *action)
{
    m_commandToDesignerAction.insert(command, action);
    connect(command, SIGNAL(keySequenceChanged()),
            m_shortcutMapper, SLOT(map()));
    m_shortcutMapper->setMapping(command, command);
    updateShortcut(command);
}

// Create an action to activate a designer tool
QAction *FormEditorW::createEditModeAction(QActionGroup *ag,
                                     const QList<int> &context,
                                     Core::ActionManager *am,
                                     Core::ActionContainer *medit,
                                     const QString &actionName,
                                     const QString &name,
                                     int toolNumber,
                                     const QString &iconName,
                                     const QString &keySequence)
{
    QAction *rc = new QAction(actionName, ag);
    rc->setCheckable(true);
    if (!iconName.isEmpty())
         rc->setIcon(designerIcon(iconName));
    Core::Command *command = am->registerAction(rc, name, context);
    if (!keySequence.isEmpty())
        command->setDefaultKeySequence(QKeySequence(keySequence));
    bindShortcut(command, rc);
    medit->addAction(command, Core::Constants::G_EDIT_OTHER);
    rc->setData(toolNumber);
    ag->addAction(rc);
    return rc;
}

// Create a tool action
void FormEditorW::addToolAction(QAction *a,
                   Core::ActionManager *am,
                   const QList<int> &context,
                   const QString &name,
                   Core::ActionContainer *c1,
                   const QString &keySequence)
{
    Core::Command *command = am->registerAction(a, name, context);
    if (!keySequence.isEmpty())
        command->setDefaultKeySequence(QKeySequence(keySequence));
    bindShortcut(command, a);
    c1->addAction(command);
}

655
EditorData FormEditorW::createEditor(QWidget *parent)
con's avatar
con committed
656
{
657 658 659 660
    if (Designer::Constants::Internal::debug)
        qDebug() << "FormEditorW::createEditor";
    // Create and associate form and text editor.
    EditorData data;
con's avatar
con committed
661
    m_fwm->closeAllPreviews();
662 663
    qdesigner_internal::FormWindowBase *form = qobject_cast<qdesigner_internal::FormWindowBase *>(m_fwm->createFormWindow(0));
    QTC_ASSERT(form, return data);
con's avatar
con committed
664
    connect(form, SIGNAL(toolChanged(int)), this, SLOT(toolChanged(int)));
665
    form->setDesignerGrid(qdesigner_internal::FormWindowBase::defaultDesignerGrid());
con's avatar
con committed
666
    qdesigner_internal::FormWindowBase::setupDefaultAction(form);
667 668 669 670 671 672 673 674 675
    data.formEditor = new FormWindowEditor(form);
    DesignerXmlEditor *xmlEditor = new DesignerXmlEditor(form, parent);
    TextEditor::TextEditorSettings::instance()->initializeEditor(xmlEditor);
    data.xmlEditor = xmlEditor->designerEditable();
    data.formEditor->setFile(data.xmlEditor->file());
    connect(data.formEditor, SIGNAL(formWindowSizeChanged(int,int)),
            xmlEditor, SIGNAL(changed()));
    m_editorWidget->add(data);
    return data;
con's avatar
con committed
676 677
}

678 679 680 681 682 683 684 685 686 687 688
void FormEditorW::updateShortcut(QObject *command)
{
    Core::Command *c = qobject_cast<Core::Command *>(command);
    if (!c)
        return;
    QAction *a = m_commandToDesignerAction.value(c);
    if (!a)
        return;
    a->setShortcut(c->action()->shortcut());
}

con's avatar
con committed
689 690
void FormEditorW::currentEditorChanged(Core::IEditor *editor)
{
691 692
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << editor << " of " << m_fwm->formWindowCount();
con's avatar
con committed
693

Lasse Holmstedt's avatar
Lasse Holmstedt committed
694 695 696
    if (editor && editor->id() == QLatin1String(Constants::K_DESIGNER_XML_EDITOR_ID)) {
        DesignerXmlEditorEditable *xmlEditor = qobject_cast<DesignerXmlEditorEditable *>(editor);
        QTC_ASSERT(xmlEditor, return);
697 698
        ensureInitStage(FullyInitialized);
        FormWindowEditor *fw = m_editorWidget->formWindowEditorForXmlEditor(xmlEditor);
699 700
        QTC_ASSERT(fw, return)
        m_editorWidget->setVisibleEditor(xmlEditor);
con's avatar
con committed
701
        m_fwm->setActiveFormWindow(fw->formWindow());
702
        m_actionGroupEditMode->setVisible(true);
con's avatar
con committed
703
        m_modeActionSeparator->setVisible(true);
704 705
        // Now switch to design mode.
        m_core->modeManager()->activateMode(QLatin1String(Core::Constants::MODE_DESIGN));
con's avatar
con committed
706
    } else {
707
        // Deactivate Designer if a non-form is being edited
708
        m_actionGroupEditMode->setVisible(false);
con's avatar
con committed
709
        m_modeActionSeparator->setVisible(false);
con's avatar
con committed
710 711 712 713 714
    }
}

void FormEditorW::activeFormWindowChanged(QDesignerFormWindowInterface *afw)
{
715
    if (Designer::Constants::Internal::debug)
716
        qDebug() << Q_FUNC_INFO << afw << " of " << m_fwm->formWindowCount();
con's avatar
con committed
717 718

    m_fwm->closeAllPreviews();
719 720
    m_actionPreview->setEnabled(afw != 0);
    m_actionGroupPreviewInStyle->setEnabled(afw != 0);
con's avatar
con committed
721 722
}

723
FormWindowEditor *FormEditorW::activeFormWindow() const
con's avatar
con committed
724
{
725 726
    if (m_editorWidget)
        return m_editorWidget->activeFormWindow();
con's avatar
con committed
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
    return 0;
}

void FormEditorW::activateEditMode(int id)
{
    if (const int count = m_fwm->formWindowCount())
        for (int i = 0; i <  count; i++)
             m_fwm->formWindow(i)->setCurrentTool(id);
}

void FormEditorW::activateEditMode(QAction* a)
{
    activateEditMode(a->data().toInt());
}

void FormEditorW::toolChanged(int t)
{
    typedef QList<QAction *> ActionList;
    if (const QAction *currentAction = m_actionGroupEditMode->checkedAction())
        if (currentAction->data().toInt() == t)
            return;
    const ActionList actions = m_actionGroupEditMode->actions();
    const ActionList::const_iterator cend = actions.constEnd();
    for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
        if ( (*it)->data().toInt() == t) {
            (*it)->setChecked(true);
            break;
        }
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
757 758 759
void FormEditorW::closeFormEditorsForXmlEditors(QList<Core::IEditor*> editors)
{
    foreach(Core::IEditor *editor, editors) {
760
        m_editorWidget->removeFormWindowEditor(editor);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
761 762 763
    }
}

con's avatar
con committed
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
void FormEditorW::print()
{
    // Printing code courtesy of designer_actions.cpp
    QDesignerFormWindowInterface *fw = m_fwm->activeFormWindow();
    if (!fw)
        return;

    const bool oldFullPage =  m_core->printer()->fullPage();
    const QPrinter::Orientation oldOrientation =  m_core->printer()->orientation ();
    m_core->printer()->setFullPage(false);
    do {

        // Grab the image to be able to a suggest suitable orientation
        QString errorMessage;
        const QPixmap pixmap = m_fwm->createPreviewPixmap(&errorMessage);
        if (pixmap.isNull()) {
Jure Repinc's avatar
Jure Repinc committed
780
            critical(tr("The image could not be created: %1").arg(errorMessage));
con's avatar
con committed
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
            break;
        }

        const QSizeF pixmapSize = pixmap.size();
        m_core->printer()->setOrientation( pixmapSize.width() > pixmapSize.height() ?  QPrinter::Landscape :  QPrinter::Portrait);

        // Printer parameters
        QPrintDialog dialog(m_core->printer(), fw);
        if (!dialog.exec())
           break;

        const QCursor oldCursor = m_core->mainWindow()->cursor();
        m_core->mainWindow()->setCursor(Qt::WaitCursor);
        // Estimate of required scaling to make form look the same on screen and printer.
        const double suggestedScaling = static_cast<double>(m_core->printer()->physicalDpiX()) /  static_cast<double>(fw->physicalDpiX());

        QPainter painter(m_core->printer());
        painter.setRenderHint(QPainter::SmoothPixmapTransform);

        // Clamp to page
        const QRectF page =  painter.viewport();
        const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height());
        const double scaling = qMin(suggestedScaling, maxScaling);

        const double xOffset = page.left() + qMax(0.0, (page.size().width()  - scaling * pixmapSize.width())  / 2.0);
        const double yOffset = page.top()  + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0);

        // Draw.
        painter.translate(xOffset, yOffset);
        painter.scale(scaling, scaling);
        painter.drawPixmap(0, 0, pixmap);
        m_core->mainWindow()->setCursor(oldCursor);

    } while (false);
    m_core->printer()->setFullPage(oldFullPage);
    m_core->printer()->setOrientation(oldOrientation);
}
Lasse Holmstedt's avatar
Lasse Holmstedt committed
818

819 820
} // namespace Internal
} // namespace Designer