formeditorw.cpp 35.8 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 33 34 35
#include "formeditorw.h"
#include "formwindoweditor.h"
#include "designerconstants.h"
#include "settingsmanager.h"
#include "settingspage.h"
#include "editorwidget.h"
36
#include "qtcreatorintegration.h"
Lasse Holmstedt's avatar
Lasse Holmstedt committed
37 38 39
#include "designerxmleditor.h"
#include "designercontext.h"
#include "formeditorstack.h"
con's avatar
con committed
40

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

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

Roberto Raggi's avatar
Roberto Raggi committed
55 56 57
#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
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerComponents>

#include <QtDesigner/QDesignerWidgetBoxInterface>
#include <QtDesigner/abstractobjectinspector.h>
#include <QtDesigner/QDesignerPropertyEditorInterface>
#include <QtDesigner/QDesignerActionEditorInterface>

#include <QtCore/QPluginLoader>
#include <QtCore/QTemporaryFile>
#include <QtCore/QDir>
#include <QtCore/QTime>
#include <QtGui/QAction>
#include <QtGui/QActionGroup>
#include <QtGui/QApplication>
#include <QtGui/QCursor>
con's avatar
con committed
74
#include <QtGui/QDockWidget>
con's avatar
con committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
#include <QtGui/QMenu>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QKeySequence>
#include <QtGui/QPrintDialog>
#include <QtGui/QPrinter>
#include <QtGui/QPainter>
#include <QtGui/QStatusBar>
#include <QtGui/QStyle>
#include <QtGui/QToolBar>

#include <QtCore/QDebug>
#include <QtCore/QSettings>

static const char *settingsGroup = "Designer";

91 92 93 94 95 96 97 98
#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
99
 * "edit mode" context) when it is focused.
100 101 102 103 104
 * 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
105 106 107 108 109 110 111 112
static inline QIcon designerIcon(const QString &iconName)
{
    const QIcon icon = qdesigner_internal::createIconSet(iconName);
    if (icon.isNull())
        qWarning() << "Unable to locate " << iconName;
    return icon;
}

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

128
using namespace Designer;
con's avatar
con committed
129 130 131
using namespace Designer::Internal;
using namespace Designer::Constants;

con's avatar
con committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
// --------- Proxy Action

ProxyAction::ProxyAction(const QString &defaultText, QObject *parent)
    : QAction(defaultText, parent),
    m_defaultText(defaultText),
    m_action(0)
{
    setEnabled(false);
}

void ProxyAction::setAction(QAction *action)
{
    if (m_action) {
        disconnect(m_action, SIGNAL(changed()), this, SLOT(update()));
        disconnect(this, SIGNAL(triggered(bool)), m_action, SIGNAL(triggered(bool)));
        disconnect(this, SIGNAL(toggled(bool)), m_action, SLOT(setChecked(bool)));
    }
    m_action = action;
    if (!m_action) {
        setEnabled(false);
//        if (hasAttribute(CA_Hide))
//            m_action->setVisible(false);
//        if (hasAttribute(CA_UpdateText)) {
            setText(m_defaultText);
//        }
    } else {
        setCheckable(m_action->isCheckable());
        setSeparator(m_action->isSeparator());
        connect(m_action, SIGNAL(changed()), this, SLOT(update()));
        // we want to avoid the toggling semantic on slot trigger(), so we just connect the signals
        connect(this, SIGNAL(triggered(bool)), m_action, SIGNAL(triggered(bool)));
        // we need to update the checked state, so we connect to setChecked slot, which also fires a toggled signal
        connect(this, SIGNAL(toggled(bool)), m_action, SLOT(setChecked(bool)));
        update();
    }
}

void ProxyAction::update()
{
    QTC_ASSERT(m_action, return)
    bool block = blockSignals(true);
//    if (hasAttribute(CA_UpdateIcon)) {
        setIcon(m_action->icon());
        setIconText(m_action->iconText());
//    }
//    if (hasAttribute(CA_UpdateText)) {
        setText(m_action->text());
        setToolTip(m_action->toolTip());
        setStatusTip(m_action->statusTip());
        setWhatsThis(m_action->whatsThis());
//    }

    setChecked(m_action->isChecked());

    setEnabled(m_action->isEnabled());
    setVisible(m_action->isVisible());
    blockSignals(block);
    emit changed();
}

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

