290 lines
9.9 KiB
C++
290 lines
9.9 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2010 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$
|
|
** Commercial Usage
|
|
** 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.
|
|
**
|
|
** 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.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.
|
|
**
|
|
** If you have questions regarding the use of this file, please contact
|
|
** Nokia at qt-info@nokia.com.
|
|
** $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
|