diff options
Diffstat (limited to 'tools/designer/src/designer/qdesigner_workbench.cpp')
-rw-r--r-- | tools/designer/src/designer/qdesigner_workbench.cpp | 1096 |
1 files changed, 1096 insertions, 0 deletions
diff --git a/tools/designer/src/designer/qdesigner_workbench.cpp b/tools/designer/src/designer/qdesigner_workbench.cpp new file mode 100644 index 0000000..7ab3e94 --- /dev/null +++ b/tools/designer/src/designer/qdesigner_workbench.cpp @@ -0,0 +1,1096 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** 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. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_workbench.h" +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_appearanceoptions.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_formwindow.h" +#include "appfontdialog.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QDesignerFormEditorPluginInterface> +#include <QtDesigner/QDesignerWidgetBoxInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> + +#include <QtDesigner/QDesignerComponents> +#include <QtDesigner/private/qdesigner_integration_p.h> +#include <QtDesigner/private/pluginmanager_p.h> +#include <QtDesigner/private/formwindowbase_p.h> +#include <QtDesigner/private/actioneditor_p.h> + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QUrl> +#include <QtCore/QTimer> +#include <QtCore/QPluginLoader> +#include <QtCore/qdebug.h> + +#include <QtGui/QActionGroup> +#include <QtGui/QCloseEvent> +#include <QtGui/QDesktopWidget> +#include <QtGui/QDockWidget> +#include <QtGui/QMenu> +#include <QtGui/QMenuBar> +#include <QtGui/QMessageBox> +#include <QtGui/QPushButton> +#include <QtGui/QToolBar> +#include <QtGui/QMdiArea> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QLayout> + +QT_BEGIN_NAMESPACE + +static const char *appFontPrefixC = "AppFonts"; + +typedef QList<QAction *> ActionList; + +static QMdiSubWindow *mdiSubWindowOf(const QWidget *w) +{ + QMdiSubWindow *rc = qobject_cast<QMdiSubWindow *>(w->parentWidget()); + Q_ASSERT(rc); + return rc; +} + +static QDockWidget *dockWidgetOf(const QWidget *w) +{ + for (QWidget *parentWidget = w->parentWidget(); parentWidget ; parentWidget = parentWidget->parentWidget()) { + if (QDockWidget *dw = qobject_cast<QDockWidget *>(parentWidget)) { + return dw; + } + } + Q_ASSERT("Dock widget not found"); + return 0; +} + +// ------------ QDesignerWorkbench::Position +QDesignerWorkbench::Position::Position(const QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset) : + m_minimized(mdiSubWindow->isShaded()), + m_position(mdiSubWindow->pos() + mdiAreaOffset) +{ +} + +QDesignerWorkbench::Position::Position(const QDockWidget *dockWidget) : + m_minimized(dockWidget->isMinimized()), + m_position(dockWidget->pos()) +{ +} + +QDesignerWorkbench::Position::Position(const QWidget *topLevelWindow, const QPoint &desktopTopLeft) +{ + const QWidget *window =topLevelWindow->window (); + Q_ASSERT(window); + m_minimized = window->isMinimized(); + m_position = window->pos() - desktopTopLeft; +} + +void QDesignerWorkbench::Position::applyTo(QMdiSubWindow *mdiSubWindow, + const QPoint &mdiAreaOffset) const +{ + // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes. + // Restore old size + const QPoint mdiAreaPos = QPoint(qMax(0, m_position.x() - mdiAreaOffset.x()), + qMax(0, m_position.y() - mdiAreaOffset.y())); + mdiSubWindow->move(mdiAreaPos); + const QSize decorationSize = mdiSubWindow->size() - mdiSubWindow->contentsRect().size(); + mdiSubWindow->resize(mdiSubWindow->widget()->size() + decorationSize); + mdiSubWindow->show(); + if (m_minimized) { + mdiSubWindow->showShaded(); + } +} + +void QDesignerWorkbench::Position::applyTo(QWidget *topLevelWindow, const QPoint &desktopTopLeft) const +{ + QWidget *window = topLevelWindow->window (); + const QPoint newPos = m_position + desktopTopLeft; + window->move(newPos); + if ( m_minimized) { + topLevelWindow->showMinimized(); + } else { + topLevelWindow->show(); + } +} + +void QDesignerWorkbench::Position::applyTo(QDockWidget *dockWidget) const +{ + dockWidget->widget()->setVisible(true); + dockWidget->setVisible(!m_minimized); +} + +static inline void addActionsToMenu(QMenu *m, const ActionList &al) +{ + const ActionList::const_iterator cend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it) + m->addAction(*it); +} + +static inline QMenu *addMenu(QMenuBar *mb, const QString &title, const ActionList &al) +{ + QMenu *rc = mb->addMenu(title); + addActionsToMenu(rc, al); + return rc; +} + +// -------- QDesignerWorkbench + +QDesignerWorkbench::QDesignerWorkbench() : + m_core(QDesignerComponents::createFormEditor(this)), + m_windowActions(new QActionGroup(this)), + m_globalMenuBar(new QMenuBar), + m_mode(NeutralMode), + m_dockedMainWindow(0), + m_state(StateInitializing) +{ + QDesignerSettings settings(m_core); + + (void) QDesignerComponents::createTaskMenu(core(), this); + + initializeCorePlugins(); + QDesignerComponents::initializePlugins(core()); + m_actionManager = new QDesignerActions(this); // accesses plugin components + + m_windowActions->setExclusive(true); + connect(m_windowActions, SIGNAL(triggered(QAction*)), this, SLOT(formWindowActionTriggered(QAction*))); + + // Build main menu bar + addMenu(m_globalMenuBar, tr("&File"), m_actionManager->fileActions()->actions()); + + QMenu *editMenu = addMenu(m_globalMenuBar, tr("Edit"), m_actionManager->editActions()->actions()); + editMenu->addSeparator(); + addActionsToMenu(editMenu, m_actionManager->toolActions()->actions()); + + QMenu *formMenu = addMenu(m_globalMenuBar, tr("F&orm"), m_actionManager->formActions()->actions()); + QMenu *previewSubMenu = new QMenu(tr("Preview in"), formMenu); + formMenu->insertMenu(m_actionManager->previewFormAction(), previewSubMenu); + addActionsToMenu(previewSubMenu, m_actionManager->styleActions()->actions()); + + QMenu *viewMenu = m_globalMenuBar->addMenu(tr("&View")); + + addMenu(m_globalMenuBar, tr("&Settings"), m_actionManager->settingsActions()->actions()); + + m_windowMenu = addMenu(m_globalMenuBar, tr("&Window"), m_actionManager->windowActions()->actions()); + + addMenu(m_globalMenuBar, tr("&Help"), m_actionManager->helpActions()->actions()); + + // Add the tools in view menu order + QActionGroup *viewActions = new QActionGroup(this); + viewActions->setExclusive(false); + + for (int i = 0; i < QDesignerToolWindow::StandardToolWindowCount; i++) { + QDesignerToolWindow *toolWindow = QDesignerToolWindow::createStandardToolWindow(static_cast< QDesignerToolWindow::StandardToolWindow>(i), this); + m_toolWindows.push_back(toolWindow); + if (QAction *action = toolWindow->action()) { + viewMenu->addAction(action); + viewActions->addAction(action); + } + // The widget box becomes the main window in top level mode + if (i == QDesignerToolWindow::WidgetBox) + connect(toolWindow, SIGNAL(closeEventReceived(QCloseEvent*)), this, SLOT(handleCloseEvent(QCloseEvent*))); + } + // Integration + m_integration = new qdesigner_internal::QDesignerIntegration(m_core, this); + connect(m_integration, SIGNAL(helpRequested(QString,QString)), m_actionManager, SLOT(helpRequested(QString,QString))); + + // remaining view options (config toolbars) + viewMenu->addSeparator(); + m_toolbarMenu = viewMenu->addMenu(tr("Toolbars")); + + emit initialized(); + + connect(m_core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(updateWindowMenu(QDesignerFormWindowInterface*))); + + + { // Add application specific options pages + QDesignerAppearanceOptionsPage *appearanceOptions = new QDesignerAppearanceOptionsPage(m_core); + connect(appearanceOptions, SIGNAL(settingsChangedDelayed()), this, SLOT(restoreUISettings())); + QList<QDesignerOptionsPageInterface*> optionsPages = m_core->optionsPages(); + optionsPages.push_front(appearanceOptions); + m_core->setOptionsPages(optionsPages); + } + + restoreUISettings(); + AppFontWidget::restore(m_core->settingsManager(), QLatin1String(appFontPrefixC)); + m_state = StateUp; +} + +QDesignerWorkbench::~QDesignerWorkbench() +{ + switch (m_mode) { + case NeutralMode: + case DockedMode: + qDeleteAll(m_toolWindows); + break; + case TopLevelMode: // Everything parented here + delete widgetBoxToolWindow(); + break; + } +} + +void QDesignerWorkbench::saveGeometriesForModeChange() +{ + m_Positions.clear(); + switch (m_mode) { + case NeutralMode: + break; + case TopLevelMode: { + const QPoint desktopOffset = QApplication::desktop()->availableGeometry().topLeft(); + foreach (QDesignerToolWindow *tw, m_toolWindows) + m_Positions.insert(tw, Position(tw, desktopOffset)); + foreach (QDesignerFormWindow *fw, m_formWindows) { + m_Positions.insert(fw, Position(fw, desktopOffset)); + } + } + break; + case DockedMode: { + const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); + foreach (QDesignerToolWindow *tw, m_toolWindows) { + m_Positions.insert(tw, Position(dockWidgetOf(tw))); + } + foreach (QDesignerFormWindow *fw, m_formWindows) { + m_Positions.insert(fw, Position(mdiSubWindowOf(fw), mdiAreaOffset)); + } + } + break; + } +} + +UIMode QDesignerWorkbench::mode() const +{ + return m_mode; +} + +void QDesignerWorkbench::addFormWindow(QDesignerFormWindow *formWindow) +{ + // ### Q_ASSERT(formWindow->windowTitle().isEmpty() == false); + + m_formWindows.append(formWindow); + + + m_actionManager->setWindowListSeparatorVisible(true); + + if (QAction *action = formWindow->action()) { + m_windowActions->addAction(action); + m_windowMenu->addAction(action); + action->setChecked(true); + } + + m_actionManager->minimizeAction()->setEnabled(true); + m_actionManager->minimizeAction()->setChecked(false); + connect(formWindow, SIGNAL(minimizationStateChanged(QDesignerFormWindowInterface *, bool)), + this, SLOT(minimizationStateChanged(QDesignerFormWindowInterface *, bool))); + + m_actionManager->editWidgets()->trigger(); +} + +Qt::WindowFlags QDesignerWorkbench::magicalWindowFlags(const QWidget *widgetForFlags) const +{ + switch (m_mode) { + case TopLevelMode: { +#ifdef Q_WS_MAC + if (qobject_cast<const QDesignerToolWindow *>(widgetForFlags)) + return Qt::Tool; +#else + Q_UNUSED(widgetForFlags); +#endif + return Qt::Window; + } + case DockedMode: + return Qt::Window | Qt::WindowShadeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint; + case NeutralMode: + return Qt::Window; + default: + Q_ASSERT(0); + return 0; + } +} + +QWidget *QDesignerWorkbench::magicalParent(const QWidget *w) const +{ + switch (m_mode) { + case TopLevelMode: { + // Use widget box as parent for all windows except self. This will + // result in having just one entry in the MS Windows task bar. + QWidget *widgetBoxWrapper = widgetBoxToolWindow(); + return w == widgetBoxWrapper ? 0 : widgetBoxWrapper; + } + case DockedMode: + return m_dockedMainWindow->mdiArea(); + case NeutralMode: + return 0; + default: + Q_ASSERT(0); + return 0; + } +} + +void QDesignerWorkbench::switchToNeutralMode() +{ + QDesignerSettings settings(m_core); + saveGeometries(settings); + saveGeometriesForModeChange(); + + if (m_mode == TopLevelMode) { + delete m_topLevelData.toolbarManager; + m_topLevelData.toolbarManager = 0; + qDeleteAll(m_topLevelData.toolbars); + m_topLevelData.toolbars.clear(); + } + + m_mode = NeutralMode; + + foreach (QDesignerToolWindow *tw, m_toolWindows) { + tw->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents); + tw->setParent(0); + } + + foreach (QDesignerFormWindow *fw, m_formWindows) { + fw->setParent(0); + fw->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + } + +#ifndef Q_WS_MAC + m_globalMenuBar->setParent(0); +#endif + + m_core->setTopLevel(0); + qDesigner->setMainWindow(0); + + delete m_dockedMainWindow; + m_dockedMainWindow = 0; +} + +void QDesignerWorkbench::switchToDockedMode() +{ + if (m_mode == DockedMode) + return; + + switchToNeutralMode(); + + m_mode = DockedMode; + const QDesignerSettings settings(m_core); + m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); + m_dockedMainWindow->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); + connect(m_dockedMainWindow, SIGNAL(closeEventReceived(QCloseEvent*)), this, SLOT(handleCloseEvent(QCloseEvent*))); + connect(m_dockedMainWindow, SIGNAL(fileDropped(QString)), this, SLOT(slotFileDropped(QString))); + connect(m_dockedMainWindow, SIGNAL(formWindowActivated(QDesignerFormWindow*)), this, SLOT(slotFormWindowActivated(QDesignerFormWindow*))); + m_dockedMainWindow->restoreSettings(settings, m_dockedMainWindow->addToolWindows(m_toolWindows), desktopGeometry()); + + m_core->setTopLevel(m_dockedMainWindow); + +#ifndef Q_WS_MAC + m_dockedMainWindow->setMenuBar(m_globalMenuBar); + m_globalMenuBar->show(); +#endif + qDesigner->setMainWindow(m_dockedMainWindow); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + QMdiSubWindow *subwin = m_dockedMainWindow->createMdiSubWindow(fw, magicalWindowFlags(fw), + m_actionManager->closeFormAction()->shortcut()); + subwin->hide(); + if (QWidget *mainContainer = fw->editor()->mainContainer()) + resizeForm(fw, mainContainer); + } + + m_actionManager->setBringAllToFrontVisible(false); + m_dockedMainWindow->show(); + // Trigger adjustMDIFormPositions() delayed as viewport size is not yet known. + + if (m_state != StateInitializing) + QMetaObject::invokeMethod(this, "adjustMDIFormPositions", Qt::QueuedConnection); +} + +void QDesignerWorkbench::adjustMDIFormPositions() +{ + const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + const PositionMap::const_iterator pit = m_Positions.constFind(fw); + if (pit != m_Positions.constEnd()) + pit->applyTo(mdiSubWindowOf(fw), mdiAreaOffset); + } +} + +void QDesignerWorkbench::switchToTopLevelMode() +{ + if (m_mode == TopLevelMode) + return; + + // make sure that the widgetbox is visible if it is different from neutral. + QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); + Q_ASSERT(widgetBoxWrapper); + if (!widgetBoxWrapper->action()->isChecked()) + widgetBoxWrapper->action()->trigger(); + + switchToNeutralMode(); + const QPoint desktopOffset = desktopGeometry().topLeft(); + m_mode = TopLevelMode; + + // The widget box is special, it gets the menubar and gets to be the main widget. + + m_core->setTopLevel(widgetBoxWrapper); +#ifndef Q_WS_MAC + widgetBoxWrapper->setMenuBar(m_globalMenuBar); + widgetBoxWrapper->action()->setVisible(false); + widgetBoxWrapper->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); + qDesigner->setMainWindow(widgetBoxWrapper); + widgetBoxWrapper->setWindowTitle(MainWindowBase::mainWindowTitle()); +#endif + + const QDesignerSettings settings(m_core); + m_topLevelData.toolbars = MainWindowBase::createToolBars(m_actionManager, false); + m_topLevelData.toolbarManager = new ToolBarManager(widgetBoxWrapper, widgetBoxWrapper, + m_toolbarMenu, m_actionManager, + m_topLevelData.toolbars, m_toolWindows); + const int toolBarCount = m_topLevelData.toolbars.size(); + for (int i = 0; i < toolBarCount; i++) { + widgetBoxWrapper->addToolBar(m_topLevelData.toolbars.at(i)); + if (i == 3) + widgetBoxWrapper->insertToolBarBreak(m_topLevelData.toolbars.at(i)); + } + m_topLevelData.toolbarManager->restoreState(settings.toolBarsState(m_mode), MainWindowBase::settingsVersion()); + widgetBoxWrapper->restoreState(settings.mainWindowState(m_mode), MainWindowBase::settingsVersion()); + + bool found_visible_window = false; + foreach (QDesignerToolWindow *tw, m_toolWindows) { + tw->setParent(magicalParent(tw), magicalWindowFlags(tw)); + settings.restoreGeometry(tw, tw->geometryHint()); + tw->action()->setChecked(tw->isVisible()); + found_visible_window |= tw->isVisible(); + } + + if (!widgetBoxWrapper->action()->isChecked()) + widgetBoxWrapper->action()->trigger(); + + if (!m_toolWindows.isEmpty() && !found_visible_window) + m_toolWindows.first()->show(); + + m_actionManager->setBringAllToFrontVisible(true); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + fw->setParent(magicalParent(fw), magicalWindowFlags(fw)); + fw->setAttribute(Qt::WA_DeleteOnClose, true); + const PositionMap::const_iterator pit = m_Positions.constFind(fw); + if (pit != m_Positions.constEnd()) pit->applyTo(fw, desktopOffset); + // Force an activate in order to refresh minimumSize, otherwise it will not be respected + if (QLayout *layout = fw->layout()) + layout->invalidate(); + if (QWidget *mainContainer = fw->editor()->mainContainer()) + resizeForm(fw, mainContainer); + } +} + +QDesignerFormWindowManagerInterface *QDesignerWorkbench::formWindowManager() const +{ + return m_core->formWindowManager(); +} + +QDesignerFormEditorInterface *QDesignerWorkbench::core() const +{ + return m_core; +} + +int QDesignerWorkbench::toolWindowCount() const +{ + return m_toolWindows.count(); +} + +QDesignerToolWindow *QDesignerWorkbench::toolWindow(int index) const +{ + return m_toolWindows.at(index); +} + +int QDesignerWorkbench::formWindowCount() const +{ + return m_formWindows.count(); +} + +QDesignerFormWindow *QDesignerWorkbench::formWindow(int index) const +{ + return m_formWindows.at(index); +} + +QRect QDesignerWorkbench::desktopGeometry() const +{ + // Return geometry of the desktop designer is running in. + QWidget *widget = 0; + switch (m_mode) { + case DockedMode: + widget = m_dockedMainWindow; + break; + case TopLevelMode: + widget = widgetBoxToolWindow(); + break; + case NeutralMode: + break; + } + const QDesktopWidget *desktop = qApp->desktop(); + const int screenNumber = widget ? desktop->screenNumber(widget) : 0; + return desktop->availableGeometry(screenNumber); +} + +QRect QDesignerWorkbench::availableGeometry() const +{ + if (m_mode == DockedMode) + return m_dockedMainWindow->mdiArea()->geometry(); + + const QDesktopWidget *desktop = qDesigner->desktop(); + return desktop->availableGeometry(desktop->screenNumber(widgetBoxToolWindow())); +} + +int QDesignerWorkbench::marginHint() const +{ return 20; +} + +void QDesignerWorkbench::slotFormWindowActivated(QDesignerFormWindow* fw) +{ + core()->formWindowManager()->setActiveFormWindow(fw->editor()); +} + +void QDesignerWorkbench::removeFormWindow(QDesignerFormWindow *formWindow) +{ + QDesignerFormWindowInterface *editor = formWindow->editor(); + const bool loadOk = editor->mainContainer(); + updateBackup(editor); + const int index = m_formWindows.indexOf(formWindow); + if (index != -1) { + m_formWindows.removeAt(index); + } + + if (QAction *action = formWindow->action()) { + m_windowActions->removeAction(action); + m_windowMenu->removeAction(action); + } + + if (m_formWindows.empty()) { + m_actionManager->setWindowListSeparatorVisible(false); + // Show up new form dialog unless closing + if (loadOk && m_state == StateUp + && QDesignerSettings(m_core).showNewFormOnStartup()) { + QTimer::singleShot(200, m_actionManager, SLOT(createForm())); + } + } +} + +void QDesignerWorkbench::initializeCorePlugins() +{ + QList<QObject*> plugins = QPluginLoader::staticInstances(); + plugins += core()->pluginManager()->instances(); + + foreach (QObject *plugin, plugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) { + if (!formEditorPlugin->isInitialized()) + formEditorPlugin->initialize(core()); + } + } +} + +void QDesignerWorkbench::saveSettings() const +{ + QDesignerSettings settings(m_core); + settings.clearBackup(); + saveGeometries(settings); + AppFontWidget::save(m_core->settingsManager(), QLatin1String(appFontPrefixC)); +} + +void QDesignerWorkbench::saveGeometries(QDesignerSettings &settings) const +{ + switch (m_mode) { + case DockedMode: + m_dockedMainWindow->saveSettings(settings); + break; + case TopLevelMode: + settings.setToolBarsState(m_mode, m_topLevelData.toolbarManager->saveState(MainWindowBase::settingsVersion())); + settings.setMainWindowState(m_mode, widgetBoxToolWindow()->saveState(MainWindowBase::settingsVersion())); + foreach (const QDesignerToolWindow *tw, m_toolWindows) + settings.saveGeometryFor(tw); + break; + case NeutralMode: + break; + } +} + +void QDesignerWorkbench::slotFileDropped(const QString &f) +{ + readInForm(f); +} + +bool QDesignerWorkbench::readInForm(const QString &fileName) const +{ + return m_actionManager->readInForm(fileName); +} + +bool QDesignerWorkbench::writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const +{ + return m_actionManager->writeOutForm(formWindow, fileName); +} + +bool QDesignerWorkbench::saveForm(QDesignerFormWindowInterface *frm) +{ + return m_actionManager->saveForm(frm); +} + +QDesignerFormWindow *QDesignerWorkbench::findFormWindow(QWidget *widget) const +{ + foreach (QDesignerFormWindow *formWindow, m_formWindows) { + if (formWindow->editor() == widget) + return formWindow; + } + + return 0; +} + +bool QDesignerWorkbench::handleClose() +{ + m_state = StateClosing; + QList<QDesignerFormWindow *> dirtyForms; + foreach (QDesignerFormWindow *w, m_formWindows) { + if (w->editor()->isDirty()) + dirtyForms << w; + } + + if (dirtyForms.size()) { + if (dirtyForms.size() == 1) { + if (!dirtyForms.at(0)->close()) { + m_state = StateUp; + return false; + } + } else { + int count = dirtyForms.size(); + QMessageBox box(QMessageBox::Warning, tr("Save Forms?"), + tr("There are %n forms with unsaved changes." + " Do you want to review these changes before quitting?", "", count), + QMessageBox::Cancel | QMessageBox::Discard | QMessageBox::Save); + box.setInformativeText(tr("If you do not review your documents, all your changes will be lost.")); + box.button(QMessageBox::Discard)->setText(tr("Discard Changes")); + QPushButton *save = static_cast<QPushButton *>(box.button(QMessageBox::Save)); + save->setText(tr("Review Changes")); + box.setDefaultButton(save); + switch (box.exec()) { + case QMessageBox::Cancel: + m_state = StateUp; + return false; + case QMessageBox::Save: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->show(); + fw->raise(); + if (!fw->close()) { + m_state = StateUp; + return false; + } + } + break; + case QMessageBox::Discard: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->editor()->setDirty(false); + fw->setWindowModified(false); + } + break; + } + } + } + + foreach (QDesignerFormWindow *fw, m_formWindows) + fw->close(); + + saveSettings(); + return true; +} + +QDesignerActions *QDesignerWorkbench::actionManager() const +{ + return m_actionManager; +} + +void QDesignerWorkbench::updateWindowMenu(QDesignerFormWindowInterface *fwi) +{ + bool minimizeChecked = false; + bool minimizeEnabled = false; + QDesignerFormWindow *activeFormWindow = 0; + do { + if (!fwi) + break; + activeFormWindow = qobject_cast<QDesignerFormWindow *>(fwi->parentWidget()); + if (!activeFormWindow) + break; + + minimizeEnabled = true; + minimizeChecked = isFormWindowMinimized(activeFormWindow); + } while (false) ; + + m_actionManager->minimizeAction()->setEnabled(minimizeEnabled); + m_actionManager->minimizeAction()->setChecked(minimizeChecked); + + if (!m_formWindows.empty()) { + const QList<QDesignerFormWindow*>::const_iterator cend = m_formWindows.constEnd(); + for (QList<QDesignerFormWindow*>::const_iterator it = m_formWindows.constBegin(); it != cend; ++it) + (*it)->action()->setChecked(*it == activeFormWindow); + } +} + +void QDesignerWorkbench::formWindowActionTriggered(QAction *a) +{ + QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow *>(a->parentWidget()); + Q_ASSERT(fw); + + if (isFormWindowMinimized(fw)) + setFormWindowMinimized(fw, false); + + if (m_mode == DockedMode) { + if (QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(fw->parent())) { + m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWindow); + } + } else { + fw->activateWindow(); + fw->raise(); + } +} + +void QDesignerWorkbench::closeAllToolWindows() +{ + foreach (QDesignerToolWindow *tw, m_toolWindows) + tw->hide(); +} + +bool QDesignerWorkbench::readInBackup() +{ + const QMap<QString, QString> backupFileMap = QDesignerSettings(m_core).backup(); + if (backupFileMap.isEmpty()) + return false; + + const QMessageBox::StandardButton answer = + QMessageBox::question(0, tr("Backup Information"), + tr("The last session of Designer was not terminated correctly. " + "Backup files were left behind. Do you want to load them?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); + if (answer == QMessageBox::No) + return false; + + const QString modifiedPlaceHolder = QLatin1String("[*]"); + QMapIterator<QString, QString> it(backupFileMap); + while(it.hasNext()) { + it.next(); + + QString fileName = it.key(); + fileName.remove(modifiedPlaceHolder); + + if(m_actionManager->readInForm(it.value())) + formWindowManager()->activeFormWindow()->setFileName(fileName); + + } + return true; +} + +void QDesignerWorkbench::updateBackup(QDesignerFormWindowInterface* fwi) +{ + QString fwn = QDir::convertSeparators(fwi->fileName()); + if (fwn.isEmpty()) + fwn = fwi->parentWidget()->windowTitle(); + + QDesignerSettings settings(m_core); + QMap<QString, QString> map = settings.backup(); + map.remove(fwn); + settings.setBackup(map); +} + +namespace { + void raiseWindow(QWidget *w) { + if (w->isMinimized()) + w->setWindowState(w->windowState() & ~Qt::WindowMinimized); + w->raise(); + } +} + +void QDesignerWorkbench::bringAllToFront() +{ + if (m_mode != TopLevelMode) + return; + foreach(QDesignerToolWindow *tw, m_toolWindows) + raiseWindow(tw); + foreach(QDesignerFormWindow *dfw, m_formWindows) + raiseWindow(dfw); +} + +// Resize a form window taking MDI decorations into account +// Apply maximum size as there is no layout connection between +// the form's main container and the integration's outer +// container due to the tool widget stack. + +void QDesignerWorkbench::resizeForm(QDesignerFormWindow *fw, const QWidget *mainContainer) const +{ + const QSize containerSize = mainContainer->size(); + const QSize containerMinimumSize = mainContainer->minimumSize(); + const QSize containerMaximumSize = mainContainer->maximumSize(); + if (m_mode != DockedMode) { + fw->resize(containerSize); + fw->setMaximumSize(containerMaximumSize); + return; + } + // get decorations and resize MDI + QMdiSubWindow *mdiSubWindow = qobject_cast<QMdiSubWindow *>(fw->parent()); + Q_ASSERT(mdiSubWindow); + const QSize decorationSize = mdiSubWindow->geometry().size() - mdiSubWindow->contentsRect().size(); + mdiSubWindow->resize(containerSize + decorationSize); + // In Qt::RightToLeft mode, the window can grow to be partially hidden by the right border. + const int mdiAreaWidth = m_dockedMainWindow->mdiArea()->width(); + if (qApp->layoutDirection() == Qt::RightToLeft && mdiSubWindow->geometry().right() >= mdiAreaWidth) + mdiSubWindow->move(mdiAreaWidth - mdiSubWindow->width(), mdiSubWindow->pos().y()); + + if (containerMaximumSize == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) { + mdiSubWindow->setMaximumSize(containerMaximumSize); + } else { + mdiSubWindow->setMaximumSize(containerMaximumSize + decorationSize); + } +} + + +// Load a form or return 0 and do cleanup. file name and editor file +// name in case of loading a template file. + +QDesignerFormWindow * QDesignerWorkbench::loadForm(const QString &fileName, + bool detectLineTermiantorMode, + bool *uic3Converted, + QString *errorMessage) +{ + QFile file(fileName); + + qdesigner_internal::FormWindowBase::LineTerminatorMode mode = qdesigner_internal::FormWindowBase::NativeLineTerminator; + + if (detectLineTermiantorMode) { + if (file.open(QFile::ReadOnly)) { + const QString text = QString::fromUtf8(file.readLine()); + file.close(); + + const int lf = text.indexOf(QLatin1Char('\n')); + if (lf > 0 && text.at(lf-1) == QLatin1Char('\r')) { + mode = qdesigner_internal::FormWindowBase::CRLFLineTerminator; + } else if (lf >= 0) { + mode = qdesigner_internal::FormWindowBase::LFLineTerminator; + } + } + } + + if (!file.open(QFile::ReadOnly|QFile::Text)) { + *errorMessage = tr("The file <b>%1</b> could not be opened.").arg(file.fileName()); + return 0; + } + + + // Create a form + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); + + QDesignerFormWindow *formWindow = new QDesignerFormWindow(/*formWindow=*/ 0, this); + addFormWindow(formWindow); + QDesignerFormWindowInterface *editor = formWindow->editor(); + Q_ASSERT(editor); + + // Temporarily set the file name. It is needed when converting a UIC 3 file. + // In this case, the file name will we be cleared on return to force a save box. + editor->setFileName(fileName); + editor->setContents(&file); + + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(editor)) + fwb->setLineTerminatorMode(mode); + + switch (m_mode) { + case DockedMode: { + // below code must be after above call to setContents(), because setContents() may popup warning dialogs which would cause + // mdi sub window activation (because of dialogs internal call to processEvent or such) + // That activation could have worse consequences, e.g. NULL resource set for active form) before the form is loaded + QMdiSubWindow *subWin = m_dockedMainWindow->createMdiSubWindow(formWindow, magicalWindowFlags(formWindow), m_actionManager->closeFormAction()->shortcut()); + m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWin); + } + break; + case TopLevelMode: { + const QRect formWindowGeometryHint = formWindow->geometryHint(); + formWindow->setAttribute(Qt::WA_DeleteOnClose, true); + formWindow->setParent(magicalParent(formWindow), magicalWindowFlags(formWindow)); + formWindow->resize(formWindowGeometryHint.size()); + formWindow->move(availableGeometry().center() - formWindowGeometryHint.center()); + } + break; + case NeutralMode: + break; + } + + if (!editor->mainContainer()) { + removeFormWindow(formWindow); + formWindowManager->removeFormWindow(editor); + m_core->metaDataBase()->remove(editor); + *errorMessage = tr("The file <b>%1</b> is not a valid Designer ui file.").arg(file.fileName()); + return 0; + } + *uic3Converted = editor->fileName().isEmpty(); + editor->setDirty(false); + resizeForm(formWindow, editor->mainContainer()); + formWindowManager->setActiveFormWindow(editor); + return formWindow; +} + + +QDesignerFormWindow * QDesignerWorkbench::openForm(const QString &fileName, QString *errorMessage) +{ + bool uic3Converted; + QDesignerFormWindow *rc =loadForm(fileName, true, &uic3Converted, errorMessage); + if (!rc) + return 0; + + if (!uic3Converted) + rc->editor()->setFileName(fileName); + rc->firstShow(); + return rc; +} + +QDesignerFormWindow * QDesignerWorkbench::openTemplate(const QString &templateFileName, + const QString &editorFileName, + QString *errorMessage) +{ + bool uic3Converted; + QDesignerFormWindow *rc =loadForm(templateFileName, false, &uic3Converted, errorMessage); + if (!rc) + return 0; + + if (!uic3Converted) + rc->editor()->setFileName(editorFileName); + + rc->firstShow(); + return rc; +} + +void QDesignerWorkbench::minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized) +{ + // refresh the minimize action state + if (core()->formWindowManager()->activeFormWindow() == formWindow) { + m_actionManager->minimizeAction()->setChecked(minimized); + } +} + +void QDesignerWorkbench::toggleFormMinimizationState() +{ + QDesignerFormWindowInterface *fwi = core()->formWindowManager()->activeFormWindow(); + if (!fwi || m_mode == NeutralMode) + return; + QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow *>(fwi->parentWidget()); + Q_ASSERT(fw); + setFormWindowMinimized(fw, !isFormWindowMinimized(fw)); +} + +bool QDesignerWorkbench::isFormWindowMinimized(const QDesignerFormWindow *fw) +{ + switch (m_mode) { + case DockedMode: + return mdiSubWindowOf(fw)->isShaded(); + case TopLevelMode: + return fw->window()->isMinimized(); + default: + break; + } + return fw->isMinimized(); +} + +void QDesignerWorkbench::setFormWindowMinimized(QDesignerFormWindow *fw, bool minimized) +{ + switch (m_mode) { + case DockedMode: { + QMdiSubWindow *mdiSubWindow = mdiSubWindowOf(fw); + if (minimized) { + mdiSubWindow->showShaded(); + } else { + mdiSubWindow->setWindowState(mdiSubWindow->windowState() & ~Qt::WindowMinimized); + } + } + break; + case TopLevelMode: { + QWidget *window = fw->window(); + if (window->isMinimized()) { + window->setWindowState(window->windowState() & ~Qt::WindowMinimized); + } else { + window->showMinimized(); + } + } + break; + default: + break; + } +} + +void QDesignerWorkbench::restoreUISettings() +{ + UIMode mode = QDesignerSettings(m_core).uiMode(); + switch (mode) { + case TopLevelMode: + switchToTopLevelMode(); + break; + case DockedMode: + switchToDockedMode(); + break; + + default: Q_ASSERT(0); + } + + ToolWindowFontSettings fontSettings = QDesignerSettings(m_core).toolWindowFont(); + const QFont &font = fontSettings.m_useFont ? fontSettings.m_font : qApp->font(); + + if (font == m_toolWindows.front()->font()) + return; + + foreach(QDesignerToolWindow *tw, m_toolWindows) + tw->setFont(font); +} + +void QDesignerWorkbench::handleCloseEvent(QCloseEvent *ev) +{ + ev->setAccepted(handleClose()); + if (ev->isAccepted()) + QMetaObject::invokeMethod(qDesigner, "quit", Qt::QueuedConnection); // We're going down! +} + +QDesignerToolWindow *QDesignerWorkbench::widgetBoxToolWindow() const +{ + return m_toolWindows.at(QDesignerToolWindow::WidgetBox); +} + +QT_END_NAMESPACE |