con's avatar
con committed
194 195 196 197 198 199
FormEditorW *FormEditorW::m_self = 0;

FormEditorW::FormEditorW() :
    m_formeditor(QDesignerComponents::createFormEditor(0)),
    m_integration(0),
    m_fwm(0),
200
    m_core(Core::ICore::instance()),
con's avatar
con committed
201 202
    m_initStage(RegisterPlugins),
    m_actionGroupEditMode(0),
203 204 205
    m_actionPrint(0),
    m_actionPreview(0),
    m_actionGroupPreviewInStyle(0),
206
    m_actionAboutPlugins(0),
Lasse Holmstedt's avatar
Lasse Holmstedt committed
207 208 209 210
    m_shortcutMapper(new QSignalMapper(this)),
    m_context(0),
    m_stack(new FormEditorStack),
    m_designMode(0)
con's avatar
con committed
211
{
212
    if (Designer::Constants::Internal::debug)
con's avatar
con committed
213
        qDebug() << Q_FUNC_INFO;
hjk's avatar
hjk committed
214
    QTC_ASSERT(!m_self, return);
con's avatar
con committed
215
    m_self = this;
hjk's avatar
hjk committed
216
    QTC_ASSERT(m_core, return);
con's avatar
con committed
217 218 219

    qFill(m_designerSubWindows, m_designerSubWindows + Designer::Constants::DesignerSubWindowCount,
          static_cast<QWidget *>(0));
con's avatar
con committed
220 221
    qFill(m_designerSubWindowActions, m_designerSubWindowActions + Designer::Constants::DesignerSubWindowCount,
          static_cast<ProxyAction *>(0));
con's avatar
con committed
222 223 224 225 226

    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
227
    QTC_ASSERT(m_fwm, return);
con's avatar
con committed
228

Lasse Holmstedt's avatar
Lasse Holmstedt committed
229
    m_context = new DesignerContext();
con's avatar
con committed
230 231 232 233 234 235 236 237 238 239 240
    setupActions();

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

    connect(m_core->editorManager(), SIGNAL(currentEditorChanged(Core::IEditor *)),
            this, SLOT(currentEditorChanged(Core::IEditor *)));
241 242
    connect(m_shortcutMapper, SIGNAL(mapped(QObject *)),
            this, SLOT(updateShortcut(QObject *)));
con's avatar
con committed
243 244 245 246 247 248
}

FormEditorW::~FormEditorW()
{
    saveSettings(m_core->settings());

Lasse Holmstedt's avatar
Lasse Holmstedt committed
249 250 251 252 253 254
    if (m_initStage == FullyInitialized) {
        m_designMode->unregisterDesignWidget(m_stack);
        delete m_stack;
        m_stack = 0;
    }

con's avatar
con committed
255 256 257 258 259 260 261 262
    for (int i = 0; i < Designer::Constants::DesignerSubWindowCount; ++i)
        delete m_designerSubWindows[i];

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



con's avatar
con committed
267 268 269 270 271
    m_self = 0;
}

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

    QDesignerComponents::createTaskMenu(m_formeditor, parent());
    QDesignerComponents::initializePlugins(designerEditor());
    QDesignerComponents::initializeResources();
    initDesignerSubWindows();
283
    m_integration = new QtCreatorIntegration(m_formeditor, this);
con's avatar
con committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297
    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);
        }
    }

298 299 300
    if (m_actionAboutPlugins)
        m_actionAboutPlugins->setEnabled(true);

301
    if (Designer::Constants::Internal::debug) {
con's avatar
con committed
302 303 304
        qDebug() << Q_FUNC_INFO << initTime->elapsed() << "ms";
        delete initTime;
    }
305

Lasse Holmstedt's avatar
Lasse Holmstedt committed
306 307 308 309 310 311 312 313 314 315 316 317
    connect(m_core->editorManager()->instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
            SLOT(checkToActivateEditor(Core::IEditor*)));
    connect(m_core->modeManager(), SIGNAL(currentModeChanged(Core::IMode*)),
            SLOT(syncOnModeChange(Core::IMode*)));    
    connect(m_core->editorManager()->instance(), SIGNAL(editorsClosed(QList<Core::IEditor*>)),
            SLOT(closeFormEditorsForXmlEditors(QList<Core::IEditor*>)));

    m_designMode = ExtensionSystem::PluginManager::instance()->getObject<Core::DesignMode>();
    QStringList mimeTypes;
    mimeTypes << FORM_MIMETYPE;
    m_designMode->registerDesignWidget(m_stack, mimeTypes);

