| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the Qt Designer of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** 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.1, 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. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qdesigner_formwindow.h" |
| #include "qdesigner_workbench.h" |
| #include "formwindowbase_p.h" |
| |
| // sdk |
| #include <QtDesigner/QDesignerFormWindowInterface> |
| #include <QtDesigner/QDesignerFormEditorInterface> |
| #include <QtDesigner/QDesignerPropertySheetExtension> |
| #include <QtDesigner/QDesignerPropertyEditorInterface> |
| #include <QtDesigner/QDesignerFormWindowManagerInterface> |
| #include <QtDesigner/QDesignerTaskMenuExtension> |
| #include <QtDesigner/QExtensionManager> |
| |
| #include <QtCore/QEvent> |
| #include <QtCore/QFile> |
| |
| #include <QtGui/QAction> |
| #include <QtGui/QCloseEvent> |
| #include <QtGui/QFileDialog> |
| #include <QtGui/QMessageBox> |
| #include <QtGui/QPushButton> |
| #include <QtGui/QVBoxLayout> |
| #include <QtGui/QUndoCommand> |
| #include <QtGui/QWindowStateChangeEvent> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QDesignerFormWindow::QDesignerFormWindow(QDesignerFormWindowInterface *editor, QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags) |
| : QWidget(parent, flags), |
| m_editor(editor), |
| m_workbench(workbench), |
| m_action(new QAction(this)), |
| m_initialized(false), |
| m_windowTitleInitialized(false) |
| { |
| Q_ASSERT(workbench); |
| |
| setMaximumSize(0xFFF, 0xFFF); |
| QDesignerFormEditorInterface *core = workbench->core(); |
| |
| if (m_editor) { |
| m_editor->setParent(this); |
| } else { |
| m_editor = core->formWindowManager()->createFormWindow(this); |
| } |
| |
| QVBoxLayout *l = new QVBoxLayout(this); |
| l->setMargin(0); |
| l->addWidget(m_editor); |
| |
| m_action->setCheckable(true); |
| |
| connect(m_editor->commandHistory(), SIGNAL(indexChanged(int)), this, SLOT(updateChanged())); |
| connect(m_editor, SIGNAL(geometryChanged()), this, SLOT(geometryChanged())); |
| qdesigner_internal::FormWindowBase::setupDefaultAction(m_editor); |
| } |
| |
| QDesignerFormWindow::~QDesignerFormWindow() |
| { |
| if (workbench()) |
| workbench()->removeFormWindow(this); |
| } |
| |
| QAction *QDesignerFormWindow::action() const |
| { |
| return m_action; |
| } |
| |
| void QDesignerFormWindow::changeEvent(QEvent *e) |
| { |
| switch (e->type()) { |
| case QEvent::WindowTitleChange: |
| m_action->setText(windowTitle().remove(QLatin1String("[*]"))); |
| break; |
| case QEvent::WindowIconChange: |
| m_action->setIcon(windowIcon()); |
| break; |
| case QEvent::WindowStateChange: { |
| const QWindowStateChangeEvent *wsce = static_cast<const QWindowStateChangeEvent *>(e); |
| const bool wasMinimized = Qt::WindowMinimized & wsce->oldState(); |
| const bool isMinimizedNow = isMinimized(); |
| if (wasMinimized != isMinimizedNow ) |
| emit minimizationStateChanged(m_editor, isMinimizedNow); |
| } |
| break; |
| default: |
| break; |
| } |
| QWidget::changeEvent(e); |
| } |
| |
| QRect QDesignerFormWindow::geometryHint() const |
| { |
| const QPoint point(0, 0); |
| // If we have a container, we want to be just as big. |
| // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes. |
| if (QWidget *mainContainer = m_editor->mainContainer()) |
| return QRect(point, mainContainer->size()); |
| |
| return QRect(point, sizeHint()); |
| } |
| |
| QDesignerFormWindowInterface *QDesignerFormWindow::editor() const |
| { |
| return m_editor; |
| } |
| |
| QDesignerWorkbench *QDesignerFormWindow::workbench() const |
| { |
| return m_workbench; |
| } |
| |
| void QDesignerFormWindow::firstShow() |
| { |
| // Set up handling of file name changes and set initial title. |
| if (!m_windowTitleInitialized) { |
| m_windowTitleInitialized = true; |
| if (m_editor) { |
| connect(m_editor, SIGNAL(fileNameChanged(QString)), this, SLOT(updateWindowTitle(QString))); |
| updateWindowTitle(m_editor->fileName()); |
| } |
| } |
| show(); |
| } |
| |
| int QDesignerFormWindow::getNumberOfUntitledWindows() const |
| { |
| const int totalWindows = m_workbench->formWindowCount(); |
| if (!totalWindows) |
| return 0; |
| |
| int maxUntitled = 0; |
| // Find the number of untitled windows excluding ourselves. |
| // Do not fall for 'untitled.ui', match with modified place holder. |
| // This will cause some problems with i18n, but for now I need the string to be "static" |
| QRegExp rx(QLatin1String("untitled( (\\d+))?\\[\\*\\]")); |
| for (int i = 0; i < totalWindows; ++i) { |
| QDesignerFormWindow *fw = m_workbench->formWindow(i); |
| if (fw != this) { |
| const QString title = m_workbench->formWindow(i)->windowTitle(); |
| if (rx.indexIn(title) != -1) { |
| if (maxUntitled == 0) |
| ++maxUntitled; |
| if (rx.captureCount() > 1) { |
| const QString numberCapture = rx.cap(2); |
| if (!numberCapture.isEmpty()) |
| maxUntitled = qMax(numberCapture.toInt(), maxUntitled); |
| } |
| } |
| } |
| } |
| return maxUntitled; |
| } |
| |
| void QDesignerFormWindow::updateWindowTitle(const QString &fileName) |
| { |
| if (!m_windowTitleInitialized) { |
| m_windowTitleInitialized = true; |
| if (m_editor) |
| connect(m_editor, SIGNAL(fileNameChanged(QString)), this, SLOT(updateWindowTitle(QString))); |
| } |
| |
| QString fileNameTitle; |
| if (fileName.isEmpty()) { |
| fileNameTitle = QLatin1String("untitled"); |
| if (const int maxUntitled = getNumberOfUntitledWindows()) { |
| fileNameTitle += QLatin1Char(' '); |
| fileNameTitle += QString::number(maxUntitled + 1); |
| } |
| } else { |
| fileNameTitle = QFileInfo(fileName).fileName(); |
| } |
| |
| if (const QWidget *mc = m_editor->mainContainer()) { |
| setWindowIcon(mc->windowIcon()); |
| setWindowTitle(tr("%1 - %2[*]").arg(mc->windowTitle()).arg(fileNameTitle)); |
| } else { |
| setWindowTitle(fileNameTitle); |
| } |
| } |
| |
| void QDesignerFormWindow::closeEvent(QCloseEvent *ev) |
| { |
| if (m_editor->isDirty()) { |
| raise(); |
| QMessageBox box(QMessageBox::Information, tr("Save Form?"), |
| tr("Do you want to save the changes to this document before closing?"), |
| QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save, m_editor); |
| box.setInformativeText(tr("If you don't save, your changes will be lost.")); |
| box.setWindowModality(Qt::WindowModal); |
| static_cast<QPushButton *>(box.button(QMessageBox::Save))->setDefault(true); |
| |
| switch (box.exec()) { |
| case QMessageBox::Save: { |
| bool ok = workbench()->saveForm(m_editor); |
| ev->setAccepted(ok); |
| m_editor->setDirty(!ok); |
| break; |
| } |
| case QMessageBox::Discard: |
| m_editor->setDirty(false); // Not really necessary, but stops problems if we get close again. |
| ev->accept(); |
| break; |
| case QMessageBox::Cancel: |
| ev->ignore(); |
| break; |
| } |
| } |
| } |
| |
| void QDesignerFormWindow::updateChanged() |
| { |
| // Sometimes called after form window destruction. |
| if (m_editor) { |
| setWindowModified(m_editor->isDirty()); |
| updateWindowTitle(m_editor->fileName()); |
| } |
| } |
| |
| void QDesignerFormWindow::resizeEvent(QResizeEvent *rev) |
| { |
| if(m_initialized) { |
| m_editor->setDirty(true); |
| setWindowModified(true); |
| } |
| |
| m_initialized = true; |
| QWidget::resizeEvent(rev); |
| } |
| |
| void QDesignerFormWindow::geometryChanged() |
| { |
| // If the form window changes, re-update the geometry of the current widget in the property editor. |
| // Note that in the case of layouts, non-maincontainer widgets must also be updated, |
| // so, do not do it for the main container only |
| const QDesignerFormEditorInterface *core = m_editor->core(); |
| QObject *object = core->propertyEditor()->object(); |
| if (object == 0 || !object->isWidgetType()) |
| return; |
| static const QString geometryProperty = QLatin1String("geometry"); |
| const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), object); |
| const int geometryIndex = sheet->indexOf(geometryProperty); |
| if (geometryIndex == -1) |
| return; |
| core->propertyEditor()->setPropertyValue(geometryProperty, sheet->property(geometryIndex)); |
| } |
| |
| QT_END_NAMESPACE |