diff options
Diffstat (limited to 'src/designer/src/designer')
47 files changed, 8314 insertions, 0 deletions
diff --git a/src/designer/src/designer/Info_mac.plist b/src/designer/src/designer/Info_mac.plist new file mode 100644 index 000000000..f19176fa7 --- /dev/null +++ b/src/designer/src/designer/Info_mac.plist @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> +<plist version="0.9"> +<dict> + <key>CFBundleIconFile</key> + <string>@ICON@</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleIdentifier</key> + <string>com.trolltech.Designer</string> + <key>CFBundleSignature</key> + <string>ttxt</string> + <key>CFBundleExecutable</key> + <string>@EXECUTABLE@</string> + <key>CFBundleDocumentTypes</key> + <array> + <dict> + <key>CFBundleTypeExtensions</key> + <array> + <string>ui</string> + </array> + <key>CFBundleTypeIconFile</key> + <string>uifile.icns</string> + <key>CFBundleTypeRole</key> + <string>Editor</string> + <key>LSIsAppleDefaultForType</key> + <true/> + </dict> + </array> + <key>NOTE</key> + <string>Qt/Designer by Nokia Corporation and/or its subsidiary(-ies)</string> +</dict> +</plist> diff --git a/src/designer/src/designer/appfontdialog.cpp b/src/designer/src/designer/appfontdialog.cpp new file mode 100644 index 000000000..00b91fa0d --- /dev/null +++ b/src/designer/src/designer/appfontdialog.cpp @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "appfontdialog.h" + +#include <iconloader_p.h> +#include <abstractsettings_p.h> + +#include <QtGui/QTreeView> +#include <QtGui/QToolButton> +#include <QtGui/QHBoxLayout> +#include <QtGui/QVBoxLayout> +#include <QtGui/QSpacerItem> +#include <QtGui/QFileDialog> +#include <QtGui/QStandardItemModel> +#include <QtGui/QMessageBox> +#include <QtGui/QFontDatabase> +#include <QtGui/QDialogButtonBox> + +#include <QtCore/QSettings> +#include <QtCore/QCoreApplication> +#include <QtCore/QStringList> +#include <QtCore/QFileInfo> +#include <QtCore/QtAlgorithms> +#include <QtCore/QVector> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +enum {FileNameRole = Qt::UserRole + 1, IdRole = Qt::UserRole + 2 }; +enum { debugAppFontWidget = 0 }; + +static const char fontFileKeyC[] = "fontFiles"; + +// AppFontManager: Singleton that maintains the mapping of loaded application font +// ids to the file names (which are not stored in QFontDatabase) +// and provides API for loading/unloading fonts as well for saving/restoring settings. + +class AppFontManager +{ + Q_DISABLE_COPY(AppFontManager) + AppFontManager(); +public: + static AppFontManager &instance(); + + void save(QDesignerSettingsInterface *s, const QString &prefix) const; + void restore(const QDesignerSettingsInterface *s, const QString &prefix); + + // Return id or -1 + int add(const QString &fontFile, QString *errorMessage); + + bool remove(int id, QString *errorMessage); + bool remove(const QString &fontFile, QString *errorMessage); + bool removeAt(int index, QString *errorMessage); + + // Store loaded fonts as pair of file name and Id + typedef QPair<QString,int> FileNameFontIdPair; + typedef QList<FileNameFontIdPair> FileNameFontIdPairs; + const FileNameFontIdPairs &fonts() const; + +private: + FileNameFontIdPairs m_fonts; +}; + +AppFontManager::AppFontManager() +{ +} + +AppFontManager &AppFontManager::instance() +{ + static AppFontManager rc; + return rc; +} + +void AppFontManager::save(QDesignerSettingsInterface *s, const QString &prefix) const +{ + // Store as list of file names + QStringList fontFiles; + const FileNameFontIdPairs::const_iterator cend = m_fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = m_fonts.constBegin(); it != cend; ++it) + fontFiles.push_back(it->first); + + s->beginGroup(prefix); + s->setValue(QLatin1String(fontFileKeyC), fontFiles); + s->endGroup(); + + if (debugAppFontWidget) + qDebug() << "AppFontManager::saved" << fontFiles.size() << "fonts under " << prefix; +} + +void AppFontManager::restore(const QDesignerSettingsInterface *s, const QString &prefix) +{ + QString key = prefix; + key += QLatin1Char('/'); + key += QLatin1String(fontFileKeyC); + const QStringList fontFiles = s->value(key, QStringList()).toStringList(); + + if (debugAppFontWidget) + qDebug() << "AppFontManager::restoring" << fontFiles.size() << "fonts from " << prefix; + if (!fontFiles.empty()) { + QString errorMessage; + const QStringList::const_iterator cend = fontFiles.constEnd(); + for (QStringList::const_iterator it = fontFiles.constBegin(); it != cend; ++it) + if (add(*it, &errorMessage) == -1) + qWarning("%s", qPrintable(errorMessage)); + } +} + +int AppFontManager::add(const QString &fontFile, QString *errorMessage) +{ + const QFileInfo inf(fontFile); + if (!inf.isFile()) { + *errorMessage = QCoreApplication::translate("AppFontManager", "'%1' is not a file.").arg(fontFile); + return -1; + } + if (!inf.isReadable()) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' does not have read permissions.").arg(fontFile); + return -1; + } + const QString fullPath = inf.absoluteFilePath(); + // Check if already loaded + const FileNameFontIdPairs::const_iterator cend = m_fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = m_fonts.constBegin(); it != cend; ++it) { + if (it->first == fullPath) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' is already loaded.").arg(fontFile); + return -1; + } + } + + const int id = QFontDatabase::addApplicationFont(fullPath); + if (id == -1) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' could not be loaded.").arg(fontFile); + return -1; + } + + if (debugAppFontWidget) + qDebug() << "AppFontManager::add" << fontFile << id; + m_fonts.push_back(FileNameFontIdPair(fullPath, id)); + return id; +} + +bool AppFontManager::remove(int id, QString *errorMessage) +{ + const int count = m_fonts.size(); + for (int i = 0; i < count; i++) + if (m_fonts[i].second == id) + return removeAt(i, errorMessage); + + *errorMessage = QCoreApplication::translate("AppFontManager", "'%1' is not a valid font id.").arg(id); + return false; +} + +bool AppFontManager::remove(const QString &fontFile, QString *errorMessage) +{ + const int count = m_fonts.size(); + for (int i = 0; i < count; i++) + if (m_fonts[i].first == fontFile) + return removeAt(i, errorMessage); + + *errorMessage = QCoreApplication::translate("AppFontManager", "There is no loaded font matching the id '%1'.").arg(fontFile); + return false; +} + +bool AppFontManager::removeAt(int index, QString *errorMessage) +{ + Q_ASSERT(index >= 0 && index < m_fonts.size()); + + const QString fontFile = m_fonts[index].first; + const int id = m_fonts[index].second; + + if (debugAppFontWidget) + qDebug() << "AppFontManager::removeAt" << index << '(' << fontFile << id << ')'; + + if (!QFontDatabase::removeApplicationFont(id)) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font '%1' (%2) could not be unloaded.").arg(fontFile).arg(id); + return false; + } + m_fonts.removeAt(index); + return true; +} + +const AppFontManager::FileNameFontIdPairs &AppFontManager::fonts() const +{ + return m_fonts; +} + +// ------------- AppFontModel +class AppFontModel : public QStandardItemModel { + Q_DISABLE_COPY(AppFontModel) +public: + AppFontModel(QObject *parent = 0); + + void init(const AppFontManager &mgr); + void add(const QString &fontFile, int id); + int idAt(const QModelIndex &idx) const; +}; + +AppFontModel::AppFontModel(QObject * parent) : + QStandardItemModel(parent) +{ + setHorizontalHeaderLabels(QStringList(AppFontWidget::tr("Fonts"))); +} + +void AppFontModel::init(const AppFontManager &mgr) +{ + typedef AppFontManager::FileNameFontIdPairs FileNameFontIdPairs; + + const FileNameFontIdPairs &fonts = mgr.fonts(); + const FileNameFontIdPairs::const_iterator cend = fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = fonts.constBegin(); it != cend; ++it) + add(it->first, it->second); +} + +void AppFontModel::add(const QString &fontFile, int id) +{ + const QFileInfo inf(fontFile); + // Root item with base name + QStandardItem *fileItem = new QStandardItem(inf.completeBaseName()); + const QString fullPath = inf.absoluteFilePath(); + fileItem->setData(fullPath, FileNameRole); + fileItem->setToolTip(fullPath); + fileItem->setData(id, IdRole); + fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + + appendRow(fileItem); + const QStringList families = QFontDatabase::applicationFontFamilies(id); + const QStringList::const_iterator cend = families.constEnd(); + for (QStringList::const_iterator it = families.constBegin(); it != cend; ++it) { + QStandardItem *familyItem = new QStandardItem(*it); + familyItem->setToolTip(fullPath); + familyItem->setFont(QFont(*it)); + familyItem->setFlags(Qt::ItemIsEnabled); + fileItem->appendRow(familyItem); + } +} + +int AppFontModel::idAt(const QModelIndex &idx) const +{ + if (const QStandardItem *item = itemFromIndex(idx)) + return item->data(IdRole).toInt(); + return -1; +} + +// ------------- AppFontWidget +AppFontWidget::AppFontWidget(QWidget *parent) : + QGroupBox(parent), + m_view(new QTreeView), + m_addButton(new QToolButton), + m_removeButton(new QToolButton), + m_removeAllButton(new QToolButton), + m_model(new AppFontModel(this)) +{ + m_model->init(AppFontManager::instance()); + m_view->setModel(m_model); + m_view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_view->expandAll(); + connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection))); + + m_addButton->setToolTip(tr("Add font files")); + m_addButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("plus.png"))); + connect(m_addButton, SIGNAL(clicked()), this, SLOT(addFiles())); + + m_removeButton->setEnabled(false); + m_removeButton->setToolTip(tr("Remove current font file")); + m_removeButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("minus.png"))); + connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveFiles())); + + m_removeAllButton->setToolTip(tr("Remove all font files")); + m_removeAllButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("editdelete.png"))); + connect(m_removeAllButton, SIGNAL(clicked()), this, SLOT(slotRemoveAll())); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(m_addButton); + hLayout->addWidget(m_removeButton); + hLayout->addWidget(m_removeAllButton); + hLayout->addItem(new QSpacerItem(0, 0,QSizePolicy::MinimumExpanding)); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(m_view); + vLayout->addLayout(hLayout); + setLayout(vLayout); +} + +void AppFontWidget::addFiles() +{ + const QStringList files = + QFileDialog::getOpenFileNames(this, tr("Add Font Files"), QString(), + tr("Font files (*.ttf)")); + if (files.empty()) + return; + + QString errorMessage; + + AppFontManager &fmgr = AppFontManager::instance(); + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + const int id = fmgr.add(*it, &errorMessage); + if (id != -1) { + m_model->add(*it, id); + } else { + QMessageBox::critical(this, tr("Error Adding Fonts"), errorMessage); + } + } + m_view->expandAll(); +} + +static void removeFonts(const QModelIndexList &selectedIndexes, AppFontModel *model, QWidget *dialogParent) +{ + if (selectedIndexes.empty()) + return; + + // Reverse sort top level rows and remove + AppFontManager &fmgr = AppFontManager::instance(); + QVector<int> rows; + rows.reserve(selectedIndexes.size()); + + QString errorMessage; + const QModelIndexList::const_iterator cend = selectedIndexes.constEnd(); + for (QModelIndexList::const_iterator it = selectedIndexes.constBegin(); it != cend; ++it) { + const int id = model->idAt(*it); + if (id != -1) { + if (fmgr.remove(id, &errorMessage)) { + rows.push_back(it->row()); + } else { + QMessageBox::critical(dialogParent, AppFontWidget::tr("Error Removing Fonts"), errorMessage); + } + } + } + + qStableSort(rows.begin(), rows.end()); + for (int i = rows.size() - 1; i >= 0; i--) + model->removeRow(rows[i]); +} + +void AppFontWidget::slotRemoveFiles() +{ + removeFonts(m_view->selectionModel()->selectedIndexes(), m_model, this); +} + +void AppFontWidget::slotRemoveAll() +{ + const int count = m_model->rowCount(); + if (!count) + return; + + const QMessageBox::StandardButton answer = + QMessageBox::question(this, tr("Remove Fonts"), tr("Would you like to remove all fonts?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + if (answer == QMessageBox::No) + return; + + QModelIndexList topLevels; + for (int i = 0; i < count; i++) + topLevels.push_back(m_model->index(i, 0)); + removeFonts(topLevels, m_model, this); +} + +void AppFontWidget::selectionChanged(const QItemSelection &selected, const QItemSelection & /*deselected*/) +{ + m_removeButton->setEnabled(!selected.indexes().empty()); +} + +void AppFontWidget::save(QDesignerSettingsInterface *s, const QString &prefix) +{ + AppFontManager::instance().save(s, prefix); +} + +void AppFontWidget::restore(const QDesignerSettingsInterface *s, const QString &prefix) +{ + AppFontManager::instance().restore(s, prefix); +} + +// ------------ AppFontDialog +AppFontDialog::AppFontDialog(QWidget *parent) : + QDialog(parent), + m_appFontWidget(new AppFontWidget) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Additional Fonts")); + setModal(false); + QVBoxLayout *vl = new QVBoxLayout; + vl->addWidget(m_appFontWidget); + + QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close); + QDialog::connect(bb, SIGNAL(rejected()), this, SLOT(reject())); + vl->addWidget(bb); + setLayout(vl); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/appfontdialog.h b/src/designer/src/designer/appfontdialog.h new file mode 100644 index 000000000..a373217ac --- /dev/null +++ b/src/designer/src/designer/appfontdialog.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_APPFONTWIDGET_H +#define QDESIGNER_APPFONTWIDGET_H + +#include <QtGui/QGroupBox> +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class AppFontModel; + +class QTreeView; +class QToolButton; +class QItemSelection; +class QDesignerSettingsInterface; + +// AppFontWidget: Manages application fonts which the user can load and +// provides API for saving/restoring them. + +class AppFontWidget : public QGroupBox +{ + Q_DISABLE_COPY(AppFontWidget) + Q_OBJECT +public: + explicit AppFontWidget(QWidget *parent = 0); + + QStringList fontFiles() const; + + static void save(QDesignerSettingsInterface *s, const QString &prefix); + static void restore(const QDesignerSettingsInterface *s, const QString &prefix); + +private slots: + void addFiles(); + void slotRemoveFiles(); + void slotRemoveAll(); + void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + +private: + QTreeView *m_view; + QToolButton *m_addButton; + QToolButton *m_removeButton; + QToolButton *m_removeAllButton; + AppFontModel *m_model; +}; + +// AppFontDialog: Non modal dialog for AppFontWidget which has Qt::WA_DeleteOnClose set. + +class AppFontDialog : public QDialog +{ + Q_DISABLE_COPY(AppFontDialog) + Q_OBJECT +public: + explicit AppFontDialog(QWidget *parent = 0); + +private: + AppFontWidget *m_appFontWidget; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_APPFONTWIDGET_H diff --git a/src/designer/src/designer/assistantclient.cpp b/src/designer/src/designer/assistantclient.cpp new file mode 100644 index 000000000..0433c5c51 --- /dev/null +++ b/src/designer/src/designer/assistantclient.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "assistantclient.h" + +#include <QtCore/QString> +#include <QtCore/QProcess> +#include <QtCore/QDir> +#include <QtCore/QLibraryInfo> +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> +#include <QtCore/QObject> +#include <QtCore/QTextStream> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +enum { debugAssistantClient = 0 }; + +AssistantClient::AssistantClient() : + m_process(0) +{ +} + +AssistantClient::~AssistantClient() +{ + if (isRunning()) { + m_process->terminate(); + m_process->waitForFinished(); + } + delete m_process; +} + +bool AssistantClient::showPage(const QString &path, QString *errorMessage) +{ + QString cmd = QLatin1String("SetSource "); + cmd += path; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::activateIdentifier(const QString &identifier, QString *errorMessage) +{ + QString cmd = QLatin1String("ActivateIdentifier "); + cmd += identifier; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::activateKeyword(const QString &keyword, QString *errorMessage) +{ + QString cmd = QLatin1String("ActivateKeyword "); + cmd += keyword; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::sendCommand(const QString &cmd, QString *errorMessage) +{ + if (debugAssistantClient) + qDebug() << "sendCommand " << cmd; + if (!ensureRunning(errorMessage)) + return false; + if (!m_process->isWritable() || m_process->bytesToWrite() > 0) { + *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to send request: Assistant is not responding."); + return false; + } + QTextStream str(m_process); + str << cmd << QLatin1Char('\n') << endl; + return true; +} + +bool AssistantClient::isRunning() const +{ + return m_process && m_process->state() != QProcess::NotRunning; +} + +QString AssistantClient::binary() +{ + QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); +#if !defined(Q_OS_MAC) + app += QLatin1String("assistant"); +#else + app += QLatin1String("Assistant.app/Contents/MacOS/Assistant"); +#endif + +#if defined(Q_OS_WIN) + app += QLatin1String(".exe"); +#endif + + return app; +} + +bool AssistantClient::ensureRunning(QString *errorMessage) +{ + if (isRunning()) + return true; + + if (!m_process) + m_process = new QProcess; + + const QString app = binary(); + if (!QFileInfo(app).isFile()) { + *errorMessage = QCoreApplication::translate("AssistantClient", "The binary '%1' does not exist.").arg(app); + return false; + } + if (debugAssistantClient) + qDebug() << "Running " << app; + // run + QStringList args(QLatin1String("-enableRemoteControl")); + m_process->start(app, args); + if (!m_process->waitForStarted()) { + *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to launch assistant (%1).").arg(app); + return false; + } + return true; +} + +QString AssistantClient::documentUrl(const QString &prefix, int qtVersion) +{ + if (qtVersion == 0) + qtVersion = QT_VERSION; + QString rc; + QTextStream(&rc) << QLatin1String("qthelp://com.trolltech.") << prefix << QLatin1Char('.') + << (qtVersion >> 16) << ((qtVersion >> 8) & 0xFF) << (qtVersion & 0xFF) + << QLatin1String("/qdoc/"); + return rc; +} + +QString AssistantClient::designerManualUrl(int qtVersion) +{ + return documentUrl(QLatin1String("designer"), qtVersion); +} + +QString AssistantClient::qtReferenceManualUrl(int qtVersion) +{ + return documentUrl(QLatin1String("qt"), qtVersion); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/assistantclient.h b/src/designer/src/designer/assistantclient.h new file mode 100644 index 000000000..67257d191 --- /dev/null +++ b/src/designer/src/designer/assistantclient.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ASSISTANTCLIENT_H +#define ASSISTANTCLIENT_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QProcess; +class QString; + +class AssistantClient +{ + AssistantClient(const AssistantClient &); + AssistantClient &operator=(const AssistantClient &); + +public: + AssistantClient(); + ~AssistantClient(); + + bool showPage(const QString &path, QString *errorMessage); + bool activateIdentifier(const QString &identifier, QString *errorMessage); + bool activateKeyword(const QString &keyword, QString *errorMessage); + + bool isRunning() const; + + static QString documentUrl(const QString &prefix, int qtVersion = 0); + // Root of the Qt Designer documentation + static QString designerManualUrl(int qtVersion = 0); + // Root of the Qt Reference documentation + static QString qtReferenceManualUrl(int qtVersion = 0); + +private: + static QString binary(); + bool sendCommand(const QString &cmd, QString *errorMessage); + bool ensureRunning(QString *errorMessage); + + QProcess *m_process; +}; + +QT_END_NAMESPACE + +#endif // ASSISTANTCLIENT_H diff --git a/src/designer/src/designer/designer.icns b/src/designer/src/designer/designer.icns Binary files differnew file mode 100644 index 000000000..9940214fc --- /dev/null +++ b/src/designer/src/designer/designer.icns diff --git a/src/designer/src/designer/designer.ico b/src/designer/src/designer/designer.ico Binary files differnew file mode 100644 index 000000000..ef667333d --- /dev/null +++ b/src/designer/src/designer/designer.ico diff --git a/src/designer/src/designer/designer.pro b/src/designer/src/designer/designer.pro new file mode 100644 index 000000000..8564e96cb --- /dev/null +++ b/src/designer/src/designer/designer.pro @@ -0,0 +1,90 @@ + +DESTDIR = ../../../../bin +QT += xml network +contains(QT_CONFIG, script): QT += script +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +INCLUDEPATH += \ + ../lib/sdk \ + ../lib/extension \ + ../lib/shared \ + ../lib/uilib \ + extra + +QMAKE_LIBDIR += ../../lib ../../../../lib +LIBS += -lQtDesignerComponents -lQtDesigner + +RESOURCES += designer.qrc + +contains(CONFIG, static) { + DEFINES += QT_DESIGNER_STATIC +} + +TARGET = designer + +include(../../../shared/fontpanel/fontpanel.pri) +include(../../../shared/qttoolbardialog/qttoolbardialog.pri) + +HEADERS += \ + qdesigner.h \ + qdesigner_toolwindow.h \ + qdesigner_formwindow.h \ + qdesigner_workbench.h \ + qdesigner_settings.h \ + qdesigner_actions.h \ + qdesigner_server.h \ + qdesigner_appearanceoptions.h \ + saveformastemplate.h \ + newform.h \ + versiondialog.h \ + designer_enums.h \ + appfontdialog.h \ + preferencesdialog.h \ + assistantclient.h \ + mainwindow.h + +SOURCES += main.cpp \ + qdesigner.cpp \ + qdesigner_toolwindow.cpp \ + qdesigner_formwindow.cpp \ + qdesigner_workbench.cpp \ + qdesigner_settings.cpp \ + qdesigner_server.cpp \ + qdesigner_actions.cpp \ + qdesigner_appearanceoptions.cpp \ + saveformastemplate.cpp \ + newform.cpp \ + versiondialog.cpp \ + appfontdialog.cpp \ + preferencesdialog.cpp \ + assistantclient.cpp \ + mainwindow.cpp + +PRECOMPILED_HEADER=qdesigner_pch.h + +FORMS += saveformastemplate.ui \ + preferencesdialog.ui \ + qdesigner_appearanceoptions.ui + +win32 { + RC_FILE = designer.rc +} + +mac { + ICON = designer.icns + QMAKE_INFO_PLIST = Info_mac.plist + TARGET = Designer + FILETYPES.files = uifile.icns + FILETYPES.path = Contents/Resources + QMAKE_BUNDLE_DATA += FILETYPES +} + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +include(../sharedcomponents.pri) + +unix:!mac:LIBS += -lm diff --git a/src/designer/src/designer/designer.qrc b/src/designer/src/designer/designer.qrc new file mode 100644 index 000000000..fac8120d0 --- /dev/null +++ b/src/designer/src/designer/designer.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="/trolltech/designer"> + <file>images/designer.png</file> + </qresource> +</RCC> diff --git a/src/designer/src/designer/designer.rc b/src/designer/src/designer/designer.rc new file mode 100644 index 000000000..9c396b555 --- /dev/null +++ b/src/designer/src/designer/designer.rc @@ -0,0 +1,32 @@ +#include "winver.h" + +IDI_ICON1 ICON DISCARDABLE "designer.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Designer" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "designer" + VALUE "OriginalFilename", "designer.exe" + VALUE "ProductName", "Qt Designer" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/src/designer/src/designer/designer_enums.h b/src/designer/src/designer/designer_enums.h new file mode 100644 index 000000000..ca115c37a --- /dev/null +++ b/src/designer/src/designer/designer_enums.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERENUMS_H +#define DESIGNERENUMS_H + +enum UIMode +{ + NeutralMode, + TopLevelMode, + DockedMode +}; + +#endif // DESIGNERENUMS_H diff --git a/src/designer/src/designer/images/designer.png b/src/designer/src/designer/images/designer.png Binary files differnew file mode 100644 index 000000000..0988fcee3 --- /dev/null +++ b/src/designer/src/designer/images/designer.png diff --git a/src/designer/src/designer/images/mdi.png b/src/designer/src/designer/images/mdi.png Binary files differnew file mode 100644 index 000000000..5012ab304 --- /dev/null +++ b/src/designer/src/designer/images/mdi.png diff --git a/src/designer/src/designer/images/sdi.png b/src/designer/src/designer/images/sdi.png Binary files differnew file mode 100644 index 000000000..7fff6e8b6 --- /dev/null +++ b/src/designer/src/designer/images/sdi.png diff --git a/src/designer/src/designer/images/workbench.png b/src/designer/src/designer/images/workbench.png Binary files differnew file mode 100644 index 000000000..06716a44f --- /dev/null +++ b/src/designer/src/designer/images/workbench.png diff --git a/src/designer/src/designer/main.cpp b/src/designer/src/designer/main.cpp new file mode 100644 index 000000000..8a5b5c044 --- /dev/null +++ b/src/designer/src/designer/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include <QtCore/QLibraryInfo> +#include <QtCore/QDir> + +#include <stdlib.h> + +QT_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(designer); + + QDesigner app(argc, argv); + app.setQuitOnLastWindowClosed(false); + + return app.exec(); +} diff --git a/src/designer/src/designer/mainwindow.cpp b/src/designer/src/designer/mainwindow.cpp new file mode 100644 index 000000000..67e1a4053 --- /dev/null +++ b/src/designer/src/designer/mainwindow.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_workbench.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_settings.h" +#include "qttoolbardialog.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QCloseEvent> +#include <QtGui/QToolBar> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QStatusBar> +#include <QtGui/QMenu> +#include <QtGui/QLayout> +#include <QtGui/QDockWidget> + +#include <QtCore/QUrl> +#include <QtCore/QDebug> + +static const char *uriListMimeFormatC = "text/uri-list"; + +QT_BEGIN_NAMESPACE + +typedef QList<QAction *> ActionList; + +// Helpers for creating toolbars and menu + +static void addActionsToToolBar(const ActionList &actions, QToolBar *t) +{ + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { + QAction *action = *it; + if (action->property(QDesignerActions::defaultToolbarPropertyName).toBool()) + t->addAction(action); + } +} +static QToolBar *createToolBar(const QString &title, const QString &objectName, const ActionList &actions) +{ + QToolBar *rc = new QToolBar; + rc->setObjectName(objectName); + rc->setWindowTitle(title); + addActionsToToolBar(actions, rc); + return rc; +} + +// ---------------- MainWindowBase + +MainWindowBase::MainWindowBase(QWidget *parent, Qt::WindowFlags flags) : + QMainWindow(parent, flags), + m_policy(AcceptCloseEvents) +{ +#ifndef Q_WS_MAC + setWindowIcon(qDesigner->windowIcon()); +#endif +} + +void MainWindowBase::closeEvent(QCloseEvent *e) +{ + switch (m_policy) { + case AcceptCloseEvents: + QMainWindow::closeEvent(e); + break; + case EmitCloseEventSignal: + emit closeEventReceived(e); + break; + } +} + +QList<QToolBar *> MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar) +{ + // Note that whenever you want to add a new tool bar here, you also have to update the default + // action groups added to the toolbar manager in the mainwindow constructor + QList<QToolBar *> rc; + if (singleToolBar) { + //: Not currently used (main tool bar) + QToolBar *main = createToolBar(tr("Main"), QLatin1String("mainToolBar"), actions->fileActions()->actions()); + addActionsToToolBar(actions->editActions()->actions(), main); + addActionsToToolBar(actions->toolActions()->actions(), main); + addActionsToToolBar(actions->formActions()->actions(), main); + rc.push_back(main); + } else { + rc.push_back(createToolBar(tr("File"), QLatin1String("fileToolBar"), actions->fileActions()->actions())); + rc.push_back(createToolBar(tr("Edit"), QLatin1String("editToolBar"), actions->editActions()->actions())); + rc.push_back(createToolBar(tr("Tools"), QLatin1String("toolsToolBar"), actions->toolActions()->actions())); + rc.push_back(createToolBar(tr("Form"), QLatin1String("formToolBar"), actions->formActions()->actions())); + } + return rc; +} + +QString MainWindowBase::mainWindowTitle() +{ + return tr("Qt Designer"); +} + +// Use the minor Qt version as settings versions to avoid conflicts +int MainWindowBase::settingsVersion() +{ + const int version = QT_VERSION; + return (version & 0x00FF00) >> 8; +} + +// ----------------- DockedMdiArea + +DockedMdiArea::DockedMdiArea(const QString &extension, QWidget *parent) : + QMdiArea(parent), + m_extension(extension) +{ + setAcceptDrops(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +} + +QStringList DockedMdiArea::uiFiles(const QMimeData *d) const +{ + // Extract dropped UI files from Mime data. + QStringList rc; + if (!d->hasFormat(QLatin1String(uriListMimeFormatC))) + return rc; + const QList<QUrl> urls = d->urls(); + if (urls.empty()) + return rc; + const QList<QUrl>::const_iterator cend = urls.constEnd(); + for (QList<QUrl>::const_iterator it = urls.constBegin(); it != cend; ++it) { + const QString fileName = it->toLocalFile(); + if (!fileName.isEmpty() && fileName.endsWith(m_extension)) + rc.push_back(fileName); + } + return rc; +} + +bool DockedMdiArea::event(QEvent *event) +{ + // Listen for desktop file manager drop and emit a signal once a file is + // dropped. + switch (event->type()) { + case QEvent::DragEnter: { + QDragEnterEvent *e = static_cast<QDragEnterEvent*>(event); + if (!uiFiles(e->mimeData()).empty()) { + e->acceptProposedAction(); + return true; + } + } + break; + case QEvent::Drop: { + QDropEvent *e = static_cast<QDropEvent*>(event); + const QStringList files = uiFiles(e->mimeData()); + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + emit fileDropped(*it); + } + e->acceptProposedAction(); + return true; + } + break; + default: + break; + } + return QMdiArea::event(event); +} + +// ------------- ToolBarManager: + +static void addActionsToToolBarManager(const ActionList &al, const QString &title, QtToolBarManager *tbm) +{ + const ActionList::const_iterator cend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it) + tbm->addAction(*it, title); +} + +ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow, + QWidget *parent, + QMenu *toolBarMenu, + const QDesignerActions *actions, + const QList<QToolBar *> &toolbars, + const QList<QDesignerToolWindow*> &toolWindows) : + QObject(parent), + m_configureableMainWindow(configureableMainWindow), + m_parent(parent), + m_toolBarMenu(toolBarMenu), + m_manager(new QtToolBarManager(this)), + m_configureAction(new QAction(tr("Configure Toolbars..."), this)), + m_toolbars(toolbars) +{ + m_configureAction->setMenuRole(QAction::NoRole); + m_configureAction->setObjectName(QLatin1String("__qt_configure_tool_bars_action")); + connect(m_configureAction, SIGNAL(triggered()), this, SLOT(configureToolBars())); + + m_manager->setMainWindow(configureableMainWindow); + + foreach(QToolBar *tb, m_toolbars) { + const QString title = tb->windowTitle(); + m_manager->addToolBar(tb, title); + addActionsToToolBarManager(tb->actions(), title, m_manager); + } + + addActionsToToolBarManager(actions->windowActions()->actions(), tr("Window"), m_manager); + addActionsToToolBarManager(actions->helpActions()->actions(), tr("Help"), m_manager); + + // Filter out the device profile preview actions which have int data(). + ActionList previewActions = actions->styleActions()->actions(); + ActionList::iterator it = previewActions.begin(); + for ( ; (*it)->isSeparator() || (*it)->data().type() == QVariant::Int; ++it) ; + previewActions.erase(previewActions.begin(), it); + addActionsToToolBarManager(previewActions, tr("Style"), m_manager); + + const QString dockTitle = tr("Dock views"); + foreach (QDesignerToolWindow *tw, toolWindows) { + if (QAction *action = tw->action()) + m_manager->addAction(action, dockTitle); + } + + QString category(tr("File")); + foreach(QAction *action, actions->fileActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Edit"); + foreach(QAction *action, actions->editActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Tools"); + foreach(QAction *action, actions->toolActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Form"); + foreach(QAction *action, actions->formActions()->actions()) + m_manager->addAction(action, category); + + m_manager->addAction(m_configureAction, tr("Toolbars")); + updateToolBarMenu(); +} + +// sort function for sorting tool bars alphabetically by title [non-static since called from template] + +bool toolBarTitleLessThan(const QToolBar *t1, const QToolBar *t2) +{ + return t1->windowTitle() < t2->windowTitle(); +} + +void ToolBarManager::updateToolBarMenu() +{ + // Sort tool bars alphabetically by title + qStableSort(m_toolbars.begin(), m_toolbars.end(), toolBarTitleLessThan); + // add to menu + m_toolBarMenu->clear(); + foreach (QToolBar *tb, m_toolbars) + m_toolBarMenu->addAction(tb->toggleViewAction()); + m_toolBarMenu->addAction(m_configureAction); +} + +void ToolBarManager::configureToolBars() +{ + QtToolBarDialog dlg(m_parent); + dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint); + dlg.setToolBarManager(m_manager); + dlg.exec(); + updateToolBarMenu(); +} + +QByteArray ToolBarManager::saveState(int version) const +{ + return m_manager->saveState(version); +} + +bool ToolBarManager::restoreState(const QByteArray &state, int version) +{ + return m_manager->restoreState(state, version); +} + +// ---------- DockedMainWindow + +DockedMainWindow::DockedMainWindow(QDesignerWorkbench *wb, + QMenu *toolBarMenu, + const QList<QDesignerToolWindow*> &toolWindows) : + m_toolBarManager(0) +{ + setObjectName(QLatin1String("MDIWindow")); + setWindowTitle(mainWindowTitle()); + + const QList<QToolBar *> toolbars = createToolBars(wb->actionManager(), false); + foreach (QToolBar *tb, toolbars) + addToolBar(tb); + DockedMdiArea *dma = new DockedMdiArea(wb->actionManager()->uiExtension()); + connect(dma, SIGNAL(fileDropped(QString)), + this, SIGNAL(fileDropped(QString))); + connect(dma, SIGNAL(subWindowActivated(QMdiSubWindow*)), + this, SLOT(slotSubWindowActivated(QMdiSubWindow*))); + setCentralWidget(dma); + + QStatusBar *sb = statusBar(); + Q_UNUSED(sb) + + m_toolBarManager = new ToolBarManager(this, this, toolBarMenu, wb->actionManager(), toolbars, toolWindows); +} + +QMdiArea *DockedMainWindow::mdiArea() const +{ + return static_cast<QMdiArea *>(centralWidget()); +} + +void DockedMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) +{ + if (subWindow) { + QWidget *widget = subWindow->widget(); + if (QDesignerFormWindow *fw = qobject_cast<QDesignerFormWindow*>(widget)) { + emit formWindowActivated(fw); + mdiArea()->setActiveSubWindow(subWindow); + } + } +} + +// Create a MDI subwindow for the form. +QMdiSubWindow *DockedMainWindow::createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut) +{ + QMdiSubWindow *rc = mdiArea()->addSubWindow(fw, f); + // Make action shortcuts respond only if focused to avoid conflicts with + // designer menu actions + if (designerCloseActionShortCut == QKeySequence(QKeySequence::Close)) { + const ActionList systemMenuActions = rc->systemMenu()->actions(); + if (!systemMenuActions.empty()) { + const ActionList::const_iterator cend = systemMenuActions.constEnd(); + for (ActionList::const_iterator it = systemMenuActions.constBegin(); it != cend; ++it) { + if ( (*it)->shortcut() == designerCloseActionShortCut) { + (*it)->setShortcutContext(Qt::WidgetShortcut); + break; + } + } + } + } + return rc; +} + +DockedMainWindow::DockWidgetList DockedMainWindow::addToolWindows(const DesignerToolWindowList &tls) +{ + DockWidgetList rc; + foreach (QDesignerToolWindow *tw, tls) { + QDockWidget *dockWidget = new QDockWidget; + dockWidget->setObjectName(tw->objectName() + QLatin1String("_dock")); + dockWidget->setWindowTitle(tw->windowTitle()); + addDockWidget(tw->dockWidgetAreaHint(), dockWidget); + dockWidget->setWidget(tw); + rc.push_back(dockWidget); + } + return rc; +} + +// Settings consist of MainWindow state and tool bar manager state +void DockedMainWindow::restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea) +{ + const int version = settingsVersion(); + m_toolBarManager->restoreState(s.toolBarsState(DockedMode), version); + + // If there are no old geometry settings, show the window maximized + s.restoreGeometry(this, QRect(desktopArea.topLeft(), QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))); + + const QByteArray mainWindowState = s.mainWindowState(DockedMode); + const bool restored = !mainWindowState.isEmpty() && restoreState(mainWindowState, version); + if (!restored) { + // Default: Tabify less relevant windows bottom/right. + tabifyDockWidget(dws.at(QDesignerToolWindow::SignalSlotEditor), + dws.at(QDesignerToolWindow::ActionEditor)); + tabifyDockWidget(dws.at(QDesignerToolWindow::ActionEditor), + dws.at(QDesignerToolWindow::ResourceEditor)); + } +} + +void DockedMainWindow::saveSettings(QDesignerSettings &s) const +{ + const int version = settingsVersion(); + s.setToolBarsState(DockedMode, m_toolBarManager->saveState(version)); + s.saveGeometryFor(this); + s.setMainWindowState(DockedMode, saveState(version)); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/mainwindow.h b/src/designer/src/designer/mainwindow.h new file mode 100644 index 000000000..e39e57203 --- /dev/null +++ b/src/designer/src/designer/mainwindow.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QtGui/QMainWindow> +#include <QtCore/QList> +#include <QtGui/QMdiArea> + +QT_BEGIN_NAMESPACE + +class QDesignerActions; +class QDesignerWorkbench; +class QDesignerToolWindow; +class QDesignerFormWindow; +class QDesignerSettings; + +class QtToolBarManager; +class QToolBar; +class QMdiArea; +class QMenu; +class QByteArray; +class QMimeData; + +/* A main window that has a configureable policy on handling close events. If + * enabled, it can forward the close event to external handlers. + * Base class for windows that can switch roles between tool windows + * and main windows. */ + +class MainWindowBase: public QMainWindow +{ + Q_DISABLE_COPY(MainWindowBase) + Q_OBJECT +protected: + explicit MainWindowBase(QWidget *parent = 0, Qt::WindowFlags flags = Qt::Window); + +public: + enum CloseEventPolicy { + /* Always accept close events */ + AcceptCloseEvents, + /* Emit a signal with the event, have it handled elsewhere */ + EmitCloseEventSignal }; + + CloseEventPolicy closeEventPolicy() const { return m_policy; } + void setCloseEventPolicy(CloseEventPolicy pol) { m_policy = pol; } + + static QList<QToolBar *> createToolBars(const QDesignerActions *actions, bool singleToolBar); + static QString mainWindowTitle(); + + // Use the minor Qt version as settings versions to avoid conflicts + static int settingsVersion(); + +signals: + void closeEventReceived(QCloseEvent *e); + +protected: + virtual void closeEvent(QCloseEvent *e); +private: + CloseEventPolicy m_policy; +}; + +/* An MdiArea that listens for desktop file manager file drop events and emits + * a signal to open a dropped file. */ +class DockedMdiArea : public QMdiArea +{ + Q_DISABLE_COPY(DockedMdiArea) + Q_OBJECT +public: + explicit DockedMdiArea(const QString &extension, QWidget *parent = 0); + +signals: + void fileDropped(const QString &); + +protected: + bool event (QEvent *event); + +private: + QStringList uiFiles(const QMimeData *d) const; + + const QString m_extension; +}; + +// Convenience class that manages a QtToolBarManager and an action to trigger +// it on a mainwindow. +class ToolBarManager : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(ToolBarManager) +public: + explicit ToolBarManager(QMainWindow *configureableMainWindow, + QWidget *parent, + QMenu *toolBarMenu, + const QDesignerActions *actions, + const QList<QToolBar *> &toolbars, + const QList<QDesignerToolWindow*> &toolWindows); + + QByteArray saveState(int version = 0) const; + bool restoreState(const QByteArray &state, int version = 0); + +private slots: + void configureToolBars(); + void updateToolBarMenu(); + +private: + QMainWindow *m_configureableMainWindow; + QWidget *m_parent; + QMenu *m_toolBarMenu; + QtToolBarManager *m_manager; + QAction *m_configureAction; + QList<QToolBar *> m_toolbars; +}; + +/* Main window to be used for docked mode */ +class DockedMainWindow : public MainWindowBase { + Q_OBJECT + Q_DISABLE_COPY(DockedMainWindow) +public: + typedef QList<QDesignerToolWindow*> DesignerToolWindowList; + typedef QList<QDockWidget *> DockWidgetList; + + explicit DockedMainWindow(QDesignerWorkbench *wb, + QMenu *toolBarMenu, + const DesignerToolWindowList &toolWindows); + + // Create a MDI subwindow for the form. + QMdiSubWindow *createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut); + + QMdiArea *mdiArea() const; + + DockWidgetList addToolWindows(const DesignerToolWindowList &toolWindows); + + void restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea); + void saveSettings(QDesignerSettings &) const; + +signals: + void fileDropped(const QString &); + void formWindowActivated(QDesignerFormWindow *); + +private slots: + void slotSubWindowActivated(QMdiSubWindow*); + +private: + ToolBarManager *m_toolBarManager; +}; + +QT_END_NAMESPACE + +#endif // MAINWINDOW_H diff --git a/src/designer/src/designer/newform.cpp b/src/designer/src/designer/newform.cpp new file mode 100644 index 000000000..34461f52a --- /dev/null +++ b/src/designer/src/designer/newform.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newform.h" +#include "qdesigner_workbench.h" +#include "qdesigner_actions.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" + +#include <newformwidget_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QTemporaryFile> + +#include <QtGui/QApplication> +#include <QtGui/QVBoxLayout> +#include <QtGui/QPushButton> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QMenu> +#include <QtGui/QCheckBox> +#include <QtGui/QFrame> +#include <QtGui/QMessageBox> + +QT_BEGIN_NAMESPACE + +NewForm::NewForm(QDesignerWorkbench *workbench, QWidget *parentWidget, const QString &fileName) + : QDialog(parentWidget, +#ifdef Q_WS_MAC + Qt::Tool | +#endif + Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + m_fileName(fileName), + m_newFormWidget(QDesignerNewFormWidgetInterface::createNewFormWidget(workbench->core())), + m_workbench(workbench), + m_chkShowOnStartup(new QCheckBox(tr("Show this Dialog on Startup"))), + m_createButton(new QPushButton(QApplication::translate("NewForm", "C&reate", 0, QApplication::UnicodeUTF8))), + m_recentButton(new QPushButton(QApplication::translate("NewForm", "Recent", 0, QApplication::UnicodeUTF8))), + m_buttonBox(0) +{ + setWindowTitle(tr("New Form")); + QDesignerSettings settings(m_workbench->core()); + + QVBoxLayout *vBoxLayout = new QVBoxLayout; + + connect(m_newFormWidget, SIGNAL(templateActivated()), this, SLOT(slotTemplateActivated())); + connect(m_newFormWidget, SIGNAL(currentTemplateChanged(bool)), this, SLOT(slotCurrentTemplateChanged(bool))); + vBoxLayout->addWidget(m_newFormWidget); + + QFrame *horizontalLine = new QFrame; + horizontalLine->setFrameShape(QFrame::HLine); + horizontalLine->setFrameShadow(QFrame::Sunken); + vBoxLayout->addWidget(horizontalLine); + + m_chkShowOnStartup->setChecked(settings.showNewFormOnStartup()); + vBoxLayout->addWidget(m_chkShowOnStartup); + + m_buttonBox = createButtonBox(); + vBoxLayout->addWidget(m_buttonBox); + setLayout(vBoxLayout); + + resize(500, 400); + slotCurrentTemplateChanged(m_newFormWidget->hasCurrentTemplate()); +} + +QDialogButtonBox *NewForm::createButtonBox() +{ + // Dialog buttons with 'recent files' + QDialogButtonBox *buttonBox = new QDialogButtonBox; + buttonBox->addButton(QApplication::translate("NewForm", "&Close", 0, + QApplication::UnicodeUTF8), QDialogButtonBox::RejectRole); + buttonBox->addButton(m_createButton, QDialogButtonBox::AcceptRole); + buttonBox->addButton(QApplication::translate("NewForm", "&Open...", 0, + QApplication::UnicodeUTF8), QDialogButtonBox::ActionRole); + buttonBox->addButton(m_recentButton, QDialogButtonBox::ActionRole); + QDesignerActions *da = m_workbench->actionManager(); + QMenu *recentFilesMenu = new QMenu(tr("&Recent Forms"), m_recentButton); + // Pop the "Recent Files" stuff in here. + const QList<QAction *> recentActions = da->recentFilesActions()->actions(); + if (!recentActions.empty()) { + const QList<QAction *>::const_iterator acend = recentActions.constEnd(); + for (QList<QAction *>::const_iterator it = recentActions.constBegin(); it != acend; ++it) { + recentFilesMenu->addAction(*it); + connect(*it, SIGNAL(triggered()), this, SLOT(recentFileChosen())); + } + } + m_recentButton->setMenu(recentFilesMenu); + connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotButtonBoxClicked(QAbstractButton*))); + return buttonBox; +} + +NewForm::~NewForm() +{ + QDesignerSettings settings (m_workbench->core()); + settings.setShowNewFormOnStartup(m_chkShowOnStartup->isChecked()); +} + +void NewForm::recentFileChosen() +{ + QAction *action = qobject_cast<QAction *>(sender()); + if (!action) + return; + if (action->objectName() == QLatin1String("__qt_action_clear_menu_")) + return; + close(); +} + +void NewForm::slotCurrentTemplateChanged(bool templateSelected) +{ + if (templateSelected) { + m_createButton->setEnabled(true); + m_createButton->setDefault(true); + } else { + m_createButton->setEnabled(false); + } +} + +void NewForm::slotTemplateActivated() +{ + m_createButton->animateClick(0); +} + +void NewForm::slotButtonBoxClicked(QAbstractButton *btn) +{ + switch (m_buttonBox->buttonRole(btn)) { + case QDialogButtonBox::RejectRole: + reject(); + break; + case QDialogButtonBox::ActionRole: + if (btn != m_recentButton) { + m_fileName.clear(); + if (m_workbench->actionManager()->openForm(this)) + accept(); + } + break; + case QDialogButtonBox::AcceptRole: { + QString errorMessage; + if (openTemplate(&errorMessage)) { + accept(); + } else { + QMessageBox::warning(this, tr("Read error"), errorMessage); + } + } + break; + default: + break; + } +} + +bool NewForm::openTemplate(QString *ptrToErrorMessage) +{ + const QString contents = m_newFormWidget->currentTemplate(ptrToErrorMessage); + if (contents.isEmpty()) + return false; + // Write to temporary file and open + QString tempPattern = QDir::tempPath(); + if (!tempPattern.endsWith(QDir::separator())) // platform-dependant + tempPattern += QDir::separator(); + tempPattern += QLatin1String("XXXXXX.ui"); + QTemporaryFile tempFormFile(tempPattern); + + tempFormFile.setAutoRemove(true); + if (!tempFormFile.open()) { + *ptrToErrorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath()); + return false; + } + const QString tempFormFileName = tempFormFile.fileName(); + tempFormFile.write(contents.toUtf8()); + if (!tempFormFile.flush()) { + *ptrToErrorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName); + return false; + } + tempFormFile.close(); + return m_workbench->openTemplate(tempFormFileName, m_fileName, ptrToErrorMessage); +} + +QImage NewForm::grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp) +{ + return qdesigner_internal::NewFormWidget::grabForm(core, file, workingDir, dp); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/newform.h b/src/designer/src/designer/newform.h new file mode 100644 index 000000000..ad51118b9 --- /dev/null +++ b/src/designer/src/designer/newform.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWFORM_H +#define NEWFORM_H + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class DeviceProfile; +} + +class QDesignerFormEditorInterface; +class QDesignerNewFormWidgetInterface; +class QDesignerWorkbench; + +class QCheckBox; +class QAbstractButton; +class QPushButton; +class QDialogButtonBox; +class QImage; +class QIODevice; + +class NewForm: public QDialog +{ + Q_OBJECT + Q_DISABLE_COPY(NewForm) + +public: + NewForm(QDesignerWorkbench *workbench, + QWidget *parentWidget, + // Use that file name instead of a temporary one + const QString &fileName = QString()); + + virtual ~NewForm(); + + // Convenience for implementing file dialogs with preview + static QImage grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp); + +private slots: + void slotButtonBoxClicked(QAbstractButton *btn); + void recentFileChosen(); + void slotCurrentTemplateChanged(bool templateSelected); + void slotTemplateActivated(); + +private: + QDialogButtonBox *createButtonBox(); + bool openTemplate(QString *ptrToErrorMessage); + + QString m_fileName; + QDesignerNewFormWidgetInterface *m_newFormWidget; + QDesignerWorkbench *m_workbench; + QCheckBox *m_chkShowOnStartup; + QPushButton *m_createButton; + QPushButton *m_recentButton; + QDialogButtonBox *m_buttonBox; +}; + +QT_END_NAMESPACE + +#endif // NEWFORM_H diff --git a/src/designer/src/designer/preferencesdialog.cpp b/src/designer/src/designer/preferencesdialog.cpp new file mode 100644 index 000000000..a27e366a5 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "preferencesdialog.h" +#include "ui_preferencesdialog.h" +#include "qdesigner_appearanceoptions.h" + +#include <QtDesigner/private/abstractoptionspage_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtGui/QFileDialog> +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +PreferencesDialog::PreferencesDialog(QDesignerFormEditorInterface *core, QWidget *parentWidget) : + QDialog(parentWidget), + m_ui(new Ui::PreferencesDialog()), + m_core(core) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_ui->setupUi(this); + + m_optionsPages = core->optionsPages(); + + m_ui->m_optionTabWidget->clear(); + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) { + QWidget *page = optionsPage->createPage(this); + m_ui->m_optionTabWidget->addTab(page, optionsPage->name()); + if (QDesignerAppearanceOptionsWidget *appearanceWidget = qobject_cast<QDesignerAppearanceOptionsWidget *>(page)) + connect(appearanceWidget, SIGNAL(uiModeChanged(bool)), this, SLOT(slotUiModeChanged(bool))); + } + + connect(m_ui->m_dialogButtonBox, SIGNAL(rejected()), this, SLOT(slotRejected())); + connect(m_ui->m_dialogButtonBox, SIGNAL(accepted()), this, SLOT(slotAccepted())); + connect(applyButton(), SIGNAL(clicked()), this, SLOT(slotApply())); +} + +PreferencesDialog::~PreferencesDialog() +{ + delete m_ui; +} + +QPushButton *PreferencesDialog::applyButton() const +{ + return m_ui->m_dialogButtonBox->button(QDialogButtonBox::Apply); +} + +void PreferencesDialog::slotApply() +{ + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) + optionsPage->apply(); +} + +void PreferencesDialog::slotAccepted() +{ + slotApply(); + closeOptionPages(); + accept(); +} + +void PreferencesDialog::slotRejected() +{ + closeOptionPages(); + reject(); +} + +void PreferencesDialog::slotUiModeChanged(bool modified) +{ + // Cannot "apply" a ui mode change (destroy the dialogs parent) + applyButton()->setEnabled(!modified); +} + +void PreferencesDialog::closeOptionPages() +{ + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) + optionsPage->finish(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/preferencesdialog.h b/src/designer/src/designer/preferencesdialog.h new file mode 100644 index 000000000..5ffd7d365 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QPushButton; +class QDesignerFormEditorInterface; +class QDesignerOptionsPageInterface; + +namespace Ui { + class PreferencesDialog; +} + +class PreferencesDialog: public QDialog +{ + Q_OBJECT +public: + explicit PreferencesDialog(QDesignerFormEditorInterface *core, QWidget *parentWidget = 0); + ~PreferencesDialog(); + + +private slots: + void slotAccepted(); + void slotRejected(); + void slotApply(); + void slotUiModeChanged(bool modified); + +private: + QPushButton *applyButton() const; + void closeOptionPages(); + + Ui::PreferencesDialog *m_ui; + QDesignerFormEditorInterface *m_core; + QList<QDesignerOptionsPageInterface*> m_optionsPages; +}; + +QT_END_NAMESPACE + +#endif // PREFERENCESDIALOG_H diff --git a/src/designer/src/designer/preferencesdialog.ui b/src/designer/src/designer/preferencesdialog.ui new file mode 100644 index 000000000..28d14bb83 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.ui @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PreferencesDialog</class> + <widget class="QDialog" name="PreferencesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>474</width> + <height>304</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Preferences</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="m_optionTabWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string notr="true">Tab 1</string> + </attribute> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="m_dialogButtonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Apply|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>m_dialogButtonBox</sender> + <signal>accepted()</signal> + <receiver>PreferencesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>m_dialogButtonBox</sender> + <signal>rejected()</signal> + <receiver>PreferencesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/designer/src/designer/qdesigner.cpp b/src/designer/src/designer/qdesigner.cpp new file mode 100644 index 000000000..1e838c197 --- /dev/null +++ b/src/designer/src/designer/qdesigner.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// designer +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_server.h" +#include "qdesigner_settings.h" +#include "qdesigner_workbench.h" +#include "mainwindow.h" + +#include <qdesigner_propertysheet_p.h> + +#include <QtGui/QFileOpenEvent> +#include <QtGui/QCloseEvent> +#include <QtGui/QMessageBox> +#include <QtGui/QIcon> +#include <QtGui/QErrorMessage> +#include <QtCore/QMetaObject> +#include <QtCore/QFile> +#include <QtCore/QLibraryInfo> +#include <QtCore/QLocale> +#include <QtCore/QTimer> +#include <QtCore/QTranslator> +#include <QtCore/QFileInfo> +#include <QtCore/qdebug.h> + +#include <QtDesigner/QDesignerComponents> + +QT_BEGIN_NAMESPACE + +static const char *designerApplicationName = "Designer"; +static const char *designerWarningPrefix = "Designer: "; + +static void designerMessageHandler(QtMsgType type, const char *msg) +{ + // Only Designer warnings are displayed as box + QDesigner *designerApp = qDesigner; + if (type != QtWarningMsg || !designerApp || qstrncmp(designerWarningPrefix, msg, qstrlen(designerWarningPrefix))) { + qInstallMsgHandler(0); + qt_message_output(type, msg); + qInstallMsgHandler (designerMessageHandler); + return; + } + designerApp->showErrorMessage(msg); +} + +QDesigner::QDesigner(int &argc, char **argv) + : QApplication(argc, argv), + m_server(0), + m_client(0), + m_workbench(0), m_suppressNewFormShow(false) +{ + setOrganizationName(QLatin1String("Trolltech")); + setApplicationName(QLatin1String(designerApplicationName)); + QDesignerComponents::initializeResources(); + +#ifndef Q_WS_MAC + setWindowIcon(QIcon(QLatin1String(":/trolltech/designer/images/designer.png"))); +#endif + initialize(); +} + +QDesigner::~QDesigner() +{ + if (m_workbench) + delete m_workbench; + if (m_server) + delete m_server; + if (m_client) + delete m_client; +} + +void QDesigner::showErrorMessage(const char *message) +{ + // strip the prefix + const QString qMessage = QString::fromUtf8(message + qstrlen(designerWarningPrefix)); + // If there is no main window yet, just store the message. + // The QErrorMessage would otherwise be hidden by the main window. + if (m_mainWindow) { + showErrorMessageBox(qMessage); + } else { + qInstallMsgHandler(0); + qt_message_output(QtWarningMsg, message); // just in case we crash + qInstallMsgHandler (designerMessageHandler); + m_initializationErrors += qMessage; + m_initializationErrors += QLatin1Char('\n'); + } +} + +void QDesigner::showErrorMessageBox(const QString &msg) +{ + // Manually suppress consecutive messages. + // This happens if for example sth is wrong with custom widget creation. + // The same warning will be displayed by Widget box D&D and form Drop + // while trying to create instance. + if (m_errorMessageDialog && m_lastErrorMessage == msg) + return; + + if (!m_errorMessageDialog) { + m_lastErrorMessage.clear(); + m_errorMessageDialog = new QErrorMessage(m_mainWindow); + const QString title = QCoreApplication::translate("QDesigner", "%1 - warning").arg(QLatin1String(designerApplicationName)); + m_errorMessageDialog->setWindowTitle(title); + m_errorMessageDialog->setMinimumSize(QSize(600, 250)); + m_errorMessageDialog->setWindowFlags(m_errorMessageDialog->windowFlags() & ~Qt::WindowContextHelpButtonHint); + } + m_errorMessageDialog->showMessage(msg); + m_lastErrorMessage = msg; +} + +QDesignerWorkbench *QDesigner::workbench() const +{ + return m_workbench; +} + +QDesignerServer *QDesigner::server() const +{ + return m_server; +} + +bool QDesigner::parseCommandLineArgs(QStringList &fileNames, QString &resourceDir) +{ + const QStringList args = arguments(); + const QStringList::const_iterator acend = args.constEnd(); + QStringList::const_iterator it = args.constBegin(); + for (++it; it != acend; ++it) { + const QString &argument = *it; + do { + // Arguments + if (!argument.startsWith(QLatin1Char('-'))) { + if (!fileNames.contains(argument)) + fileNames.append(argument); + break; + } + // Options + if (argument == QLatin1String("-server")) { + m_server = new QDesignerServer(); + printf("%d\n", m_server->serverPort()); + fflush(stdout); + break; + } + if (argument == QLatin1String("-client")) { + bool ok = true; + if (++it == acend) { + qWarning("** WARNING The option -client requires an argument"); + return false; + } + const quint16 port = it->toUShort(&ok); + if (ok) { + m_client = new QDesignerClient(port, this); + } else { + qWarning("** WARNING Non-numeric argument specified for -client"); + return false; + } + break; + } + if (argument == QLatin1String("-resourcedir")) { + if (++it == acend) { + qWarning("** WARNING The option -resourcedir requires an argument"); + return false; + } + resourceDir = QFile::decodeName(it->toLocal8Bit()); + break; + } + if (argument == QLatin1String("-enableinternaldynamicproperties")) { + QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(true); + break; + } + const QString msg = QString::fromUtf8("** WARNING Unknown option %1").arg(argument); + qWarning("%s", qPrintable(msg)); + } while (false); + } + return true; +} + +void QDesigner::initialize() +{ + // initialize the sub components + QStringList files; + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + parseCommandLineArgs(files, resourceDir); + + QTranslator *translator = new QTranslator(this); + QTranslator *qtTranslator = new QTranslator(this); + + const QString localSysName = QLocale::system().name(); + QString translatorFileName = QLatin1String("designer_"); + translatorFileName += localSysName; + translator->load(translatorFileName, resourceDir); + + translatorFileName = QLatin1String("qt_"); + translatorFileName += localSysName; + qtTranslator->load(translatorFileName, resourceDir); + installTranslator(translator); + installTranslator(qtTranslator); + + if (QLibraryInfo::licensedProducts() == QLatin1String("Console")) { + QMessageBox::information(0, tr("Qt Designer"), + tr("This application cannot be used for the Console edition of Qt")); + QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + return; + } + + m_workbench = new QDesignerWorkbench(); + + emit initialized(); + qInstallMsgHandler(designerMessageHandler); // Warn when loading faulty forms + + m_suppressNewFormShow = m_workbench->readInBackup(); + + if (!files.empty()) { + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + // Ensure absolute paths for recent file list to be unique + QString fileName = *it; + const QFileInfo fi(fileName); + if (fi.exists() && fi.isRelative()) + fileName = fi.absoluteFilePath(); + m_workbench->readInForm(fileName); + } + } + if ( m_workbench->formWindowCount()) + m_suppressNewFormShow = true; + + // Show up error box with parent now if something went wrong + if (m_initializationErrors.isEmpty()) { + if (!m_suppressNewFormShow && QDesignerSettings(m_workbench->core()).showNewFormOnStartup()) + QTimer::singleShot(100, this, SLOT(callCreateForm())); // won't show anything if suppressed + } else { + showErrorMessageBox(m_initializationErrors); + m_initializationErrors.clear(); + } +} + +bool QDesigner::event(QEvent *ev) +{ + bool eaten; + switch (ev->type()) { + case QEvent::FileOpen: + // Set it true first since, if it's a Qt 3 form, the messagebox from convert will fire the timer. + m_suppressNewFormShow = true; + if (!m_workbench->readInForm(static_cast<QFileOpenEvent *>(ev)->file())) + m_suppressNewFormShow = false; + eaten = true; + break; + case QEvent::Close: { + QCloseEvent *closeEvent = static_cast<QCloseEvent *>(ev); + closeEvent->setAccepted(m_workbench->handleClose()); + if (closeEvent->isAccepted()) { + // We're going down, make sure that we don't get our settings saved twice. + if (m_mainWindow) + m_mainWindow->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents); + eaten = QApplication::event(ev); + } + eaten = true; + break; + } + default: + eaten = QApplication::event(ev); + break; + } + return eaten; +} + +void QDesigner::setMainWindow(MainWindowBase *tw) +{ + m_mainWindow = tw; +} + +MainWindowBase *QDesigner::mainWindow() const +{ + return m_mainWindow; +} + +void QDesigner::callCreateForm() +{ + if (!m_suppressNewFormShow) + m_workbench->actionManager()->createForm(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner.h b/src/designer/src/designer/qdesigner.h new file mode 100644 index 000000000..ff45edffd --- /dev/null +++ b/src/designer/src/designer/qdesigner.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_H +#define QDESIGNER_H + +#include <QtCore/QPointer> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +#define qDesigner \ + (static_cast<QDesigner*>(QCoreApplication::instance())) + +class QDesignerWorkbench; +class QDesignerToolWindow; +class MainWindowBase; +class QDesignerServer; +class QDesignerClient; +class QErrorMessage; + +class QDesigner: public QApplication +{ + Q_OBJECT +public: + QDesigner(int &argc, char **argv); + virtual ~QDesigner(); + + QDesignerWorkbench *workbench() const; + QDesignerServer *server() const; + MainWindowBase *mainWindow() const; + void setMainWindow(MainWindowBase *tw); + +protected: + bool event(QEvent *ev); + +signals: + void initialized(); + +public slots: + void showErrorMessage(const char *message); + +private slots: + void initialize(); + void callCreateForm(); + +private: + bool parseCommandLineArgs(QStringList &fileNames, QString &resourceDir); + void showErrorMessageBox(const QString &); + + QDesignerServer *m_server; + QDesignerClient *m_client; + QDesignerWorkbench *m_workbench; + QPointer<MainWindowBase> m_mainWindow; + QPointer<QErrorMessage> m_errorMessageDialog; + + QString m_initializationErrors; + QString m_lastErrorMessage; + bool m_suppressNewFormShow; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_H diff --git a/src/designer/src/designer/qdesigner_actions.cpp b/src/designer/src/designer/qdesigner_actions.cpp new file mode 100644 index 000000000..a84e0732d --- /dev/null +++ b/src/designer/src/designer/qdesigner_actions.cpp @@ -0,0 +1,1437 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_actions.h" +#include "designer_enums.h" +#include "qdesigner.h" +#include "qdesigner_workbench.h" +#include "qdesigner_formwindow.h" +#include "newform.h" +#include "versiondialog.h" +#include "saveformastemplate.h" +#include "qdesigner_toolwindow.h" +#include "preferencesdialog.h" +#include "appfontdialog.h" + +#include <pluginmanager_p.h> +#include <qdesigner_formbuilder_p.h> +#include <qdesigner_utils_p.h> +#include <iconloader_p.h> +#include <qsimpleresource_p.h> +#include <previewmanager_p.h> +#include <codedialog_p.h> +#include <qdesigner_formwindowmanager_p.h> +#include "qdesigner_integration_p.h" + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerLanguageExtension> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <QtDesigner/QDesignerFormEditorPluginInterface> +#include <QtDesigner/QExtensionManager> + +#include <QtDesigner/private/shared_settings_p.h> +#include <QtDesigner/private/formwindowbase_p.h> + +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QStyleFactory> +#include <QtGui/QCloseEvent> +#include <QtGui/QFileDialog> +#include <QtGui/QMenu> +#include <QtGui/QMessageBox> +#include <QtGui/QPushButton> +#include <QtGui/QIcon> +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QPrintDialog> +#include <QtGui/QPainter> +#include <QtGui/QTransform> +#include <QtGui/QCursor> +#include <QtCore/QSizeF> + +#include <QtCore/QLibraryInfo> +#include <QtCore/QBuffer> +#include <QtCore/QPluginLoader> +#include <QtCore/qdebug.h> +#include <QtCore/QTimer> +#include <QtCore/QMetaObject> +#include <QtCore/QFileInfo> +#include <QtGui/QStatusBar> +#include <QtGui/QDesktopWidget> +#include <QtXml/QDomDocument> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +const char *QDesignerActions::defaultToolbarPropertyName = "__qt_defaultToolBarAction"; + +//#ifdef Q_WS_MAC +# define NONMODAL_PREVIEW +//#endif + +static QAction *createSeparator(QObject *parent) { + QAction * rc = new QAction(parent); + rc->setSeparator(true); + return rc; +} + +static QActionGroup *createActionGroup(QObject *parent, bool exclusive = false) { + QActionGroup * rc = new QActionGroup(parent); + rc->setExclusive(exclusive); + return rc; +} + +static inline QString savedMessage(const QString &fileName) +{ + return QDesignerActions::tr("Saved %1.").arg(fileName); +} + +// Prompt for a file and make sure an extension is added +// unless the user explicitly specifies another one. + +static QString getSaveFileNameWithExtension(QWidget *parent, const QString &title, QString dir, const QString &filter, const QString &extension) +{ + const QChar dot = QLatin1Char('.'); + + QString saveFile; + while (true) { + saveFile = QFileDialog::getSaveFileName(parent, title, dir, filter, 0, QFileDialog::DontConfirmOverwrite); + if (saveFile.isEmpty()) + return saveFile; + + const QFileInfo fInfo(saveFile); + if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) { + saveFile += dot; + saveFile += extension; + } + + const QFileInfo fi(saveFile); + if (!fi.exists()) + break; + + const QString prompt = QDesignerActions::tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()); + if (QMessageBox::warning(parent, title, prompt, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + break; + + dir = saveFile; + } + return saveFile; +} + +QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) + : QObject(workbench), + m_workbench(workbench), + m_core(workbench->core()), + m_settings(workbench->core()), + m_backupTimer(new QTimer(this)), + m_fileActions(createActionGroup(this)), + m_recentFilesActions(createActionGroup(this)), + m_editActions(createActionGroup(this)), + m_formActions(createActionGroup(this)), + m_settingsActions(createActionGroup(this)), + m_windowActions(createActionGroup(this)), + m_toolActions(createActionGroup(this, true)), + m_helpActions(0), + m_styleActions(0), + m_editWidgetsAction(new QAction(tr("Edit Widgets"), this)), + m_newFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filenew.png")), tr("&New..."), this)), + m_openFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("fileopen.png")), tr("&Open..."), this)), + m_saveFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filesave.png")), tr("&Save"), this)), + m_saveFormAsAction(new QAction(tr("Save &As..."), this)), + m_saveAllFormsAction(new QAction(tr("Save A&ll"), this)), + m_saveFormAsTemplateAction(new QAction(tr("Save As &Template..."), this)), + m_closeFormAction(new QAction(tr("&Close"), this)), + m_savePreviewImageAction(new QAction(tr("Save &Image..."), this)), + m_printPreviewAction(new QAction(tr("&Print..."), this)), + m_quitAction(new QAction(tr("&Quit"), this)), + m_previewFormAction(0), + m_viewCodeAction(new QAction(tr("View &Code..."), this)), + m_minimizeAction(new QAction(tr("&Minimize"), this)), + m_bringAllToFrontSeparator(createSeparator(this)), + m_bringAllToFrontAction(new QAction(tr("Bring All to Front"), this)), + m_windowListSeparatorAction(createSeparator(this)), + m_preferencesAction(new QAction(tr("Preferences..."), this)), + m_appFontAction(new QAction(tr("Additional Fonts..."), this)), + m_appFontDialog(0), +#ifndef QT_NO_PRINTER + m_printer(0), +#endif + m_previewManager(0) +{ +#ifdef Q_WS_X11 + m_newFormAction->setIcon(QIcon::fromTheme("document-new", m_newFormAction->icon())); + m_openFormAction->setIcon(QIcon::fromTheme("document-open", m_openFormAction->icon())); + m_saveFormAction->setIcon(QIcon::fromTheme("document-save", m_saveFormAction->icon())); + m_saveFormAsAction->setIcon(QIcon::fromTheme("document-save-as", m_saveFormAsAction->icon())); + m_printPreviewAction->setIcon(QIcon::fromTheme("document-print", m_printPreviewAction->icon())); + m_closeFormAction->setIcon(QIcon::fromTheme("window-close", m_closeFormAction->icon())); + m_quitAction->setIcon(QIcon::fromTheme("application-exit", m_quitAction->icon())); +#endif + + Q_ASSERT(m_core != 0); + qdesigner_internal::QDesignerFormWindowManager *ifwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager *>(m_core->formWindowManager()); + Q_ASSERT(ifwm); + m_previewManager = ifwm->previewManager(); + m_previewFormAction = ifwm->actionDefaultPreview(); + m_styleActions = ifwm->actionGroupPreviewInStyle(); + connect(ifwm, SIGNAL(formWindowSettingsChanged(QDesignerFormWindowInterface*)), + this, SLOT(formWindowSettingsChanged(QDesignerFormWindowInterface*))); + + m_editWidgetsAction->setObjectName(QLatin1String("__qt_edit_widgets_action")); + m_newFormAction->setObjectName(QLatin1String("__qt_new_form_action")); + m_openFormAction->setObjectName(QLatin1String("__qt_open_form_action")); + m_saveFormAction->setObjectName(QLatin1String("__qt_save_form_action")); + m_saveFormAsAction->setObjectName(QLatin1String("__qt_save_form_as_action")); + m_saveAllFormsAction->setObjectName(QLatin1String("__qt_save_all_forms_action")); + m_saveFormAsTemplateAction->setObjectName(QLatin1String("__qt_save_form_as_template_action")); + m_closeFormAction->setObjectName(QLatin1String("__qt_close_form_action")); + m_quitAction->setObjectName(QLatin1String("__qt_quit_action")); + m_previewFormAction->setObjectName(QLatin1String("__qt_preview_form_action")); + m_viewCodeAction->setObjectName(QLatin1String("__qt_preview_code_action")); + m_minimizeAction->setObjectName(QLatin1String("__qt_minimize_action")); + m_bringAllToFrontAction->setObjectName(QLatin1String("__qt_bring_all_to_front_action")); + m_preferencesAction->setObjectName(QLatin1String("__qt_preferences_action")); + + m_helpActions = createHelpActions(); + + m_newFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_openFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_saveFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); + Q_ASSERT(formWindowManager != 0); + +// +// file actions +// + m_newFormAction->setShortcut(QKeySequence::New); + connect(m_newFormAction, SIGNAL(triggered()), this, SLOT(createForm())); + m_fileActions->addAction(m_newFormAction); + + m_openFormAction->setShortcut(QKeySequence::Open); + connect(m_openFormAction, SIGNAL(triggered()), this, SLOT(slotOpenForm())); + m_fileActions->addAction(m_openFormAction); + + m_fileActions->addAction(createRecentFilesMenu()); + m_fileActions->addAction(createSeparator(this)); + + m_saveFormAction->setShortcut(QKeySequence::Save); + connect(m_saveFormAction, SIGNAL(triggered()), this, SLOT(saveForm())); + m_fileActions->addAction(m_saveFormAction); + + connect(m_saveFormAsAction, SIGNAL(triggered()), this, SLOT(saveFormAs())); + m_fileActions->addAction(m_saveFormAsAction); + +#ifdef Q_OS_MAC + m_saveAllFormsAction->setShortcut(tr("ALT+CTRL+S")); +#else + m_saveAllFormsAction->setShortcut(tr("CTRL+SHIFT+S")); // Commonly "Save As" on Mac +#endif + connect(m_saveAllFormsAction, SIGNAL(triggered()), this, SLOT(saveAllForms())); + m_fileActions->addAction(m_saveAllFormsAction); + + connect(m_saveFormAsTemplateAction, SIGNAL(triggered()), this, SLOT(saveFormAsTemplate())); + m_fileActions->addAction(m_saveFormAsTemplateAction); + + m_fileActions->addAction(createSeparator(this)); + + m_printPreviewAction->setShortcut(QKeySequence::Print); + connect(m_printPreviewAction, SIGNAL(triggered()), this, SLOT(printPreviewImage())); + m_fileActions->addAction(m_printPreviewAction); + m_printPreviewAction->setObjectName(QLatin1String("__qt_print_action")); + + connect(m_savePreviewImageAction, SIGNAL(triggered()), this, SLOT(savePreviewImage())); + m_savePreviewImageAction->setObjectName(QLatin1String("__qt_saveimage_action")); + m_fileActions->addAction(m_savePreviewImageAction); + m_fileActions->addAction(createSeparator(this)); + + m_closeFormAction->setShortcut(QKeySequence::Close); + connect(m_closeFormAction, SIGNAL(triggered()), this, SLOT(closeForm())); + m_fileActions->addAction(m_closeFormAction); + updateCloseAction(); + + m_fileActions->addAction(createSeparator(this)); + + m_quitAction->setShortcuts(QKeySequence::Quit); + m_quitAction->setMenuRole(QAction::QuitRole); + connect(m_quitAction, SIGNAL(triggered()), this, SLOT(shutdown())); + m_fileActions->addAction(m_quitAction); + +// +// edit actions +// + QAction *undoAction = formWindowManager->actionUndo(); + undoAction->setObjectName(QLatin1String("__qt_undo_action")); + undoAction->setShortcut(QKeySequence::Undo); + m_editActions->addAction(undoAction); + + QAction *redoAction = formWindowManager->actionRedo(); + redoAction->setObjectName(QLatin1String("__qt_redo_action")); + redoAction->setShortcut(QKeySequence::Redo); + m_editActions->addAction(redoAction); + + m_editActions->addAction(createSeparator(this)); + + m_editActions->addAction(formWindowManager->actionCut()); + m_editActions->addAction(formWindowManager->actionCopy()); + m_editActions->addAction(formWindowManager->actionPaste()); + m_editActions->addAction(formWindowManager->actionDelete()); + + m_editActions->addAction(formWindowManager->actionSelectAll()); + + m_editActions->addAction(createSeparator(this)); + + m_editActions->addAction(formWindowManager->actionLower()); + m_editActions->addAction(formWindowManager->actionRaise()); + + formWindowManager->actionLower()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionRaise()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + +// +// edit mode actions +// + + m_editWidgetsAction->setCheckable(true); + QList<QKeySequence> shortcuts; + shortcuts.append(QKeySequence(Qt::Key_F3)); +#if QT_VERSION >= 0x040900 // "ESC" switching to edit mode: Activate once item delegates handle shortcut overrides for ESC. + shortcuts.append(QKeySequence(Qt::Key_Escape)); +#endif + m_editWidgetsAction->setShortcuts(shortcuts); + QIcon fallback(m_core->resourceLocation() + QLatin1String("/widgettool.png")); + m_editWidgetsAction->setIcon(QIcon::fromTheme("designer-edit-widget", fallback)); + connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot())); + m_editWidgetsAction->setChecked(true); + m_editWidgetsAction->setEnabled(false); + m_editWidgetsAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_toolActions->addAction(m_editWidgetsAction); + + connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); + + QList<QObject*> builtinPlugins = QPluginLoader::staticInstances(); + builtinPlugins += m_core->pluginManager()->instances(); + foreach (QObject *plugin, builtinPlugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) { + if (QAction *action = formEditorPlugin->action()) { + m_toolActions->addAction(action); + action->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + action->setCheckable(true); + } + } + } + + connect(m_preferencesAction, SIGNAL(triggered()), this, SLOT(showPreferencesDialog())); + m_preferencesAction->setMenuRole(QAction::PreferencesRole); + m_settingsActions->addAction(m_preferencesAction); + + connect(m_appFontAction, SIGNAL(triggered()), this, SLOT(showAppFontDialog())); + m_appFontAction->setMenuRole(QAction::PreferencesRole); + m_settingsActions->addAction(m_appFontAction); +// +// form actions +// + + m_formActions->addAction(formWindowManager->actionHorizontalLayout()); + m_formActions->addAction(formWindowManager->actionVerticalLayout()); + m_formActions->addAction(formWindowManager->actionSplitHorizontal()); + m_formActions->addAction(formWindowManager->actionSplitVertical()); + m_formActions->addAction(formWindowManager->actionGridLayout()); + m_formActions->addAction(formWindowManager->actionFormLayout()); + m_formActions->addAction(formWindowManager->actionBreakLayout()); + m_formActions->addAction(formWindowManager->actionAdjustSize()); + m_formActions->addAction(formWindowManager->actionSimplifyLayout()); + m_formActions->addAction(createSeparator(this)); + + formWindowManager->actionHorizontalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionVerticalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitHorizontal()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitVertical()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionGridLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionFormLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionBreakLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionAdjustSize()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + + m_previewFormAction->setShortcut(tr("CTRL+R")); + m_formActions->addAction(m_previewFormAction); + connect(m_previewManager, SIGNAL(firstPreviewOpened()), this, SLOT(updateCloseAction())); + connect(m_previewManager, SIGNAL(lastPreviewClosed()), this, SLOT(updateCloseAction())); + + connect(m_viewCodeAction, SIGNAL(triggered()), this, SLOT(viewCode())); + // Preview code only in Cpp + if (qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core) == 0) + m_formActions->addAction(m_viewCodeAction); + + m_formActions->addAction(createSeparator(this)); + + m_formActions->addAction(ifwm->actionShowFormWindowSettingsDialog()); +// +// window actions +// + m_minimizeAction->setEnabled(false); + m_minimizeAction->setCheckable(true); + m_minimizeAction->setShortcut(tr("CTRL+M")); + connect(m_minimizeAction, SIGNAL(triggered()), m_workbench, SLOT(toggleFormMinimizationState())); + m_windowActions->addAction(m_minimizeAction); + + m_windowActions->addAction(m_bringAllToFrontSeparator); + connect(m_bringAllToFrontAction, SIGNAL(triggered()), m_workbench, SLOT(bringAllToFront())); + m_windowActions->addAction(m_bringAllToFrontAction); + m_windowActions->addAction(m_windowListSeparatorAction); + + setWindowListSeparatorVisible(false); + +// +// connections +// + fixActionContext(); + activeFormWindowChanged(core()->formWindowManager()->activeFormWindow()); + + m_backupTimer->start(180000); // 3min + connect(m_backupTimer, SIGNAL(timeout()), this, SLOT(backupForms())); + + // Enable application font action + connect(formWindowManager, SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged())); + connect(formWindowManager, SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged())); + formWindowCountChanged(); +} + +QActionGroup *QDesignerActions::createHelpActions() +{ + QActionGroup *helpActions = createActionGroup(this); + +#ifndef QT_JAMBI_BUILD + QAction *mainHelpAction = new QAction(tr("Qt Designer &Help"), this); + mainHelpAction->setObjectName(QLatin1String("__qt_designer_help_action")); + connect(mainHelpAction, SIGNAL(triggered()), this, SLOT(showDesignerHelp())); + mainHelpAction->setShortcut(Qt::CTRL + Qt::Key_Question); + helpActions->addAction(mainHelpAction); + + helpActions->addAction(createSeparator(this)); + QAction *widgetHelp = new QAction(tr("Current Widget Help"), this); + widgetHelp->setObjectName(QLatin1String("__qt_current_widget_help_action")); + widgetHelp->setShortcut(Qt::Key_F1); + connect(widgetHelp, SIGNAL(triggered()), this, SLOT(showWidgetSpecificHelp())); + helpActions->addAction(widgetHelp); + + helpActions->addAction(createSeparator(this)); + QAction *whatsNewAction = new QAction(tr("What's New in Qt Designer?"), this); + whatsNewAction->setObjectName(QLatin1String("__qt_whats_new_in_qt_designer_action")); + connect(whatsNewAction, SIGNAL(triggered()), this, SLOT(showWhatsNew())); + helpActions->addAction(whatsNewAction); +#endif + + helpActions->addAction(createSeparator(this)); + QAction *aboutPluginsAction = new QAction(tr("About Plugins"), this); + aboutPluginsAction->setObjectName(QLatin1String("__qt_about_plugins_action")); + aboutPluginsAction->setMenuRole(QAction::ApplicationSpecificRole); + connect(aboutPluginsAction, SIGNAL(triggered()), m_core->formWindowManager(), SLOT(aboutPlugins())); + helpActions->addAction(aboutPluginsAction); + + QAction *aboutDesignerAction = new QAction(tr("About Qt Designer"), this); + aboutDesignerAction->setMenuRole(QAction::AboutRole); + aboutDesignerAction->setObjectName(QLatin1String("__qt_about_designer_action")); + connect(aboutDesignerAction, SIGNAL(triggered()), this, SLOT(aboutDesigner())); + helpActions->addAction(aboutDesignerAction); + + QAction *aboutQtAction = new QAction(tr("About Qt"), this); + aboutQtAction->setMenuRole(QAction::AboutQtRole); + aboutQtAction->setObjectName(QLatin1String("__qt_about_qt_action")); + connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + helpActions->addAction(aboutQtAction); + return helpActions; +} + +QDesignerActions::~QDesignerActions() +{ +#ifndef QT_NO_PRINTER + delete m_printer; +#endif +} + +QString QDesignerActions::uiExtension() const +{ + QDesignerLanguageExtension *lang + = qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core); + if (lang) + return lang->uiExtension(); + return QLatin1String("ui"); +} + +QAction *QDesignerActions::createRecentFilesMenu() +{ + QMenu *menu = new QMenu; + QAction *act; + // Need to insert this into the QAction. + for (int i = 0; i < MaxRecentFiles; ++i) { + act = new QAction(this); + act->setVisible(false); + connect(act, SIGNAL(triggered()), this, SLOT(openRecentForm())); + m_recentFilesActions->addAction(act); + menu->addAction(act); + } + updateRecentFileActions(); + menu->addSeparator(); + act = new QAction(QIcon::fromTheme("edit-clear"), tr("Clear &Menu"), this); + act->setObjectName(QLatin1String("__qt_action_clear_menu_")); + connect(act, SIGNAL(triggered()), this, SLOT(clearRecentFiles())); + m_recentFilesActions->addAction(act); + menu->addAction(act); + + act = new QAction(QIcon::fromTheme("document-open-recent"), tr("&Recent Forms"), this); + act->setMenu(menu); + return act; +} + +QActionGroup *QDesignerActions::toolActions() const +{ return m_toolActions; } + +QDesignerWorkbench *QDesignerActions::workbench() const +{ return m_workbench; } + +QDesignerFormEditorInterface *QDesignerActions::core() const +{ return m_core; } + +QActionGroup *QDesignerActions::fileActions() const +{ return m_fileActions; } + +QActionGroup *QDesignerActions::editActions() const +{ return m_editActions; } + +QActionGroup *QDesignerActions::formActions() const +{ return m_formActions; } + +QActionGroup *QDesignerActions::settingsActions() const +{ return m_settingsActions; } + +QActionGroup *QDesignerActions::windowActions() const +{ return m_windowActions; } + +QActionGroup *QDesignerActions::helpActions() const +{ return m_helpActions; } + +QActionGroup *QDesignerActions::styleActions() const +{ return m_styleActions; } + +QAction *QDesignerActions::previewFormAction() const +{ return m_previewFormAction; } + +QAction *QDesignerActions::viewCodeAction() const +{ return m_viewCodeAction; } + + +void QDesignerActions::editWidgetsSlot() +{ + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + for (int i=0; i<formWindowManager->formWindowCount(); ++i) { + QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i); + formWindow->editWidgets(); + } +} + +void QDesignerActions::createForm() +{ + showNewFormDialog(QString()); +} + +void QDesignerActions::showNewFormDialog(const QString &fileName) +{ + closePreview(); + NewForm *dlg = new NewForm(workbench(), workbench()->core()->topLevel(), fileName); + + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->setAttribute(Qt::WA_ShowModal); + + dlg->setGeometry(fixDialogRect(dlg->rect())); + dlg->exec(); +} + +void QDesignerActions::slotOpenForm() +{ + openForm(core()->topLevel()); +} + +bool QDesignerActions::openForm(QWidget *parent) +{ + closePreview(); + const QString extension = uiExtension(); + const QStringList fileNames = QFileDialog::getOpenFileNames(parent, tr("Open Form"), + m_openDirectory, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet); + + if (fileNames.isEmpty()) + return false; + + bool atLeastOne = false; + foreach (const QString &fileName, fileNames) { + if (readInForm(fileName) && !atLeastOne) + atLeastOne = true; + } + + return atLeastOne; +} + +bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw) +{ + const QString extension = uiExtension(); + + QString dir = fw->fileName(); + if (dir.isEmpty()) { + do { + // Build untitled name + if (!m_saveDirectory.isEmpty()) { + dir = m_saveDirectory; + break; + } + if (!m_openDirectory.isEmpty()) { + dir = m_openDirectory; + break; + } + dir = QDir::current().absolutePath(); + } while (false); + dir += QDir::separator(); + dir += QLatin1String("untitled."); + dir += extension; + } + + const QString saveFile = getSaveFileNameWithExtension(fw, tr("Save Form As"), dir, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), extension); + if (saveFile.isEmpty()) + return false; + + fw->setFileName(saveFile); + return writeOutForm(fw, saveFile); +} + +void QDesignerActions::saveForm() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + if (saveForm(fw)) + showStatusBarMessage(savedMessage(QFileInfo(fw->fileName()).fileName())); + } +} + +void QDesignerActions::saveAllForms() +{ + QString fileNames; + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + if (const int totalWindows = formWindowManager->formWindowCount()) { + const QString separator = QLatin1String(", "); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindowInterface *fw = formWindowManager->formWindow(i); + if (fw && fw->isDirty()) { + formWindowManager->setActiveFormWindow(fw); + if (saveForm(fw)) { + if (!fileNames.isEmpty()) + fileNames += separator; + fileNames += QFileInfo(fw->fileName()).fileName(); + } else { + break; + } + } + } + } + + if (!fileNames.isEmpty()) { + showStatusBarMessage(savedMessage(fileNames)); + } +} + +bool QDesignerActions::saveForm(QDesignerFormWindowInterface *fw) +{ + bool ret; + if (fw->fileName().isEmpty()) + ret = saveFormAs(fw); + else + ret = writeOutForm(fw, fw->fileName()); + return ret; +} + +void QDesignerActions::closeForm() +{ + if (m_previewManager->previewCount()) { + closePreview(); + return; + } + + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) + if (QWidget *parent = fw->parentWidget()) { + if (QMdiSubWindow *mdiSubWindow = qobject_cast<QMdiSubWindow *>(parent->parentWidget())) { + mdiSubWindow->close(); + } else { + parent->close(); + } + } +} + +void QDesignerActions::saveFormAs() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + if (saveFormAs(fw)) + showStatusBarMessage(savedMessage(fw->fileName())); + } +} + +void QDesignerActions::saveFormAsTemplate() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + SaveFormAsTemplate dlg(core(), fw, fw->window()); + dlg.exec(); + } +} + +void QDesignerActions::notImplementedYet() +{ + QMessageBox::information(core()->topLevel(), tr("Designer"), tr("Feature not implemented yet!")); +} + +void QDesignerActions::closePreview() +{ + m_previewManager->closeAllPreviews(); +} + +void QDesignerActions::viewCode() +{ + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + QString errorMessage; + if (!qdesigner_internal::CodeDialog::showCodeDialog(fw, fw, &errorMessage)) + QMessageBox::warning(fw, tr("Code generation failed"), errorMessage); +} + +void QDesignerActions::fixActionContext() +{ + QList<QAction*> actions; + actions += m_fileActions->actions(); + actions += m_editActions->actions(); + actions += m_toolActions->actions(); + actions += m_formActions->actions(); + actions += m_windowActions->actions(); + actions += m_helpActions->actions(); + + foreach (QAction *a, actions) { + a->setShortcutContext(Qt::ApplicationShortcut); + } +} + +bool QDesignerActions::readInForm(const QString &fileName) +{ + QString fn = fileName; + + // First make sure that we don't have this one open already. + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + const int totalWindows = formWindowManager->formWindowCount(); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindowInterface *w = formWindowManager->formWindow(i); + if (w->fileName() == fn) { + w->raise(); + formWindowManager->setActiveFormWindow(w); + addRecentFile(fn); + return true; + } + } + + // Otherwise load it. + do { + QString errorMessage; + if (workbench()->openForm(fn, &errorMessage)) { + addRecentFile(fn); + m_openDirectory = QFileInfo(fn).absolutePath(); + return true; + } else { + // prompt to reload + QMessageBox box(QMessageBox::Warning, tr("Read error"), + tr("%1\nDo you want to update the file location or generate a new form?").arg(errorMessage), + QMessageBox::Cancel, core()->topLevel()); + + QPushButton *updateButton = box.addButton(tr("&Update"), QMessageBox::ActionRole); + QPushButton *newButton = box.addButton(tr("&New Form"), QMessageBox::ActionRole); + box.exec(); + if (box.clickedButton() == box.button(QMessageBox::Cancel)) + return false; + + if (box.clickedButton() == updateButton) { + const QString extension = uiExtension(); + fn = QFileDialog::getOpenFileName(core()->topLevel(), + tr("Open Form"), m_openDirectory, + tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet); + + if (fn.isEmpty()) + return false; + } else if (box.clickedButton() == newButton) { + // If the file does not exist, but its directory, is valid, open the template with the editor file name set to it. + // (called from command line). + QString newFormFileName; + const QFileInfo fInfo(fn); + if (!fInfo.exists()) { + // Normalize file name + const QString directory = fInfo.absolutePath(); + if (QDir(directory).exists()) { + newFormFileName = directory; + newFormFileName += QLatin1Char('/'); + newFormFileName += fInfo.fileName(); + } + } + showNewFormDialog(newFormFileName); + return false; + } + } + } while (true); + return true; +} + +static QString createBackup(const QString &fileName) +{ + const QString suffix = QLatin1String(".bak"); + QString backupFile = fileName + suffix; + QFileInfo fi(backupFile); + int i = 0; + while (fi.exists()) { + backupFile = fileName + suffix + QString::number(++i); + fi.setFile(backupFile); + } + + if (QFile::copy(fileName, backupFile)) + return backupFile; + return QString(); +} + +static void removeBackup(const QString &backupFile) +{ + if (!backupFile.isEmpty()) + QFile::remove(backupFile); +} + +bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile) +{ + Q_ASSERT(fw && !saveFile.isEmpty()); + + QString backupFile; + QFileInfo fi(saveFile); + if (fi.exists()) + backupFile = createBackup(saveFile); + + QString contents = fw->contents(); + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fw)) { + if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator) + contents.replace(QLatin1Char('\n'), QLatin1String("\r\n")); + } + const QByteArray utf8Array = contents.toUtf8(); + m_workbench->updateBackup(fw); + + QFile f(saveFile); + while (!f.open(QFile::WriteOnly)) { + QMessageBox box(QMessageBox::Warning, + tr("Save Form?"), + tr("Could not open file"), + QMessageBox::NoButton, fw); + + box.setWindowModality(Qt::WindowModal); + box.setInformativeText(tr("The file %1 could not be opened." + "\nReason: %2" + "\nWould you like to retry or select a different file?") + .arg(f.fileName()).arg(f.errorString())); + QPushButton *retryButton = box.addButton(QMessageBox::Retry); + retryButton->setDefault(true); + QPushButton *switchButton = box.addButton(tr("Select New File"), QMessageBox::AcceptRole); + QPushButton *cancelButton = box.addButton(QMessageBox::Cancel); + box.exec(); + + if (box.clickedButton() == cancelButton) { + removeBackup(backupFile); + return false; + } else if (box.clickedButton() == switchButton) { + QString extension = uiExtension(); + const QString fileName = QFileDialog::getSaveFileName(fw, tr("Save Form As"), + QDir::current().absolutePath(), + QLatin1String("*.") + extension); + if (fileName.isEmpty()) { + removeBackup(backupFile); + return false; + } + if (f.fileName() != fileName) { + removeBackup(backupFile); + fi.setFile(fileName); + backupFile.clear(); + if (fi.exists()) + backupFile = createBackup(fileName); + } + f.setFileName(fileName); + fw->setFileName(fileName); + } + // loop back around... + } + while (f.write(utf8Array, utf8Array.size()) != utf8Array.size()) { + QMessageBox box(QMessageBox::Warning, tr("Save Form?"), + tr("Could not write file"), + QMessageBox::Retry|QMessageBox::Cancel, fw); + box.setWindowModality(Qt::WindowModal); + box.setInformativeText(tr("It was not possible to write the entire file %1 to disk." + "\nReason:%2\nWould you like to retry?") + .arg(f.fileName()).arg(f.errorString())); + box.setDefaultButton(QMessageBox::Retry); + switch (box.exec()) { + case QMessageBox::Retry: + f.resize(0); + break; + default: + return false; + } + } + f.close(); + removeBackup(backupFile); + addRecentFile(saveFile); + m_saveDirectory = QFileInfo(f).absolutePath(); + + fw->setDirty(false); + fw->parentWidget()->setWindowModified(false); + return true; +} + +void QDesignerActions::shutdown() +{ + // Follow the idea from the Mac, i.e. send the Application a close event + // and if it's accepted, quit. + QCloseEvent ev; + QApplication::sendEvent(qDesigner, &ev); + if (ev.isAccepted()) + qDesigner->quit(); +} + +void QDesignerActions::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + const bool enable = formWindow != 0; + m_saveFormAction->setEnabled(enable); + m_saveFormAsAction->setEnabled(enable); + m_saveAllFormsAction->setEnabled(enable); + m_saveFormAsTemplateAction->setEnabled(enable); + m_closeFormAction->setEnabled(enable); + m_savePreviewImageAction->setEnabled(enable); + m_printPreviewAction->setEnabled(enable); + + m_editWidgetsAction->setEnabled(enable); + + m_previewFormAction->setEnabled(enable); + m_viewCodeAction->setEnabled(enable); + m_styleActions->setEnabled(enable); +} + +void QDesignerActions::formWindowSettingsChanged(QDesignerFormWindowInterface *fw) +{ + if (QDesignerFormWindow *window = m_workbench->findFormWindow(fw)) + window->updateChanged(); +} + +void QDesignerActions::updateRecentFileActions() +{ + QStringList files = m_settings.recentFilesList(); + const int originalSize = files.size(); + int numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + const QList<QAction *> recentFilesActs = m_recentFilesActions->actions(); + + for (int i = 0; i < numRecentFiles; ++i) { + const QFileInfo fi(files[i]); + // If the file doesn't exist anymore, just remove it from the list so + // people don't get confused. + if (!fi.exists()) { + files.removeAt(i); + --i; + numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + continue; + } + const QString text = fi.fileName(); + recentFilesActs[i]->setText(text); + recentFilesActs[i]->setIconText(files[i]); + recentFilesActs[i]->setVisible(true); + } + + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFilesActs[j]->setVisible(false); + + // If there's been a change, right it back + if (originalSize != files.size()) + m_settings.setRecentFilesList(files); +} + +void QDesignerActions::openRecentForm() +{ + if (const QAction *action = qobject_cast<const QAction *>(sender())) { + if (!readInForm(action->iconText())) + updateRecentFileActions(); // File doesn't exist, remove it from settings + } +} + +void QDesignerActions::clearRecentFiles() +{ + m_settings.setRecentFilesList(QStringList()); + updateRecentFileActions(); +} + +QActionGroup *QDesignerActions::recentFilesActions() const +{ + return m_recentFilesActions; +} + +void QDesignerActions::addRecentFile(const QString &fileName) +{ + QStringList files = m_settings.recentFilesList(); + files.removeAll(fileName); + files.prepend(fileName); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + m_settings.setRecentFilesList(files); + updateRecentFileActions(); +} + +QAction *QDesignerActions::openFormAction() const +{ + return m_openFormAction; +} + +QAction *QDesignerActions::closeFormAction() const +{ + return m_closeFormAction; +} + +QAction *QDesignerActions::minimizeAction() const +{ + return m_minimizeAction; +} + +void QDesignerActions::showDesignerHelp() +{ + QString url = AssistantClient::designerManualUrl(); + url += QLatin1String("designer-manual.html"); + showHelp(url); +} + +void QDesignerActions::showWhatsNew() +{ + QString url = AssistantClient::qtReferenceManualUrl(); + url += QLatin1String("qt4-designer.html"); + showHelp(url); +} + +void QDesignerActions::helpRequested(const QString &manual, const QString &document) +{ + QString url = AssistantClient::documentUrl(manual); + url += document; + showHelp(url); +} + +void QDesignerActions::showHelp(const QString &url) +{ + QString errorMessage; + if (!m_assistantClient.showPage(url, &errorMessage)) + QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage); +} + +void QDesignerActions::aboutDesigner() +{ + VersionDialog mb(core()->topLevel()); + mb.setWindowTitle(tr("About Qt Designer")); + if (mb.exec()) { + QMessageBox messageBox(QMessageBox::Information, QLatin1String("Easter Egg"), + QLatin1String("Easter Egg"), QMessageBox::Ok, core()->topLevel()); + messageBox.setInformativeText(QLatin1String("The Easter Egg has been removed.")); + messageBox.exec(); + } +} + +QAction *QDesignerActions::editWidgets() const +{ + return m_editWidgetsAction; +} + +void QDesignerActions::showWidgetSpecificHelp() +{ + QString helpId; + if (const qdesigner_internal::QDesignerIntegration *integration = qobject_cast<qdesigner_internal::QDesignerIntegration *>(core()->integration())) + helpId = integration->contextHelpId(); + + if (helpId.isEmpty()) { + showDesignerHelp(); + return; + } + + QString errorMessage; + const bool rc = m_assistantClient.activateIdentifier(helpId, &errorMessage); + if (!rc) + QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage); +} + +void QDesignerActions::updateCloseAction() +{ + if (m_previewManager->previewCount()) { + m_closeFormAction->setText(tr("&Close Preview")); + } else { + m_closeFormAction->setText(tr("&Close")); + } +} + +void QDesignerActions::backupForms() +{ + const int count = m_workbench->formWindowCount(); + if (!count || !ensureBackupDirectories()) + return; + + + QStringList tmpFiles; + QMap<QString, QString> backupMap; + QDir backupDir(m_backupPath); + const bool warningsEnabled = qdesigner_internal::QSimpleResource::setWarningsEnabled(false); + for (int i = 0; i < count; ++i) { + QDesignerFormWindow *fw = m_workbench->formWindow(i); + QDesignerFormWindowInterface *fwi = fw->editor(); + + QString formBackupName; + QTextStream(&formBackupName) << m_backupPath << QDir::separator() + << QLatin1String("backup") << i << QLatin1String(".bak"); + + QString fwn = QDir::convertSeparators(fwi->fileName()); + if (fwn.isEmpty()) + fwn = fw->windowTitle(); + + backupMap.insert(fwn, formBackupName); + + QFile file(formBackupName.replace(m_backupPath, m_backupTmpPath)); + if (file.open(QFile::WriteOnly)){ + QString contents = fixResourceFileBackupPath(fwi, backupDir); + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fwi)) { + if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator) + contents.replace(QLatin1Char('\n'), QLatin1String("\r\n")); + } + const QByteArray utf8Array = contents.toUtf8(); + if (file.write(utf8Array, utf8Array.size()) != utf8Array.size()) { + backupMap.remove(fwn); + qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(file.fileName())); + } else + tmpFiles.append(formBackupName); + + file.close(); + } + } + qdesigner_internal::QSimpleResource::setWarningsEnabled(warningsEnabled); + if(!tmpFiles.isEmpty()) { + const QStringList backupFiles = backupDir.entryList(QDir::Files); + if(!backupFiles.isEmpty()) { + QStringListIterator it(backupFiles); + while (it.hasNext()) + backupDir.remove(it.next()); + } + + QStringListIterator it(tmpFiles); + while (it.hasNext()) { + const QString tmpName = it.next(); + QString name(tmpName); + name.replace(m_backupTmpPath, m_backupPath); + QFile tmpFile(tmpName); + if (!tmpFile.copy(name)) + qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(name)); + tmpFile.remove(); + } + + m_settings.setBackup(backupMap); + } +} + +QString QDesignerActions::fixResourceFileBackupPath(QDesignerFormWindowInterface *fwi, const QDir& backupDir) +{ + const QString content = fwi->contents(); + QDomDocument domDoc(QLatin1String("backup")); + if(!domDoc.setContent(content)) + return content; + + const QDomNodeList list = domDoc.elementsByTagName(QLatin1String("resources")); + if (list.isEmpty()) + return content; + + for (int i = 0; i < list.count(); i++) { + const QDomNode node = list.at(i); + if (!node.isNull()) { + const QDomElement element = node.toElement(); + if(!element.isNull() && element.tagName() == QLatin1String("resources")) { + QDomNode childNode = element.firstChild(); + while (!childNode.isNull()) { + QDomElement childElement = childNode.toElement(); + if(!childElement.isNull() && childElement.tagName() == QLatin1String("include")) { + const QString attr = childElement.attribute(QLatin1String("location")); + const QString path = fwi->absoluteDir().absoluteFilePath(attr); + childElement.setAttribute(QLatin1String("location"), backupDir.relativeFilePath(path)); + } + childNode = childNode.nextSibling(); + } + } + } + } + + + return domDoc.toString(); +} + +QRect QDesignerActions::fixDialogRect(const QRect &rect) const +{ + QRect frameGeometry; + const QRect availableGeometry = QApplication::desktop()->availableGeometry(core()->topLevel()); + + if (workbench()->mode() == DockedMode) { + frameGeometry = core()->topLevel()->frameGeometry(); + } else + frameGeometry = availableGeometry; + + QRect dlgRect = rect; + dlgRect.moveCenter(frameGeometry.center()); + + // make sure that parts of the dialog are not outside of screen + dlgRect.moveBottom(qMin(dlgRect.bottom(), availableGeometry.bottom())); + dlgRect.moveRight(qMin(dlgRect.right(), availableGeometry.right())); + dlgRect.moveLeft(qMax(dlgRect.left(), availableGeometry.left())); + dlgRect.moveTop(qMax(dlgRect.top(), availableGeometry.top())); + + return dlgRect; +} + +void QDesignerActions::showStatusBarMessage(const QString &message) const +{ + if (workbench()->mode() == DockedMode) { + QStatusBar *bar = qDesigner->mainWindow()->statusBar(); + if (bar && !bar->isHidden()) + bar->showMessage(message, 3000); + } +} + +void QDesignerActions::setBringAllToFrontVisible(bool visible) +{ + m_bringAllToFrontSeparator->setVisible(visible); + m_bringAllToFrontAction->setVisible(visible); +} + +void QDesignerActions::setWindowListSeparatorVisible(bool visible) +{ + m_windowListSeparatorAction->setVisible(visible); +} + +bool QDesignerActions::ensureBackupDirectories() { + + if (m_backupPath.isEmpty()) { + // create names + m_backupPath = QDir::homePath(); + m_backupPath += QDir::separator(); + m_backupPath += QLatin1String(".designer"); + m_backupPath += QDir::separator(); + m_backupPath += QLatin1String("backup"); + m_backupPath = QDir::convertSeparators(m_backupPath ); + + m_backupTmpPath = m_backupPath; + m_backupTmpPath += QDir::separator(); + m_backupTmpPath += QLatin1String("tmp"); + m_backupTmpPath = QDir::convertSeparators(m_backupTmpPath); + } + + // ensure directories + const QDir backupDir(m_backupPath); + const QDir backupTmpDir(m_backupTmpPath); + + if (!backupDir.exists()) { + if (!backupDir.mkpath(m_backupPath)) { + qdesigner_internal::designerWarning(tr("The backup directory %1 could not be created.").arg(m_backupPath)); + return false; + } + } + if (!backupTmpDir.exists()) { + if (!backupTmpDir.mkpath(m_backupTmpPath)) { + qdesigner_internal::designerWarning(tr("The temporary backup directory %1 could not be created.").arg(m_backupTmpPath)); + return false; + } + } + return true; +} + +void QDesignerActions::showPreferencesDialog() +{ + PreferencesDialog preferencesDialog(workbench()->core(), m_core->topLevel()); + preferencesDialog.exec(); +} + +void QDesignerActions::showAppFontDialog() +{ + if (!m_appFontDialog) // Might get deleted when switching ui modes + m_appFontDialog = new AppFontDialog(core()->topLevel()); + m_appFontDialog->show(); + m_appFontDialog->raise(); +} + +QPixmap QDesignerActions::createPreviewPixmap(QDesignerFormWindowInterface *fw) +{ + const QCursor oldCursor = core()->topLevel()->cursor(); + core()->topLevel()->setCursor(Qt::WaitCursor); + + QString errorMessage; + const QPixmap pixmap = m_previewManager->createPreviewPixmap(fw, QString(), &errorMessage); + core()->topLevel()->setCursor(oldCursor); + if (pixmap.isNull()) { + QMessageBox::warning(fw, tr("Preview failed"), errorMessage); + } + return pixmap; +} + +qdesigner_internal::PreviewConfiguration QDesignerActions::previewConfiguration() +{ + qdesigner_internal::PreviewConfiguration pc; + QDesignerSharedSettings settings(core()); + if (settings.isCustomPreviewConfigurationEnabled()) + pc = settings.customPreviewConfiguration(); + return pc; +} + +void QDesignerActions::savePreviewImage() +{ + const char *format = "png"; + + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + + QImage image; + const QString extension = QString::fromAscii(format); + const QString filter = tr("Image files (*.%1)").arg(extension); + + QString suggestion = fw->fileName(); + if (!suggestion.isEmpty()) { + suggestion = QFileInfo(suggestion).baseName(); + suggestion += QLatin1Char('.'); + suggestion += extension; + } + do { + const QString fileName = getSaveFileNameWithExtension(fw, tr("Save Image"), suggestion, filter, extension); + if (fileName.isEmpty()) + break; + + if (image.isNull()) { + const QPixmap pixmap = createPreviewPixmap(fw); + if (pixmap.isNull()) + break; + + image = pixmap.toImage(); + } + + if (image.save(fileName, format)) { + showStatusBarMessage(tr("Saved image %1.").arg(QFileInfo(fileName).fileName())); + break; + } + + QMessageBox box(QMessageBox::Warning, tr("Save Image"), + tr("The file %1 could not be written.").arg( fileName), + QMessageBox::Retry|QMessageBox::Cancel, fw); + if (box.exec() == QMessageBox::Cancel) + break; + } while (true); +} + +void QDesignerActions::formWindowCountChanged() +{ + const bool enabled = m_core->formWindowManager()->formWindowCount() == 0; + /* Disable the application font action if there are form windows open + * as the reordering of the fonts sets font properties to 'changed' + * and overloaded fonts are not updated. */ + static const QString disabledTip = tr("Please close all forms to enable the loading of additional fonts."); + m_appFontAction->setEnabled(enabled); + m_appFontAction->setStatusTip(enabled ? QString() : disabledTip); +} + +void QDesignerActions::printPreviewImage() +{ +#ifndef QT_NO_PRINTER + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + + if (!m_printer) + m_printer = new QPrinter(QPrinter::HighResolution); + + m_printer->setFullPage(false); + + // Grab the image to be able to a suggest suitable orientation + const QPixmap pixmap = createPreviewPixmap(fw); + if (pixmap.isNull()) + return; + + const QSizeF pixmapSize = pixmap.size(); + m_printer->setOrientation( pixmapSize.width() > pixmapSize.height() ? QPrinter::Landscape : QPrinter::Portrait); + + // Printer parameters + QPrintDialog dialog(m_printer, fw); + if (!dialog.exec()) + return; + + const QCursor oldCursor = core()->topLevel()->cursor(); + core()->topLevel()->setCursor(Qt::WaitCursor); + // Estimate of required scaling to make form look the same on screen and printer. + const double suggestedScaling = static_cast<double>(m_printer->physicalDpiX()) / static_cast<double>(fw->physicalDpiX()); + + QPainter painter(m_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); + core()->topLevel()->setCursor(oldCursor); + + showStatusBarMessage(tr("Printed %1.").arg(QFileInfo(fw->fileName()).fileName())); +#endif +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_actions.h b/src/designer/src/designer/qdesigner_actions.h new file mode 100644 index 000000000..910901bcb --- /dev/null +++ b/src/designer/src/designer/qdesigner_actions.h @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_ACTIONS_H +#define QDESIGNER_ACTIONS_H + +#include "assistantclient.h" +#include "qdesigner_settings.h" + +#include <QtCore/QObject> +#include <QtCore/QPointer> +#include <QtGui/QPrinter> + +QT_BEGIN_NAMESPACE + +class QDesignerWorkbench; + +class QDir; +class QTimer; +class QAction; +class QActionGroup; +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class AppFontDialog; + +class QRect; +class QWidget; +class QPixmap; +class QMenu; + +namespace qdesigner_internal { + class PreviewConfiguration; + class PreviewManager; +} + +class QDesignerActions: public QObject +{ + Q_OBJECT +public: + explicit QDesignerActions(QDesignerWorkbench *mainWindow); + virtual ~QDesignerActions(); + + QDesignerWorkbench *workbench() const; + QDesignerFormEditorInterface *core() const; + + bool saveForm(QDesignerFormWindowInterface *fw); + bool readInForm(const QString &fileName); + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName); + + QActionGroup *fileActions() const; + QActionGroup *recentFilesActions() const; + QActionGroup *editActions() const; + QActionGroup *formActions() const; + QActionGroup *settingsActions() const; + QActionGroup *windowActions() const; + QActionGroup *toolActions() const; + QActionGroup *helpActions() const; + QActionGroup *uiMode() const; + QActionGroup *styleActions() const; + // file actions + QAction *openFormAction() const; + QAction *closeFormAction() const; + // window actions + QAction *minimizeAction() const; + // edit mode actions + QAction *editWidgets() const; + // form actions + QAction *previewFormAction() const; + QAction *viewCodeAction() const; + + void setBringAllToFrontVisible(bool visible); + void setWindowListSeparatorVisible(bool visible); + + bool openForm(QWidget *parent); + + QString uiExtension() const; + + // Boolean dynamic property set on actions to + // show them in the default toolbar layout + static const char *defaultToolbarPropertyName; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + void createForm(); + void slotOpenForm(); + void helpRequested(const QString &manual, const QString &document); + +signals: + void useBigIcons(bool); + +private slots: + void saveForm(); + void saveFormAs(); + void saveAllForms(); + void saveFormAsTemplate(); + void viewCode(); + void notImplementedYet(); + void shutdown(); + void editWidgetsSlot(); + void openRecentForm(); + void clearRecentFiles(); + void closeForm(); + void showDesignerHelp(); + void showWhatsNew(); + void aboutDesigner(); + void showWidgetSpecificHelp(); + void backupForms(); + void showNewFormDialog(const QString &fileName); + void showPreferencesDialog(); + void showAppFontDialog(); + void savePreviewImage(); + void printPreviewImage(); + void updateCloseAction(); + void formWindowCountChanged(); + void formWindowSettingsChanged(QDesignerFormWindowInterface *fw); + +private: + QAction *createRecentFilesMenu(); + bool saveFormAs(QDesignerFormWindowInterface *fw); + void fixActionContext(); + void updateRecentFileActions(); + void addRecentFile(const QString &fileName); + void showHelp(const QString &help); + void closePreview(); + QRect fixDialogRect(const QRect &rect) const; + QString fixResourceFileBackupPath(QDesignerFormWindowInterface *fwi, const QDir& backupDir); + void showStatusBarMessage(const QString &message) const; + QActionGroup *createHelpActions(); + bool ensureBackupDirectories(); + QPixmap createPreviewPixmap(QDesignerFormWindowInterface *fw); + qdesigner_internal::PreviewConfiguration previewConfiguration(); + + enum { MaxRecentFiles = 10 }; + QDesignerWorkbench *m_workbench; + QDesignerFormEditorInterface *m_core; + QDesignerSettings m_settings; + AssistantClient m_assistantClient; + QString m_openDirectory; + QString m_saveDirectory; + + + QString m_backupPath; + QString m_backupTmpPath; + + QTimer* m_backupTimer; + + QActionGroup *m_fileActions; + QActionGroup *m_recentFilesActions; + QActionGroup *m_editActions; + QActionGroup *m_formActions; + QActionGroup *m_settingsActions; + QActionGroup *m_windowActions; + QActionGroup *m_toolActions; + QActionGroup *m_helpActions; + QActionGroup *m_styleActions; + + QAction *m_editWidgetsAction; + + QAction *m_newFormAction; + QAction *m_openFormAction; + QAction *m_saveFormAction; + QAction *m_saveFormAsAction; + QAction *m_saveAllFormsAction; + QAction *m_saveFormAsTemplateAction; + QAction *m_closeFormAction; + QAction *m_savePreviewImageAction; + QAction *m_printPreviewAction; + + QAction *m_quitAction; + + QAction *m_previewFormAction; + QAction *m_viewCodeAction; + + QAction *m_minimizeAction; + QAction *m_bringAllToFrontSeparator; + QAction *m_bringAllToFrontAction; + QAction *m_windowListSeparatorAction; + + QAction *m_preferencesAction; + QAction *m_appFontAction; + + QPointer<AppFontDialog> m_appFontDialog; + +#ifndef QT_NO_PRINTER + QPrinter *m_printer; +#endif + + qdesigner_internal::PreviewManager *m_previewManager; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_ACTIONS_H diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.cpp b/src/designer/src/designer/qdesigner_appearanceoptions.cpp new file mode 100644 index 000000000..f5b3f3d6d --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_appearanceoptions.h" +#include "ui_qdesigner_appearanceoptions.h" + +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtCore/QTimer> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +// ---------------- AppearanceOptions +AppearanceOptions::AppearanceOptions() : + uiMode(DockedMode) +{ +} + +bool AppearanceOptions::equals(const AppearanceOptions &rhs) const +{ + return uiMode == rhs.uiMode && toolWindowFontSettings == rhs.toolWindowFontSettings; +} + +void AppearanceOptions::toSettings(QDesignerSettings &settings) const +{ + settings.setUiMode(uiMode); + settings.setToolWindowFont(toolWindowFontSettings); +} + +void AppearanceOptions::fromSettings(const QDesignerSettings &settings) +{ + uiMode = settings.uiMode(); + toolWindowFontSettings = settings.toolWindowFont(); +} + +// ---------------- QDesignerAppearanceOptionsWidget +QDesignerAppearanceOptionsWidget::QDesignerAppearanceOptionsWidget(QWidget *parent) : + QWidget(parent), + m_ui(new Ui::AppearanceOptionsWidget), + m_initialUIMode(NeutralMode) +{ + m_ui->setupUi(this); + + m_ui->m_uiModeCombo->addItem(tr("Docked Window"), QVariant(DockedMode)); + m_ui->m_uiModeCombo->addItem(tr("Multiple Top-Level Windows"), QVariant(TopLevelMode)); + connect(m_ui->m_uiModeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(slotUiModeComboChanged())); + + m_ui->m_fontPanel->setCheckable(true); + m_ui->m_fontPanel->setTitle(tr("Toolwindow Font")); + +} + +QDesignerAppearanceOptionsWidget::~QDesignerAppearanceOptionsWidget() +{ + delete m_ui; +} + +UIMode QDesignerAppearanceOptionsWidget::uiMode() const +{ + return static_cast<UIMode>(m_ui->m_uiModeCombo->itemData(m_ui->m_uiModeCombo->currentIndex()).toInt()); +} + +AppearanceOptions QDesignerAppearanceOptionsWidget::appearanceOptions() const +{ + AppearanceOptions rc; + rc.uiMode = uiMode(); + rc.toolWindowFontSettings.m_font = m_ui->m_fontPanel->selectedFont(); + rc.toolWindowFontSettings.m_useFont = m_ui->m_fontPanel->isChecked(); + rc.toolWindowFontSettings.m_writingSystem = m_ui->m_fontPanel->writingSystem(); + return rc; +} + +void QDesignerAppearanceOptionsWidget::setAppearanceOptions(const AppearanceOptions &ao) +{ + m_initialUIMode = ao.uiMode; + m_ui->m_uiModeCombo->setCurrentIndex(m_ui->m_uiModeCombo->findData(QVariant(ao.uiMode))); + m_ui->m_fontPanel->setWritingSystem(ao.toolWindowFontSettings.m_writingSystem); + m_ui->m_fontPanel->setSelectedFont(ao.toolWindowFontSettings.m_font); + m_ui->m_fontPanel->setChecked(ao.toolWindowFontSettings.m_useFont); +} + +void QDesignerAppearanceOptionsWidget::slotUiModeComboChanged() +{ + emit uiModeChanged(m_initialUIMode != uiMode()); +} + +// ----------- QDesignerAppearanceOptionsPage +QDesignerAppearanceOptionsPage::QDesignerAppearanceOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString QDesignerAppearanceOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("QDesignerAppearanceOptionsPage", "Appearance"); +} + +QWidget *QDesignerAppearanceOptionsPage::createPage(QWidget *parent) +{ + m_widget = new QDesignerAppearanceOptionsWidget(parent); + m_initialOptions.fromSettings(QDesignerSettings(m_core)); + m_widget->setAppearanceOptions(m_initialOptions); + return m_widget; +} + +void QDesignerAppearanceOptionsPage::apply() +{ + if (m_widget) { + const AppearanceOptions newOptions = m_widget->appearanceOptions(); + if (newOptions != m_initialOptions) { + QDesignerSettings settings(m_core); + newOptions.toSettings(settings); + QTimer::singleShot(0, this, SIGNAL(settingsChangedDelayed())); + m_initialOptions = newOptions; + } + } +} + +void QDesignerAppearanceOptionsPage::finish() +{ +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.h b/src/designer/src/designer/qdesigner_appearanceoptions.h new file mode 100644 index 000000000..a6e4f9a49 --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_APPEARANCEOPTIONS_H +#define QDESIGNER_APPEARANCEOPTIONS_H + +#include "designer_enums.h" +#include "qdesigner_toolwindow.h" + +#include <QtDesigner/private/abstractoptionspage_p.h> +#include <QtCore/QObject> +#include <QtCore/QPointer> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerSettings; + +namespace Ui { + class AppearanceOptionsWidget; +} + +/* AppearanceOptions data */ +struct AppearanceOptions { + AppearanceOptions(); + bool equals(const AppearanceOptions&) const; + void toSettings(QDesignerSettings &) const; + void fromSettings(const QDesignerSettings &); + + UIMode uiMode; + ToolWindowFontSettings toolWindowFontSettings; +}; + +inline bool operator==(const AppearanceOptions &ao1, const AppearanceOptions &ao2) +{ + return ao1.equals(ao2); +} + +inline bool operator!=(const AppearanceOptions &ao1, const AppearanceOptions &ao2) +{ + return !ao1.equals(ao2); +} + +/* QDesignerAppearanceOptionsWidget: Let the user edit AppearanceOptions */ +class QDesignerAppearanceOptionsWidget : public QWidget +{ + Q_OBJECT +public: + explicit QDesignerAppearanceOptionsWidget(QWidget *parent = 0); + ~QDesignerAppearanceOptionsWidget(); + + AppearanceOptions appearanceOptions() const; + void setAppearanceOptions(const AppearanceOptions &ao); + +signals: + void uiModeChanged(bool modified); + +private slots: + void slotUiModeComboChanged(); + +private: + UIMode uiMode() const; + + Ui::AppearanceOptionsWidget *m_ui; + UIMode m_initialUIMode; +}; + +/* The options page for appearance options. Emits a Timer-0 delayed changed + * signal to allow the preferences dialog to close (and be deleted) before a + * possible switch from docked mode to top-level mode happens. (The switch + * would delete the main window, which the preference dialog is a child of + * -> BOOM) */ + +class QDesignerAppearanceOptionsPage : public QObject, public QDesignerOptionsPageInterface +{ + Q_OBJECT + +public: + QDesignerAppearanceOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +signals: + void settingsChangedDelayed(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer<QDesignerAppearanceOptionsWidget> m_widget; + AppearanceOptions m_initialOptions; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_APPEARANCEOPTIONS_H diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.ui b/src/designer/src/designer/qdesigner_appearanceoptions.ui new file mode 100644 index 000000000..a5582f2ab --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.ui @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AppearanceOptionsWidget</class> + <widget class="QWidget" name="AppearanceOptionsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>325</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="m_uiModeGroupBox"> + <property name="title"> + <string>User Interface Mode</string> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QComboBox" name="m_uiModeCombo"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="FontPanel" name="m_fontPanel"/> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>FontPanel</class> + <extends>QGroupBox</extends> + <header>fontpanel.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/designer/src/designer/qdesigner_formwindow.cpp b/src/designer/src/designer/qdesigner_formwindow.cpp new file mode 100644 index 000000000..4770d2a58 --- /dev/null +++ b/src/designer/src/designer/qdesigner_formwindow.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** 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()); + updateChanged(); + } + } + 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 diff --git a/src/designer/src/designer/qdesigner_formwindow.h b/src/designer/src/designer/qdesigner_formwindow.h new file mode 100644 index 000000000..5ee4c40b4 --- /dev/null +++ b/src/designer/src/designer/qdesigner_formwindow.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_FORMWINDOW_H +#define QDESIGNER_FORMWINDOW_H + +#include <QtCore/QPointer> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerWorkbench; +class QDesignerFormWindowInterface; + +class QDesignerFormWindow: public QWidget +{ + Q_OBJECT +public: + QDesignerFormWindow(QDesignerFormWindowInterface *formWindow, QDesignerWorkbench *workbench, + QWidget *parent = 0, Qt::WindowFlags flags = 0); + + void firstShow(); + + virtual ~QDesignerFormWindow(); + + QAction *action() const; + QDesignerWorkbench *workbench() const; + QDesignerFormWindowInterface *editor() const; + + QRect geometryHint() const; + +public slots: + void updateChanged(); + +private slots: + void updateWindowTitle(const QString &fileName); + void geometryChanged(); + +signals: + void minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized); + void triggerAction(); + +protected: + virtual void changeEvent(QEvent *e); + virtual void closeEvent(QCloseEvent *ev); + virtual void resizeEvent(QResizeEvent* rev); + +private: + int getNumberOfUntitledWindows() const; + QPointer<QDesignerFormWindowInterface> m_editor; + QPointer<QDesignerWorkbench> m_workbench; + QAction *m_action; + bool m_initialized; + bool m_windowTitleInitialized; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_FORMWINDOW_H diff --git a/src/designer/src/designer/qdesigner_pch.h b/src/designer/src/designer/qdesigner_pch.h new file mode 100644 index 000000000..12eb3f376 --- /dev/null +++ b/src/designer/src/designer/qdesigner_pch.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#if defined __cplusplus +#include <QtCore/QObject> +#include <QtCore/QPointer> +#include <QtCore/QSettings> +#include <QtCore/qdebug.h> +#include <QtGui/QCloseEvent> +#include <QtGui/QHeaderView> +#include <QtGui/QMessageBox> +#include <QtGui/QVBoxLayout> +#include <QtDesigner/abstractformeditor.h> +#include <QtDesigner/abstractformwindow.h> + +#include "qdesigner.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_workbench.h" +#endif diff --git a/src/designer/src/designer/qdesigner_server.cpp b/src/designer/src/designer/qdesigner_server.cpp new file mode 100644 index 000000000..bffee5b7e --- /dev/null +++ b/src/designer/src/designer/qdesigner_server.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFileInfo> +#include <QtCore/QStringList> + +#include <QtNetwork/QHostAddress> +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QTcpSocket> + +#include "qdesigner.h" +#include "qdesigner_server.h" + +#include <qevent.h> + +QT_BEGIN_NAMESPACE + +// ### review + +QDesignerServer::QDesignerServer(QObject *parent) + : QObject(parent) +{ + m_socket = 0; + m_server = new QTcpServer(this); + m_server->listen(QHostAddress::LocalHost, 0); + if (m_server->isListening()) + { + connect(m_server, SIGNAL(newConnection()), + this, SLOT(handleNewConnection())); + } +} + +QDesignerServer::~QDesignerServer() +{ +} + +quint16 QDesignerServer::serverPort() const +{ + return m_server ? m_server->serverPort() : 0; +} + +void QDesignerServer::sendOpenRequest(int port, const QStringList &files) +{ + QTcpSocket *sSocket = new QTcpSocket(); + sSocket->connectToHost(QHostAddress::LocalHost, port); + if(sSocket->waitForConnected(3000)) + { + foreach(const QString &file, files) + { + QFileInfo fi(file); + sSocket->write(fi.absoluteFilePath().toUtf8() + '\n'); + } + sSocket->waitForBytesWritten(3000); + sSocket->close(); + } + delete sSocket; +} + +void QDesignerServer::readFromClient() +{ + while (m_socket->canReadLine()) { + QString file = QString::fromUtf8(m_socket->readLine()); + if (!file.isNull()) { + file.remove(QLatin1Char('\n')); + file.remove(QLatin1Char('\r')); + qDesigner->postEvent(qDesigner, new QFileOpenEvent(file)); + } + } +} + +void QDesignerServer::socketClosed() +{ + m_socket = 0; +} + +void QDesignerServer::handleNewConnection() +{ + // no need for more than one connection + if (m_socket == 0) { + m_socket = m_server->nextPendingConnection(); + connect(m_socket, SIGNAL(readyRead()), + this, SLOT(readFromClient())); + connect(m_socket, SIGNAL(disconnected()), + this, SLOT(socketClosed())); + } +} + + +QDesignerClient::QDesignerClient(quint16 port, QObject *parent) +: QObject(parent) +{ + m_socket = new QTcpSocket(this); + m_socket->connectToHost(QHostAddress::LocalHost, port); + connect(m_socket, SIGNAL(readyRead()), + this, SLOT(readFromSocket())); + +} + +QDesignerClient::~QDesignerClient() +{ + m_socket->close(); + m_socket->flush(); +} + +void QDesignerClient::readFromSocket() +{ + while (m_socket->canReadLine()) { + QString file = QString::fromUtf8(m_socket->readLine()); + if (!file.isNull()) { + file.remove(QLatin1Char('\n')); + file.remove(QLatin1Char('\r')); + if (QFile::exists(file)) + qDesigner->postEvent(qDesigner, new QFileOpenEvent(file)); + } + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_server.h b/src/designer/src/designer/qdesigner_server.h new file mode 100644 index 000000000..3aeeebdee --- /dev/null +++ b/src/designer/src/designer/qdesigner_server.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_SERVER_H +#define QDESIGNER_SERVER_H + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QTcpServer; +class QTcpSocket; + +class QDesignerServer: public QObject +{ + Q_OBJECT +public: + explicit QDesignerServer(QObject *parent = 0); + virtual ~QDesignerServer(); + + quint16 serverPort() const; + + static void sendOpenRequest(int port, const QStringList &files); + +private slots: + void handleNewConnection(); + void readFromClient(); + void socketClosed(); + +private: + QTcpServer *m_server; + QTcpSocket *m_socket; +}; + +class QDesignerClient: public QObject +{ + Q_OBJECT +public: + explicit QDesignerClient(quint16 port, QObject *parent = 0); + virtual ~QDesignerClient(); + +private slots: + void readFromSocket(); + +private: + QTcpSocket *m_socket; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_SERVER_H diff --git a/src/designer/src/designer/qdesigner_settings.cpp b/src/designer/src/designer/qdesigner_settings.cpp new file mode 100644 index 000000000..89bec14f2 --- /dev/null +++ b/src/designer/src/designer/qdesigner_settings.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_workbench.h" + +#include <abstractformeditor.h> +#include <abstractsettings_p.h> +#include <qdesigner_utils_p.h> +#include <previewmanager_p.h> + +#include <QtCore/QVariant> +#include <QtCore/QDir> + +#include <QtGui/QDesktopWidget> +#include <QtGui/QStyle> +#include <QtGui/QListView> + +#include <QtCore/qdebug.h> + +enum { debugSettings = 0 }; + +QT_BEGIN_NAMESPACE + +static const char *newFormShowKey = "newFormDialog/ShowOnStartup"; + +// Change the version whenever the arrangement changes significantly. +static const char *mainWindowStateKey = "MainWindowState45"; +static const char *toolBarsStateKey = "ToolBarsState45"; + +static const char *backupOrgListKey = "backup/fileListOrg"; +static const char *backupBakListKey = "backup/fileListBak"; +static const char *recentFilesListKey = "recentFilesList"; + +QDesignerSettings::QDesignerSettings(QDesignerFormEditorInterface *core) : + qdesigner_internal::QDesignerSharedSettings(core) +{ +} + +void QDesignerSettings::setValue(const QString &key, const QVariant &value) +{ + settings()->setValue(key, value); +} + +QVariant QDesignerSettings::value(const QString &key, const QVariant &defaultValue) const +{ + return settings()->value(key, defaultValue); +} + +static inline QChar modeChar(UIMode mode) +{ + return QLatin1Char(static_cast<char>(mode) + '0'); +} + +void QDesignerSettings::saveGeometryFor(const QWidget *w) +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + QDesignerSettingsInterface *s = settings(); + const bool visible = w->isVisible(); + if (debugSettings) + qDebug() << Q_FUNC_INFO << w << "visible=" << visible; + s->beginGroup(w->objectName()); + s->setValue(QLatin1String("visible"), visible); + s->setValue(QLatin1String("geometry"), w->saveGeometry()); + s->endGroup(); +} + +void QDesignerSettings::restoreGeometry(QWidget *w, QRect fallBack) const +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + const QString key = w->objectName(); + const QByteArray ba(settings()->value(key + QLatin1String("/geometry")).toByteArray()); + const bool visible = settings()->value(key + QLatin1String("/visible"), true).toBool(); + + if (debugSettings) + qDebug() << Q_FUNC_INFO << w << fallBack << "visible=" << visible; + if (ba.isEmpty()) { + /// Apply default geometry, check for null and maximal size + if (fallBack.isNull()) + fallBack = QRect(QPoint(0, 0), w->sizeHint()); + if (fallBack.size() == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) { + w->setWindowState(w->windowState() | Qt::WindowMaximized); + } else { + w->move(fallBack.topLeft()); + w->resize(fallBack.size()); + } + } else { + w->restoreGeometry(ba); + } + + if (visible) + w->show(); +} + +QStringList QDesignerSettings::recentFilesList() const +{ + return settings()->value(QLatin1String(recentFilesListKey)).toStringList(); +} + +void QDesignerSettings::setRecentFilesList(const QStringList &sl) +{ + settings()->setValue(QLatin1String(recentFilesListKey), sl); +} + +void QDesignerSettings::setShowNewFormOnStartup(bool showIt) +{ + settings()->setValue(QLatin1String(newFormShowKey), showIt); +} + +bool QDesignerSettings::showNewFormOnStartup() const +{ + return settings()->value(QLatin1String(newFormShowKey), true).toBool(); +} + +QByteArray QDesignerSettings::mainWindowState(UIMode mode) const +{ + return settings()->value(QLatin1String(mainWindowStateKey) + modeChar(mode)).toByteArray(); +} + +void QDesignerSettings::setMainWindowState(UIMode mode, const QByteArray &mainWindowState) +{ + settings()->setValue(QLatin1String(mainWindowStateKey) + modeChar(mode), mainWindowState); +} + +QByteArray QDesignerSettings::toolBarsState(UIMode mode) const +{ + QString key = QLatin1String(toolBarsStateKey); + key += modeChar(mode); + return settings()->value(key).toByteArray(); +} + +void QDesignerSettings::setToolBarsState(UIMode mode, const QByteArray &toolBarsState) +{ + QString key = QLatin1String(toolBarsStateKey); + key += modeChar(mode); + settings()->setValue(key, toolBarsState); +} + +void QDesignerSettings::clearBackup() +{ + QDesignerSettingsInterface *s = settings(); + s->remove(QLatin1String(backupOrgListKey)); + s->remove(QLatin1String(backupBakListKey)); +} + +void QDesignerSettings::setBackup(const QMap<QString, QString> &map) +{ + const QStringList org = map.keys(); + const QStringList bak = map.values(); + + QDesignerSettingsInterface *s = settings(); + s->setValue(QLatin1String(backupOrgListKey), org); + s->setValue(QLatin1String(backupBakListKey), bak); +} + +QMap<QString, QString> QDesignerSettings::backup() const +{ + const QStringList org = settings()->value(QLatin1String(backupOrgListKey), QStringList()).toStringList(); + const QStringList bak = settings()->value(QLatin1String(backupBakListKey), QStringList()).toStringList(); + + QMap<QString, QString> map; + const int orgCount = org.count(); + for (int i = 0; i < orgCount; ++i) + map.insert(org.at(i), bak.at(i)); + + return map; +} + +void QDesignerSettings::setUiMode(UIMode mode) +{ + QDesignerSettingsInterface *s = settings(); + s->beginGroup(QLatin1String("UI")); + s->setValue(QLatin1String("currentMode"), mode); + s->endGroup(); +} + +UIMode QDesignerSettings::uiMode() const +{ +#ifdef Q_WS_MAC + const UIMode defaultMode = TopLevelMode; +#else + const UIMode defaultMode = DockedMode; +#endif + UIMode uiMode = static_cast<UIMode>(value(QLatin1String("UI/currentMode"), defaultMode).toInt()); + return uiMode; +} + +void QDesignerSettings::setToolWindowFont(const ToolWindowFontSettings &fontSettings) +{ + QDesignerSettingsInterface *s = settings(); + s->beginGroup(QLatin1String("UI")); + s->setValue(QLatin1String("font"), fontSettings.m_font); + s->setValue(QLatin1String("useFont"), fontSettings.m_useFont); + s->setValue(QLatin1String("writingSystem"), fontSettings.m_writingSystem); + s->endGroup(); +} + +ToolWindowFontSettings QDesignerSettings::toolWindowFont() const +{ + ToolWindowFontSettings fontSettings; + fontSettings.m_writingSystem = + static_cast<QFontDatabase::WritingSystem>(value(QLatin1String("UI/writingSystem"), + QFontDatabase::Any).toInt()); + fontSettings.m_font = qvariant_cast<QFont>(value(QLatin1String("UI/font"))); + fontSettings.m_useFont = + settings()->value(QLatin1String("UI/useFont"), QVariant(false)).toBool(); + return fontSettings; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_settings.h b/src/designer/src/designer/qdesigner_settings.h new file mode 100644 index 000000000..2391581b8 --- /dev/null +++ b/src/designer/src/designer/qdesigner_settings.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_SETTINGS_H +#define QDESIGNER_SETTINGS_H + +#include "designer_enums.h" +#include <shared_settings_p.h> +#include <QtCore/QMap> +#include <QtCore/QRect> +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerSettingsInterface; +struct ToolWindowFontSettings; + +class QDesignerSettings : public qdesigner_internal::QDesignerSharedSettings +{ +public: + QDesignerSettings(QDesignerFormEditorInterface *core); + + void setValue(const QString &key, const QVariant &value); + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + + void restoreGeometry(QWidget *w, QRect fallBack = QRect()) const; + void saveGeometryFor(const QWidget *w); + + QStringList recentFilesList() const; + void setRecentFilesList(const QStringList &list); + + void setShowNewFormOnStartup(bool showIt); + bool showNewFormOnStartup() const; + + void setUiMode(UIMode mode); + UIMode uiMode() const; + + void setToolWindowFont(const ToolWindowFontSettings &fontSettings); + ToolWindowFontSettings toolWindowFont() const; + + QByteArray mainWindowState(UIMode mode) const; + void setMainWindowState(UIMode mode, const QByteArray &mainWindowState); + + QByteArray toolBarsState(UIMode mode) const; + void setToolBarsState(UIMode mode, const QByteArray &mainWindowState); + + void clearBackup(); + void setBackup(const QMap<QString, QString> &map); + QMap<QString, QString> backup() const; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_SETTINGS_H diff --git a/src/designer/src/designer/qdesigner_toolwindow.cpp b/src/designer/src/designer/qdesigner_toolwindow.cpp new file mode 100644 index 000000000..376b0afae --- /dev/null +++ b/src/designer/src/designer/qdesigner_toolwindow.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_workbench.h" + +#include <QtDesigner/QDesignerPropertyEditorInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerActionEditorInterface> +#include <QtDesigner/QDesignerObjectInspectorInterface> +#include <QtDesigner/QDesignerWidgetBoxInterface> +#include <QtDesigner/QDesignerComponents> + +#include <QtCore/QEvent> +#include <QtCore/QDebug> +#include <QtGui/QAction> +#include <QtGui/QCloseEvent> + +enum { debugToolWindow = 0 }; + +QT_BEGIN_NAMESPACE + +// ---------------- QDesignerToolWindowFontSettings +ToolWindowFontSettings::ToolWindowFontSettings() : + m_writingSystem(QFontDatabase::Any), + m_useFont(false) +{ +} + +bool ToolWindowFontSettings::equals(const ToolWindowFontSettings &rhs) const +{ + return m_useFont == rhs.m_useFont && + m_writingSystem == rhs.m_writingSystem && + m_font == rhs.m_font; +} + +// ---------------- QDesignerToolWindow +QDesignerToolWindow::QDesignerToolWindow(QDesignerWorkbench *workbench, + QWidget *w, + const QString &objectName, + const QString &title, + const QString &actionObjectName, + Qt::DockWidgetArea dockAreaHint, + QWidget *parent, + Qt::WindowFlags flags) : + MainWindowBase(parent, flags), + m_dockAreaHint(dockAreaHint), + m_workbench(workbench), + m_action(new QAction(this)) +{ + setObjectName(objectName); + setCentralWidget(w); + + setWindowTitle(title); + + m_action->setObjectName(actionObjectName); + m_action->setShortcutContext(Qt::ApplicationShortcut); + m_action->setText(title); + m_action->setCheckable(true); + connect(m_action, SIGNAL(triggered(bool)), this, SLOT(showMe(bool))); +} + +void QDesignerToolWindow::showMe(bool v) +{ + // Access the QMdiSubWindow in MDI mode. + if (QWidget *target = m_workbench->mode() == DockedMode ? parentWidget() : this) { + if (v) + target->setWindowState(target->windowState() & ~Qt::WindowMinimized); + target->setVisible(v); + } +} + +void QDesignerToolWindow::showEvent(QShowEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(true); + m_action->blockSignals(blocked); +} + +void QDesignerToolWindow::hideEvent(QHideEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(false); + m_action->blockSignals(blocked); +} + +QAction *QDesignerToolWindow::action() const +{ + return m_action; +} + +void QDesignerToolWindow::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::WindowTitleChange: + m_action->setText(windowTitle()); + break; + case QEvent::WindowIconChange: + m_action->setIcon(windowIcon()); + break; + default: + break; + } + QMainWindow::changeEvent(e); +} + +QDesignerWorkbench *QDesignerToolWindow::workbench() const +{ + return m_workbench; +} + +QRect QDesignerToolWindow::geometryHint() const +{ + return QRect(); +} + +QRect QDesignerToolWindow::availableToolWindowGeometry() const +{ + return m_workbench->availableGeometry(); +} + +// ---------------------- PropertyEditorToolWindow + +static inline QWidget *createPropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerPropertyEditorInterface *widget = QDesignerComponents::createPropertyEditor(core, parent); + core->setPropertyEditor(widget); + return widget; +} + +class PropertyEditorToolWindow : public QDesignerToolWindow +{ +public: + explicit PropertyEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; + +protected: + virtual void showEvent(QShowEvent *event); +}; + +PropertyEditorToolWindow::PropertyEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createPropertyEditor(workbench->core()), + QLatin1String("qt_designer_propertyeditor"), + QDesignerToolWindow::tr("Property Editor"), + QLatin1String("__qt_property_editor_action"), + Qt::RightDockWidgetArea) +{ + action()->setShortcut(Qt::CTRL + Qt::Key_I); + +} + +QRect PropertyEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + const int spacing = 40; + const QSize sz(g.width() * 1/4, g.height() * 4/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + (g.top() + margin + g.height() * 1/6) + spacing, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +void PropertyEditorToolWindow::showEvent(QShowEvent *event) +{ + if (QDesignerPropertyEditorInterface *e = workbench()->core()->propertyEditor()) { + // workaround to update the propertyeditor when it is not visible! + e->setObject(e->object()); // ### remove me + } + + QDesignerToolWindow::showEvent(event); +} + +// ---------------------- ActionEditorToolWindow + +static inline QWidget *createActionEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerActionEditorInterface *widget = QDesignerComponents::createActionEditor(core, parent); + core->setActionEditor(widget); + return widget; +} + +class ActionEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit ActionEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ActionEditorToolWindow::ActionEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createActionEditor(workbench->core()), + QLatin1String("qt_designer_actioneditor"), + QDesignerToolWindow::tr("Action Editor"), + QLatin1String("__qt_action_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ActionEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/4, g.height() * 1/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + g.top() + margin, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// ---------------------- ObjectInspectorToolWindow + +static inline QWidget *createObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerObjectInspectorInterface *widget = QDesignerComponents::createObjectInspector(core, parent); + core->setObjectInspector(widget); + return widget; +} + +class ObjectInspectorToolWindow: public QDesignerToolWindow +{ +public: + explicit ObjectInspectorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ObjectInspectorToolWindow::ObjectInspectorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createObjectInspector(workbench->core()), + QLatin1String("qt_designer_objectinspector"), + QDesignerToolWindow::tr("Object Inspector"), + QLatin1String("__qt_object_inspector_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ObjectInspectorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/4, g.height() * 1/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + g.top() + margin, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// ---------------------- ResourceEditorToolWindow + +class ResourceEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit ResourceEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ResourceEditorToolWindow::ResourceEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + QDesignerComponents::createResourceEditor(workbench->core(), 0), + QLatin1String("qt_designer_resourceeditor"), + QDesignerToolWindow::tr("Resource Browser"), + QLatin1String("__qt_resource_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ResourceEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveBottom(g.bottom() - margin); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << r; + return r; +} + +// ---------------------- SignalSlotEditorToolWindow + +class SignalSlotEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit SignalSlotEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +SignalSlotEditorToolWindow::SignalSlotEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + QDesignerComponents::createSignalSlotEditor(workbench->core(), 0), + QLatin1String("qt_designer_signalsloteditor"), + QDesignerToolWindow::tr("Signal/Slot Editor"), + QLatin1String("__qt_signal_slot_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect SignalSlotEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveTop(margin + g.top()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << r; + return r; +} + +// ---------------------- WidgetBoxToolWindow + +static inline QWidget *createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerWidgetBoxInterface *widget = QDesignerComponents::createWidgetBox(core, parent); + core->setWidgetBox(widget); + return widget; +} + +class WidgetBoxToolWindow: public QDesignerToolWindow +{ +public: + explicit WidgetBoxToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +WidgetBoxToolWindow::WidgetBoxToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createWidgetBox(workbench->core()), + QLatin1String("qt_designer_widgetbox"), + QDesignerToolWindow::tr("Widget Box"), + QLatin1String("__qt_widget_box_tool_action"), + Qt::LeftDockWidgetArea) +{ +} + +QRect WidgetBoxToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + const QRect rc = QRect(g.left() + margin, + g.top() + margin, + g.width() * 1/4, g.height() * 5/6); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// -- Factory +QDesignerToolWindow *QDesignerToolWindow::createStandardToolWindow(StandardToolWindow which, + QDesignerWorkbench *workbench) +{ + switch (which) { + case ActionEditor: + return new ActionEditorToolWindow(workbench); + case ResourceEditor: + return new ResourceEditorToolWindow(workbench); + case SignalSlotEditor: + return new SignalSlotEditorToolWindow(workbench); + case PropertyEditor: + return new PropertyEditorToolWindow(workbench); + case ObjectInspector: + return new ObjectInspectorToolWindow(workbench); + case WidgetBox: + return new WidgetBoxToolWindow(workbench); + default: + break; + } + return 0; +} + + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_toolwindow.h b/src/designer/src/designer/qdesigner_toolwindow.h new file mode 100644 index 000000000..1c7b876d1 --- /dev/null +++ b/src/designer/src/designer/qdesigner_toolwindow.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_TOOLWINDOW_H +#define QDESIGNER_TOOLWINDOW_H + +#include "mainwindow.h" + +#include <QtCore/QPointer> +#include <QtGui/QFontDatabase> +#include <QtGui/QMainWindow> + +QT_BEGIN_NAMESPACE + +struct ToolWindowFontSettings { + ToolWindowFontSettings(); + bool equals(const ToolWindowFontSettings &) const; + + QFont m_font; + QFontDatabase::WritingSystem m_writingSystem; + bool m_useFont; +}; + +inline bool operator==(const ToolWindowFontSettings &tw1, const ToolWindowFontSettings &tw2) +{ + return tw1.equals(tw2); +} + +inline bool operator!=(const ToolWindowFontSettings &tw1, const ToolWindowFontSettings &tw2) +{ + return !tw1.equals(tw2); +} + +class QDesignerWorkbench; + +/* A tool window with an action that activates it. Note that in toplevel mode, + * the Widget box is a tool window as well as the applications' main window, + * So, we need to inherit from MainWindowBase. */ + +class QDesignerToolWindow : public MainWindowBase +{ + Q_OBJECT +protected: + explicit QDesignerToolWindow(QDesignerWorkbench *workbench, + QWidget *w, + const QString &objectName, + const QString &title, + const QString &actionObjectName, + Qt::DockWidgetArea dockAreaHint, + QWidget *parent = 0, + Qt::WindowFlags flags = Qt::Window); + +public: + // Note: The order influences the dock widget position. + enum StandardToolWindow { WidgetBox, ObjectInspector, PropertyEditor, + ResourceEditor, ActionEditor, SignalSlotEditor, + StandardToolWindowCount }; + + static QDesignerToolWindow *createStandardToolWindow(StandardToolWindow which, QDesignerWorkbench *workbench); + + QDesignerWorkbench *workbench() const; + QAction *action() const; + + Qt::DockWidgetArea dockWidgetAreaHint() const { return m_dockAreaHint; } + virtual QRect geometryHint() const; + +private slots: + void showMe(bool); + +protected: + virtual void showEvent(QShowEvent *e); + virtual void hideEvent(QHideEvent *e); + virtual void changeEvent(QEvent *e); + + QRect availableToolWindowGeometry() const; + +private: + const Qt::DockWidgetArea m_dockAreaHint; + QDesignerWorkbench *m_workbench; + QAction *m_action; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_TOOLWINDOW_H diff --git a/src/designer/src/designer/qdesigner_workbench.cpp b/src/designer/src/designer/qdesigner_workbench.cpp new file mode 100644 index 000000000..ffc4b8c7a --- /dev/null +++ b/src/designer/src/designer/qdesigner_workbench.cpp @@ -0,0 +1,1100 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@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(); + +#ifndef Q_WS_MAC + QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); + widgetBoxWrapper->action()->setVisible(true); + widgetBoxWrapper->setWindowTitle(tr("Widget Box")); +#endif + + m_mode = DockedMode; + const QDesignerSettings settings(m_core); + m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); + m_dockedMainWindow->setUnifiedTitleAndToolBarOnMac(true); + 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); + + 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 (!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(); + // Did user specify another (missing) resource path -> set dirty. + const bool dirty = editor->property("_q_resourcepathchanged").toBool(); + editor->setDirty(dirty); + 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 diff --git a/src/designer/src/designer/qdesigner_workbench.h b/src/designer/src/designer/qdesigner_workbench.h new file mode 100644 index 000000000..9266eea60 --- /dev/null +++ b/src/designer/src/designer/qdesigner_workbench.h @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_WORKBENCH_H +#define QDESIGNER_WORKBENCH_H + +#include "designer_enums.h" + +#include <QtCore/QObject> +#include <QtCore/QHash> +#include <QtCore/QSet> +#include <QtCore/QList> +#include <QtCore/QRect> + +QT_BEGIN_NAMESPACE + +class QDesignerActions; +class QDesignerToolWindow; +class QDesignerFormWindow; +class DockedMainWindow; +class QDesignerSettings; + +class QAction; +class QActionGroup; +class QDockWidget; +class QMenu; +class QMenuBar; +class QMainWindow; +class QToolBar; +class QMdiArea; +class QMdiSubWindow; +class QCloseEvent; +class QFont; +class QtToolBarManager; +class ToolBarManager; + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerFormWindowManagerInterface; + +namespace qdesigner_internal { +class QDesignerIntegration; +} + +class QDesignerWorkbench: public QObject +{ + Q_OBJECT + +public: + QDesignerWorkbench(); + virtual ~QDesignerWorkbench(); + + UIMode mode() const; + + QDesignerFormEditorInterface *core() const; + QDesignerFormWindow *findFormWindow(QWidget *widget) const; + + QDesignerFormWindow *openForm(const QString &fileName, QString *errorMessage); + QDesignerFormWindow *openTemplate(const QString &templateFileName, + const QString &editorFileName, + QString *errorMessage); + + int toolWindowCount() const; + QDesignerToolWindow *toolWindow(int index) const; + + int formWindowCount() const; + QDesignerFormWindow *formWindow(int index) const; + + QDesignerActions *actionManager() const; + + QActionGroup *modeActionGroup() const; + + QRect availableGeometry() const; + QRect desktopGeometry() const; + + int marginHint() const; + + bool readInForm(const QString &fileName) const; + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const; + bool saveForm(QDesignerFormWindowInterface *fw); + bool handleClose(); + bool readInBackup(); + void updateBackup(QDesignerFormWindowInterface* fwi); + +signals: + void modeChanged(UIMode mode); + void initialized(); + +public slots: + void addFormWindow(QDesignerFormWindow *formWindow); + void removeFormWindow(QDesignerFormWindow *formWindow); + void bringAllToFront(); + void toggleFormMinimizationState(); + +private slots: + void switchToNeutralMode(); + void switchToDockedMode(); + void switchToTopLevelMode(); + void initializeCorePlugins(); + void handleCloseEvent(QCloseEvent *); + void slotFormWindowActivated(QDesignerFormWindow* fw); + void updateWindowMenu(QDesignerFormWindowInterface *fw); + void formWindowActionTriggered(QAction *a); + void adjustMDIFormPositions(); + void minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized); + + void restoreUISettings(); + void slotFileDropped(const QString &f); + +private: + QWidget *magicalParent(const QWidget *w) const; + Qt::WindowFlags magicalWindowFlags(const QWidget *widgetForFlags) const; + QDesignerFormWindowManagerInterface *formWindowManager() const; + void closeAllToolWindows(); + QDesignerToolWindow *widgetBoxToolWindow() const; + QDesignerFormWindow *loadForm(const QString &fileName, bool detectLineTermiantorMode, bool *uic3Converted, QString *errorMessage); + void resizeForm(QDesignerFormWindow *fw, const QWidget *mainContainer) const; + void saveGeometriesForModeChange(); + void saveGeometries(QDesignerSettings &settings) const; + + bool isFormWindowMinimized(const QDesignerFormWindow *fw); + void setFormWindowMinimized(QDesignerFormWindow *fw, bool minimized); + void saveSettings() const; + + QDesignerFormEditorInterface *m_core; + qdesigner_internal::QDesignerIntegration *m_integration; + + QDesignerActions *m_actionManager; + QActionGroup *m_windowActions; + + QMenu *m_windowMenu; + + QMenuBar *m_globalMenuBar; + + struct TopLevelData { + ToolBarManager *toolbarManager; + QList<QToolBar *> toolbars; + }; + TopLevelData m_topLevelData; + + UIMode m_mode; + DockedMainWindow *m_dockedMainWindow; + + QList<QDesignerToolWindow*> m_toolWindows; + QList<QDesignerFormWindow*> m_formWindows; + + QMenu *m_toolbarMenu; + + // Helper class to remember the position of a window while switching user + // interface modes. + class Position { + public: + Position(const QDockWidget *dockWidget); + Position(const QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset); + Position(const QWidget *topLevelWindow, const QPoint &desktopTopLeft); + + void applyTo(QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset) const; + void applyTo(QWidget *topLevelWindow, const QPoint &desktopTopLeft) const; + void applyTo(QDockWidget *dockWidget) const; + + QPoint position() const { return m_position; } + private: + bool m_minimized; + // Position referring to top-left corner (desktop in top-level mode or + // main window in MDI mode) + QPoint m_position; + }; + typedef QHash<QWidget*, Position> PositionMap; + PositionMap m_Positions; + + enum State { StateInitializing, StateUp, StateClosing }; + State m_state; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_WORKBENCH_H diff --git a/src/designer/src/designer/saveformastemplate.cpp b/src/designer/src/designer/saveformastemplate.cpp new file mode 100644 index 000000000..49ac64ee5 --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "saveformastemplate.h" +#include "qdesigner_settings.h" + +#include <QtCore/QFile> +#include <QtGui/QFileDialog> +#include <QtGui/QMessageBox> +#include <QtGui/QPushButton> + +#include <QtDesigner/abstractformeditor.h> +#include <QtDesigner/abstractformwindow.h> + +QT_BEGIN_NAMESPACE + +SaveFormAsTemplate::SaveFormAsTemplate(QDesignerFormEditorInterface *core, + QDesignerFormWindowInterface *formWindow, + QWidget *parent) + : QDialog(parent, Qt::Sheet), + m_core(core), + m_formWindow(formWindow) +{ + ui.setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.templateNameEdit->setText(formWindow->mainContainer()->objectName()); + ui.templateNameEdit->selectAll(); + + ui.templateNameEdit->setFocus(); + + QStringList paths = QDesignerSettings(m_core).formTemplatePaths(); + ui.categoryCombo->addItems(paths); + ui.categoryCombo->addItem(tr("Add path...")); + m_addPathIndex = ui.categoryCombo->count() - 1; + connect(ui.templateNameEdit, SIGNAL(textChanged(QString)), + this, SLOT(updateOKButton(QString))); + connect(ui.categoryCombo, SIGNAL(activated(int)), this, SLOT(checkToAddPath(int))); +} + +SaveFormAsTemplate::~SaveFormAsTemplate() +{ +} + +void SaveFormAsTemplate::accept() +{ + QString templateFileName = ui.categoryCombo->currentText(); + templateFileName += QLatin1Char('/'); + const QString name = ui.templateNameEdit->text(); + templateFileName += name; + const QString extension = QLatin1String(".ui"); + if (!templateFileName.endsWith(extension)) + templateFileName.append(extension); + QFile file(templateFileName); + + if (file.exists()) { + QMessageBox msgBox(QMessageBox::Information, tr("Template Exists"), + tr("A template with the name %1 already exists.\n" + "Do you want overwrite the template?").arg(name), QMessageBox::Cancel, m_formWindow); + msgBox.setDefaultButton(QMessageBox::Cancel); + QPushButton *overwriteButton = msgBox.addButton(tr("Overwrite Template"), QMessageBox::AcceptRole); + msgBox.exec(); + if (msgBox.clickedButton() != overwriteButton) + return; + } + + while (!file.open(QFile::WriteOnly)) { + if (QMessageBox::information(m_formWindow, tr("Open Error"), + tr("There was an error opening template %1 for writing. Reason: %2").arg(name).arg(file.errorString()), + QMessageBox::Retry|QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { + return; + } + } + + const QString origName = m_formWindow->fileName(); + // ensure m_formWindow->contents() will convert properly resource paths to relative paths + // (relative to template location, not to the current form location) + m_formWindow->setFileName(templateFileName); + QByteArray ba = m_formWindow->contents().toUtf8(); + m_formWindow->setFileName(origName); + while (file.write(ba) != ba.size()) { + if (QMessageBox::information(m_formWindow, tr("Write Error"), + tr("There was an error writing the template %1 to disk. Reason: %2").arg(name).arg(file.errorString()), + QMessageBox::Retry|QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { + file.close(); + file.remove(); + return; + } + file.reset(); + } + // update the list of places too... + QStringList sl; + for (int i = 0; i < m_addPathIndex; ++i) + sl << ui.categoryCombo->itemText(i); + + QDesignerSettings(m_core).setFormTemplatePaths(sl); + + QDialog::accept(); +} + +void SaveFormAsTemplate::updateOKButton(const QString &str) +{ + QPushButton *okButton = ui.buttonBox->button(QDialogButtonBox::Ok); + okButton->setEnabled(!str.isEmpty()); +} + +QString SaveFormAsTemplate::chooseTemplatePath(QWidget *parent) +{ + QString rc = QFileDialog::getExistingDirectory(parent, + tr("Pick a directory to save templates in")); + if (rc.isEmpty()) + return rc; + + if (rc.endsWith(QDir::separator())) + rc.remove(rc.size() - 1, 1); + return rc; +} + +void SaveFormAsTemplate::checkToAddPath(int itemIndex) +{ + if (itemIndex != m_addPathIndex) + return; + + const QString dir = chooseTemplatePath(this); + if (dir.isEmpty()) { + ui.categoryCombo->setCurrentIndex(0); + return; + } + + ui.categoryCombo->insertItem(m_addPathIndex, dir); + ui.categoryCombo->setCurrentIndex(m_addPathIndex); + ++m_addPathIndex; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/saveformastemplate.h b/src/designer/src/designer/saveformastemplate.h new file mode 100644 index 000000000..8b0b3ab8e --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SAVEFORMASTEMPLATE_H +#define SAVEFORMASTEMPLATE_H + +#include "ui_saveformastemplate.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class SaveFormAsTemplate: public QDialog +{ + Q_OBJECT +public: + explicit SaveFormAsTemplate(QDesignerFormEditorInterface *m_core, + QDesignerFormWindowInterface *formWindow, + QWidget *parent = 0); + virtual ~SaveFormAsTemplate(); + +private slots: + void accept(); + void updateOKButton(const QString &str); + void checkToAddPath(int itemIndex); + +private: + static QString chooseTemplatePath(QWidget *parent); + + Ui::SaveFormAsTemplate ui; + QDesignerFormEditorInterface *m_core; + QDesignerFormWindowInterface *m_formWindow; + int m_addPathIndex; +}; + +QT_END_NAMESPACE + +#endif // SAVEFORMASTEMPLATE_H diff --git a/src/designer/src/designer/saveformastemplate.ui b/src/designer/src/designer/saveformastemplate.ui new file mode 100644 index 000000000..c29ad9ad4 --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.ui @@ -0,0 +1,166 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>SaveFormAsTemplate</class> + <widget class="QDialog" name="SaveFormAsTemplate" > + <property name="windowTitle" > + <string>Save Form As Template</string> + </property> + <layout class="QVBoxLayout" > + <item> + <layout class="QFormLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="frameShape" > + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Plain</enum> + </property> + <property name="text" > + <string>&Name:</string> + </property> + <property name="textFormat" > + <enum>Qt::AutoText</enum> + </property> + <property name="buddy" > + <cstring>templateNameEdit</cstring> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="templateNameEdit" > + <property name="minimumSize" > + <size> + <width>222</width> + <height>0</height> + </size> + </property> + <property name="text" > + <string/> + </property> + <property name="echoMode" > + <enum>QLineEdit::Normal</enum> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="frameShape" > + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Plain</enum> + </property> + <property name="text" > + <string>&Category:</string> + </property> + <property name="textFormat" > + <enum>Qt::AutoText</enum> + </property> + <property name="buddy" > + <cstring>categoryCombo</cstring> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="categoryCombo" /> + </item> + </layout> + </item> + <item> + <widget class="QFrame" name="horizontalLine" > + <property name="frameShape" > + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Sunken</enum> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>SaveFormAsTemplate</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>256</x> + <y>124</y> + </hint> + <hint type="destinationlabel" > + <x>113</x> + <y>143</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>SaveFormAsTemplate</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>332</x> + <y>127</y> + </hint> + <hint type="destinationlabel" > + <x>372</x> + <y>147</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/designer/src/designer/uifile.icns b/src/designer/src/designer/uifile.icns Binary files differnew file mode 100644 index 000000000..2473ea4dc --- /dev/null +++ b/src/designer/src/designer/uifile.icns diff --git a/src/designer/src/designer/versiondialog.cpp b/src/designer/src/designer/versiondialog.cpp new file mode 100644 index 000000000..63a95e6d7 --- /dev/null +++ b/src/designer/src/designer/versiondialog.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QVector> +#include <QtGui/QMouseEvent> +#include <QtGui/QGridLayout> +#include <QtGui/QLabel> +#include <QtGui/QPushButton> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QPainter> +#include <QtGui/QPainterPath> +#include <QtGui/QStyleOption> +#include "versiondialog.h" + +QT_BEGIN_NAMESPACE + +class VersionLabel : public QLabel +{ + Q_OBJECT +public: + VersionLabel(QWidget *parent = 0); + +signals: + void triggered(); + +protected: + void mousePressEvent(QMouseEvent *me); + void mouseMoveEvent(QMouseEvent *me); + void mouseReleaseEvent(QMouseEvent *me); + void paintEvent(QPaintEvent *pe); +private: + QVector<QPoint> hitPoints; + QVector<QPoint> missPoints; + QPainterPath m_path; + bool secondStage; + bool m_pushed; +}; + +VersionLabel::VersionLabel(QWidget *parent) + : QLabel(parent), secondStage(false), m_pushed(false) +{ + setPixmap(QPixmap(QLatin1String(":/trolltech/designer/images/designer.png"))); + hitPoints.append(QPoint(56, 25)); + hitPoints.append(QPoint(29, 55)); + hitPoints.append(QPoint(56, 87)); + hitPoints.append(QPoint(82, 55)); + hitPoints.append(QPoint(58, 56)); + + secondStage = false; + m_pushed = false; +} + +void VersionLabel::mousePressEvent(QMouseEvent *me) +{ + if (me->button() == Qt::LeftButton) { + if (!secondStage) { + m_path = QPainterPath(me->pos()); + } else { + m_pushed = true; + update(); + } + } +} + +void VersionLabel::mouseMoveEvent(QMouseEvent *me) +{ + if (me->buttons() & Qt::LeftButton) + if (!secondStage) + m_path.lineTo(me->pos()); +} + +void VersionLabel::mouseReleaseEvent(QMouseEvent *me) +{ + if (me->button() == Qt::LeftButton) { + if (!secondStage) { + m_path.lineTo(me->pos()); + bool gotIt = true; + foreach(const QPoint &pt, hitPoints) { + if (!m_path.contains(pt)) { + gotIt = false; + break; + } + } + if (gotIt) { + foreach(const QPoint &pt, missPoints) { + if (m_path.contains(pt)) { + gotIt = false; + break; + } + } + } + if (gotIt && !secondStage) { + secondStage = true; + m_path = QPainterPath(); + update(); + } + } else { + m_pushed = false; + update(); + emit triggered(); + } + } +} + +void VersionLabel::paintEvent(QPaintEvent *pe) +{ + if (secondStage) { + QPainter p(this); + QStyleOptionButton opt; + opt.init(this); + if (!m_pushed) + opt.state |= QStyle::State_Raised; + else + opt.state |= QStyle::State_Sunken; + opt.state &= ~QStyle::State_HasFocus; + style()->drawControl(QStyle::CE_PushButtonBevel, &opt, &p, this); + } + QLabel::paintEvent(pe); +} + +VersionDialog::VersionDialog(QWidget *parent) + : QDialog(parent +#ifdef Q_WS_MAC + , Qt::Tool +#endif + ) +{ + setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | Qt::MSWindowsFixedSizeDialogHint); + QGridLayout *layout = new QGridLayout(this); + VersionLabel *label = new VersionLabel; + QLabel *lbl = new QLabel; + QString version = tr("<h3>%1</h3><br/><br/>Version %2"); + version = version.arg(tr("Qt Designer")).arg(QLatin1String(QT_VERSION_STR)); + version.append(tr("<br/>Qt Designer is a graphical user interface designer for Qt applications.<br/>")); + + lbl->setText(tr("%1" + "<br/>Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + ).arg(version)); + + lbl->setWordWrap(true); + lbl->setOpenExternalLinks(true); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject())); + connect(label, SIGNAL(triggered()), this, SLOT(accept())); + layout->addWidget(label, 0, 0, 1, 1); + layout->addWidget(lbl, 0, 1, 4, 4); + layout->addWidget(buttonBox, 4, 2, 1, 1); +} + +QT_END_NAMESPACE + +#include "versiondialog.moc" diff --git a/src/designer/src/designer/versiondialog.h b/src/designer/src/designer/versiondialog.h new file mode 100644 index 000000000..0e6760092 --- /dev/null +++ b/src/designer/src/designer/versiondialog.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VERSIONDIALOG_H +#define VERSIONDIALOG_H + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class VersionDialog : public QDialog +{ + Q_OBJECT +public: + explicit VersionDialog(QWidget *parent); +}; + +QT_END_NAMESPACE + +#endif |