con's avatar
con committed
318 319 320 321 322 323 324 325
    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
326
    wb->setWindowTitle(tr("Widget Box"));
con's avatar
con committed
327 328 329 330
    m_formeditor->setWidgetBox(wb);
    m_designerSubWindows[WidgetBoxSubWindow] = wb;

    QDesignerObjectInspectorInterface *oi = QDesignerComponents::createObjectInspector(m_formeditor, 0);
con's avatar
con committed
331
    oi->setWindowTitle(tr("Object Inspector"));
con's avatar
con committed
332 333 334 335
    m_formeditor->setObjectInspector(oi);
    m_designerSubWindows[ObjectInspectorSubWindow] = oi;

    QDesignerPropertyEditorInterface *pe = QDesignerComponents::createPropertyEditor(m_formeditor, 0);
con's avatar
con committed
336
    pe->setWindowTitle(tr("Property Editor"));
con's avatar
con committed
337 338 339 340
    m_formeditor->setPropertyEditor(pe);
    m_designerSubWindows[PropertyEditorSubWindow] = pe;

    QWidget *se = QDesignerComponents::createSignalSlotEditor(m_formeditor, 0);
con's avatar
con committed
341
    se->setWindowTitle(tr("Signals & Slots Editor"));
con's avatar
con committed
342 343 344
    m_designerSubWindows[SignalSlotEditorSubWindow] = se;

    QDesignerActionEditorInterface *ae = QDesignerComponents::createActionEditor(m_formeditor, 0);
con's avatar
con committed
345
    ae->setWindowTitle(tr("Action Editor"));
con's avatar
con committed
346 347 348 349 350 351
    m_formeditor->setActionEditor(ae);
    m_designerSubWindows[ActionEditorSubWindow] = ae;
}

