blob: 440a8d61b560f5b185724419d3b159b2bc104adf [file] [log] [blame]
/****************************************************************************
**
** 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