void FormEditorW::ensureInitStage(InitializationStage s)
{
352
    if (Designer::Constants::Internal::debug)
con's avatar
con committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
        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;
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
void FormEditorW::checkToActivateEditor(Core::IEditor *editor)
{
    Core::ModeManager *mm = Core::ICore::instance()->modeManager();
    if (editor && editor->id() == Constants::K_DESIGNER_XML_EDITOR_ID) {
        mm->activateMode(Core::Constants::MODE_DESIGN);
    }
}

void FormEditorW::syncOnModeChange(Core::IMode *mode)
{
    Core::ICore *core = Core::ICore::instance();
    if (mode->id() == Core::Constants::MODE_DESIGN
        && core->editorManager()->currentEditor()->id() == Designer::Constants::K_DESIGNER_XML_EDITOR_ID )
    {
        m_stack->setVisibleEditor(core->editorManager()->currentEditor());
    }
}

con's avatar
con committed
392 393
void FormEditorW::setupActions()
{
394
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
395
    Core::Command *command;
con's avatar
con committed
396 397

    //menus
398
    Core::ActionContainer *medit =
con's avatar
con committed
399
        am->actionContainer(Core::Constants::M_EDIT);
400
    Core::ActionContainer *mtools =
con's avatar
con committed
401 402
        am->actionContainer(Core::Constants::M_TOOLS);

403
    Core::ActionContainer *mformtools =
con's avatar
con committed
404
        am->createMenu(M_FORMEDITOR);
Friedemann Kleint's avatar
Friedemann Kleint committed
405
    mformtools->menu()->setTitle(tr("For&m Editor"));
con's avatar
con committed
406 407 408
    mtools->addMenu(mformtools);

    //overridden actions
Lasse Holmstedt's avatar
Lasse Holmstedt committed
409 410 411 412 413 414
    bindShortcut(am->registerAction(m_fwm->actionUndo(), Core::Constants::UNDO, m_context->context()), m_fwm->actionUndo());
    bindShortcut(am->registerAction(m_fwm->actionRedo(), Core::Constants::REDO, m_context->context()), m_fwm->actionRedo());
    bindShortcut(am->registerAction(m_fwm->actionCut(), Core::Constants::CUT, m_context->context()), m_fwm->actionCut());
    bindShortcut(am->registerAction(m_fwm->actionCopy(), Core::Constants::COPY, m_context->context()), m_fwm->actionCopy());
    bindShortcut(am->registerAction(m_fwm->actionPaste(), Core::Constants::PASTE, m_context->context()), m_fwm->actionPaste());
    bindShortcut(am->registerAction(m_fwm->actionSelectAll(), Core::Constants::SELECTALL, m_context->context()), m_fwm->actionSelectAll());
con's avatar
con committed
415 416

    m_actionPrint = new QAction(this);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
417
    bindShortcut(am->registerAction(m_actionPrint, Core::Constants::PRINT, m_context->context()), m_actionPrint);
con's avatar
con committed
418 419 420
    connect(m_actionPrint, SIGNAL(triggered()), this, SLOT(print()));

    //'delete' action
Lasse Holmstedt's avatar
Lasse Holmstedt committed
421
    command = am->registerAction(m_fwm->actionDelete(), QLatin1String("FormEditor.Edit.Delete"), m_context->context());
con's avatar
con committed
422
    command->setDefaultKeySequence(QKeySequence::Delete);
423
    bindShortcut(command, m_fwm->actionDelete());
con's avatar
con committed
424
    command->setAttribute(Core::Command::CA_Hide);
con's avatar
con committed
425 426
    medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

427 428 429
    QList<int> globalcontext;
    globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);

con's avatar
con committed
430 431 432 433
    m_actionGroupEditMode = new QActionGroup(this);
    m_actionGroupEditMode->setExclusive(true);
    connect(m_actionGroupEditMode, SIGNAL(triggered(QAction*)), this, SLOT(activateEditMode(QAction*)));

con's avatar
con committed
434 435 436 437 438
    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
439
    m_toolActionIds.push_back(QLatin1String("FormEditor.WidgetEditor"));
440
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
441
                         tr("Edit widgets"), m_toolActionIds.back(),
con's avatar
con committed
442 443 444
                         EditModeWidgetEditor, QLatin1String("widgettool.png"), tr("F3"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.SignalsSlotsEditor"));
445
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
446
                         tr("Edit signals/slots"), m_toolActionIds.back(),
con's avatar
con committed
447 448 449
                         EditModeSignalsSlotEditor, QLatin1String("signalslottool.png"), tr("F4"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.BuddyEditor"));
450
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
451
                         tr("Edit buddies"), m_toolActionIds.back(),
con's avatar
con committed
452 453 454
                         EditModeBuddyEditor, QLatin1String("buddytool.png"));

    m_toolActionIds.push_back(QLatin1String("FormEditor.TabOrderEditor"));
455
    createEditModeAction(m_actionGroupEditMode, globalcontext, am, medit,
456
                         tr("Edit tab order"),  m_toolActionIds.back(),
con's avatar
con committed
457 458 459 460
                         EditModeTabOrderEditor, QLatin1String("tabordertool.png"));

    //tool actions
    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutHorizontally"));
461 462 463 464
    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
465
    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutVertically"));
466 467 468
    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
469 470

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

    m_toolActionIds.push_back(QLatin1String("FormEditor.SplitVertical"));
475
    addToolAction(m_fwm->actionSplitVertical(), am, globalcontext,
con's avatar
con committed
476 477 478
                  m_toolActionIds.back(), mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutForm"));
479
    addToolAction(m_fwm->actionFormLayout(), am, globalcontext,
con's avatar
con committed
480 481 482
                  m_toolActionIds.back(),  mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutGrid"));
483 484 485
    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
486 487

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutBreak"));
488
    addToolAction(m_fwm->actionBreakLayout(), am, globalcontext,
con's avatar
con committed
489 490 491
                  m_toolActionIds.back(), mformtools);

    m_toolActionIds.push_back(QLatin1String("FormEditor.LayoutAdjustSize"));
492 493 494
    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
495 496

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

Lasse Holmstedt's avatar
Lasse Holmstedt committed
500
    createSeparator(this, am, m_context->context(), mformtools, QLatin1String("FormEditor.Menu.Tools.Separator1"));
con's avatar
con committed
501

502
    addToolAction(m_fwm->actionLower(), am, globalcontext,
con's avatar
con committed
503 504
                  QLatin1String("FormEditor.Lower"), mformtools);

505
    addToolAction(m_fwm->actionRaise(), am, globalcontext,
con's avatar
con committed
506 507
                  QLatin1String("FormEditor.Raise"), mformtools);

con's avatar
con committed
508 509 510 511
    // Views
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.SeparatorViews"));

    Core::ActionContainer *mviews = am->createMenu(M_FORMEDITOR_VIEWS);
512
    mviews->menu()->setTitle(tr("Views"));
con's avatar
con committed
513 514 515 516 517 518 519 520 521 522 523 524 525 526
    mformtools->addMenu(mviews);

    m_designerSubWindowActions[WidgetBoxSubWindow] = new ProxyAction(tr("Widget Box"), this);
    addToolAction(m_designerSubWindowActions[WidgetBoxSubWindow], am, globalcontext,
                  QLatin1String("FormEditor.WidgetBox"), mviews, "");

    m_designerSubWindowActions[ObjectInspectorSubWindow] = new ProxyAction(tr("Object Inspector"), this);
    addToolAction(m_designerSubWindowActions[ObjectInspectorSubWindow], am, globalcontext,
                  QLatin1String("FormEditor.ObjectInspector"), mviews, "");

        m_designerSubWindowActions[PropertyEditorSubWindow] = new ProxyAction(tr("Property Editor"), this);
    addToolAction(m_designerSubWindowActions[PropertyEditorSubWindow], am, globalcontext,
                  QLatin1String("FormEditor.PropertyEditor"), mviews, "");

Daniel Molkentin's avatar
Daniel Molkentin committed
527
    m_designerSubWindowActions[SignalSlotEditorSubWindow] = new ProxyAction(tr("Signals && Slots Editor"), this);
con's avatar
con committed
528 529 530 531 532 533 534
    addToolAction(m_designerSubWindowActions[SignalSlotEditorSubWindow], am, globalcontext,
                  QLatin1String("FormEditor.SignalsAndSlotsEditor"), mviews, "");

    m_designerSubWindowActions[ActionEditorSubWindow] = new ProxyAction(tr("Action Editor"), this);
    addToolAction(m_designerSubWindowActions[ActionEditorSubWindow], am, globalcontext,
                  QLatin1String("FormEditor.ActionEditor"), mviews, "");

535 536 537 538 539 540 541 542 543 544 545 546 547
    createSeparator(this, am, globalcontext, mviews, 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"), mviews, "");
    connect(m_lockAction, SIGNAL(toggled(bool)), this, SLOT(setFormWindowLayoutLocked(bool)));

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

    m_resetLayoutAction = new QAction(tr("Reset to Default Layout"), this);
    addToolAction(m_resetLayoutAction, am, globalcontext, QLatin1String("FormEditor.ResetToDefaultLayout"), mviews, "");
    connect(m_resetLayoutAction, SIGNAL(triggered()), this, SLOT(resetToDefaultLayout()));

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

    m_actionPreview = m_fwm->actionDefaultPreview();
hjk's avatar
hjk committed
552
    QTC_ASSERT(m_actionPreview, return);
553
    addToolAction(m_actionPreview,  am,  globalcontext,
con's avatar
con committed
554 555 556 557 558 559 560
                   QLatin1String("FormEditor.Preview"), mformtools, tr("Ctrl+Alt+R"));

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

    // Form settings
Lasse Holmstedt's avatar
Lasse Holmstedt committed
561
    createSeparator(this, am, m_context->context(),  medit, QLatin1String("FormEditor.Edit.Separator2"), Core::Constants::G_EDIT_OTHER);
con's avatar
con committed
562

563
    createSeparator(this, am, globalcontext, mformtools, QLatin1String("FormEditor.Menu.Tools.Separator3"));
con's avatar
con committed
564
    QAction *actionFormSettings = m_fwm->actionShowFormWindowSettingsDialog();
565 566
    addToolAction(actionFormSettings, am, globalcontext, QLatin1String("FormEditor.FormSettings"), mformtools);

567 568 569 570 571 572 573
    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);

con's avatar
con committed
574 575 576 577 578 579 580
    // FWM
    connect(m_fwm, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface *)), this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface *)));
}


QToolBar *FormEditorW::createEditorToolBar() const
{
con's avatar
con committed
581
    QToolBar *toolBar = new QToolBar;
582
    Core::ActionManager *am = m_core->actionManager();
con's avatar
con committed
583 584
    const QStringList::const_iterator cend = m_toolActionIds.constEnd();
    for (QStringList::const_iterator it = m_toolActionIds.constBegin(); it != cend; ++it) {
con's avatar
con committed
585
        Core::Command *cmd = am->command(*it);
hjk's avatar
hjk committed
586
        QTC_ASSERT(cmd, continue);
con's avatar
con committed
587 588
        QAction *action = cmd->action();
        if (!action->icon().isNull()) // Simplify grid has no action yet
con's avatar
con committed
589
            toolBar->addAction(action);
con's avatar
con committed
590
    }
con's avatar
con committed
591 592 593 594
    int size = toolBar->style()->pixelMetric(QStyle::PM_SmallIconSize);
    toolBar->setIconSize(QSize(size, size));
    toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    return toolBar;
con's avatar
con committed
595 596
}

597
Core::ActionContainer *FormEditorW::createPreviewStyleMenu(Core::ActionManager *am,
con's avatar
con committed
598 599 600
                                                            QActionGroup *actionGroup)
{
    const QString menuId = QLatin1String(M_FORMEDITOR_PREVIEW);
601
    Core::ActionContainer *menuPreviewStyle = am->createMenu(menuId);
con's avatar
con committed
602 603 604 605 606 607 608 609 610 611 612
    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
613
    foreach (QAction* a, actions) {
con's avatar
con committed
614 615 616 617 618 619 620 621 622
        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();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
623
        Core::Command *command = am->registerAction(a, name, m_context->context());
624
        bindShortcut(command, a);
con's avatar
con committed
625
        if (isDeviceProfile) {
con's avatar
con committed
626 627
            command->setAttribute(Core::Command::CA_UpdateText);
            command->setAttribute(Core::Command::CA_NonConfigureable);
con's avatar
con committed
628 629 630 631 632 633 634 635 636
        }
        menuPreviewStyle->addAction(command);
    }
    return menuPreviewStyle;
}

void FormEditorW::saveSettings(QSettings *s)
{
    s->beginGroup(settingsGroup);
637
    EditorWidget::saveState(s);
con's avatar
con committed
638 639 640
    s->endGroup();
}

641
void FormEditorW::restoreSettings(QSettings *s)
con's avatar
con committed
642
{
643 644 645
    s->beginGroup(settingsGroup);
    EditorWidget::restoreState(s);
    s->endGroup();
con's avatar
con committed
646 647 648 649 650 651 652 653
}


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

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
// 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);
}

con's avatar
con committed
704 705 706 707
FormWindowEditor *FormEditorW::createFormWindowEditor(QWidget* parentWidget)
{
    m_fwm->closeAllPreviews();
    QDesignerFormWindowInterface *form = m_fwm->createFormWindow(0);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
708

con's avatar
con committed
709 710
    connect(form, SIGNAL(toolChanged(int)), this, SLOT(toolChanged(int)));
    qdesigner_internal::FormWindowBase::setupDefaultAction(form);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
711 712

    FormWindowEditor *fww = new FormWindowEditor(form, parentWidget);
hjk's avatar
hjk committed
713 714
    // Store a pointer to all form windows so we can unselect
    // all other formwindows except the active one.
con's avatar
con committed
715
    m_formWindows.append(fww);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
716 717 718

    fww->setContext(m_context->context());

con's avatar
con committed
719 720 721 722 723 724 725 726
    connect(fww, SIGNAL(destroyed()), this, SLOT(editorDestroyed()));
    return fww;
}

void FormEditorW::editorDestroyed()
{
    QObject *source = sender();

727 728
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << source;
con's avatar
con committed
729 730 731 732 733 734 735 736 737 738 739

    for (EditorList::iterator it = m_formWindows.begin(); it != m_formWindows.end(); ) {
        if (*it == source) {
            it = m_formWindows.erase(it);
            break;
        } else {
            ++it;
        }
    }
}

740 741 742 743 744 745 746 747 748 749 750
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
751 752
void FormEditorW::currentEditorChanged(Core::IEditor *editor)
{
753 754
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << editor << " of " << m_fwm->formWindowCount();
con's avatar
con committed
755 756

    // Deactivate Designer if a non-form is being edited
Lasse Holmstedt's avatar
Lasse Holmstedt committed
757 758 759 760 761 762 763 764 765 766 767 768
    if (editor && editor->id() == QLatin1String(Constants::K_DESIGNER_XML_EDITOR_ID)) {
        DesignerXmlEditorEditable *xmlEditor = qobject_cast<DesignerXmlEditorEditable *>(editor);
        FormWindowEditor *fw = m_stack->formWindowEditorForXmlEditor(xmlEditor);
        QTC_ASSERT(xmlEditor, return);
        if (!fw)
            fw = m_stack->createFormWindowEditor(xmlEditor);

        // change context when activating another editor
        m_core->removeContextObject(m_context);
        m_context->setWidget(fw->widget());
        m_core->addContextObject(m_context);

con's avatar
con committed
769
        fw->activate();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
770

con's avatar
con committed
771
        m_fwm->setActiveFormWindow(fw->formWindow());
772
        m_actionGroupEditMode->setVisible(true);
con's avatar
con committed
773
        m_modeActionSeparator->setVisible(true);
con's avatar
con committed
774 775 776 777 778
        QDockWidget * const*dockWidgets = fw->dockWidgets();
        for (int i = 0; i < Designer::Constants::DesignerSubWindowCount; ++i) {
            if (m_designerSubWindowActions[i] != 0 && dockWidgets[i] != 0)
                m_designerSubWindowActions[i]->setAction(dockWidgets[i]->toggleViewAction());
        }
779 780 781
        m_lockAction->setEnabled(true);
        m_lockAction->setChecked(fw->isLocked());
        m_resetLayoutAction->setEnabled(true);
con's avatar
con committed
782
    } else {
783
        m_actionGroupEditMode->setVisible(false);
con's avatar
con committed
784
        m_modeActionSeparator->setVisible(false);
con's avatar
con committed
785
        m_fwm->setActiveFormWindow(0);
con's avatar
con committed
786 787 788 789
        for (int i = 0; i < Designer::Constants::DesignerSubWindowCount; ++i) {
            if (m_designerSubWindowActions[i] != 0)
                m_designerSubWindowActions[i]->setAction(0);
        }
790 791
        m_lockAction->setEnabled(false);
        m_resetLayoutAction->setEnabled(false);
con's avatar
con committed
792 793 794 795 796
    }
}

void FormEditorW::activeFormWindowChanged(QDesignerFormWindowInterface *afw)
{
797 798
    if (Designer::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << afw << " of " << m_fwm->formWindowCount() << m_formWindows;
con's avatar
con committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857

    m_fwm->closeAllPreviews();

    bool foundFormWindow = false;
    // Display form selection handles only on active window
    EditorList::const_iterator cend = m_formWindows.constEnd();
    for (EditorList::const_iterator it = m_formWindows.constBegin(); it != cend ; ++it) {
        FormWindowEditor *fwe = *it;
        const bool active = fwe->formWindow() == afw;
        if (active)
            foundFormWindow = true;
        fwe->updateFormWindowSelectionHandles(active);
    }

    m_actionPreview->setEnabled(foundFormWindow);
    m_actionGroupPreviewInStyle->setEnabled(foundFormWindow);
}

FormWindowEditor *FormEditorW::activeFormWindow()
{
    QDesignerFormWindowInterface *afw = m_fwm->activeFormWindow();
    for (int i = 0; i < m_formWindows.count(); ++i) {
        if (FormWindowEditor *fw = m_formWindows[i]) {
            QDesignerFormWindowInterface *fwd = fw->formWindow();
            if (fwd == afw) {
                return fw;
            }
        }
    }
    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;
        }
}

858 859 860 861 862 863 864 865 866 867 868 869 870 871
void FormEditorW::setFormWindowLayoutLocked(bool locked)
{
    FormWindowEditor *fwe = activeFormWindow();
    if (fwe)
        fwe->setLocked(locked);
}

void FormEditorW::resetToDefaultLayout()
{
    FormWindowEditor *fwe = activeFormWindow();
    if (fwe)
        fwe->resetToDefaultLayout();
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
872 873 874 875 876 877 878
void FormEditorW::closeFormEditorsForXmlEditors(QList<Core::IEditor*> editors)
{
    foreach(Core::IEditor *editor, editors) {
        m_stack->removeFormWindowEditor(editor);
    }
}

con's avatar
con committed
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
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
895
            critical(tr("The image could not be created: %1").arg(errorMessage));
con's avatar
con committed
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
            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
933