diff options
Diffstat (limited to 'tools/designer/src/components')
374 files changed, 44713 insertions, 0 deletions
diff --git a/tools/designer/src/components/buddyeditor/buddyeditor.cpp b/tools/designer/src/components/buddyeditor/buddyeditor.cpp new file mode 100644 index 0000000..f5c93fa --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::BuddyEditor +*/ + +#include "buddyeditor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerPropertySheetExtension> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QExtensionManager> + +#include <qdesigner_command_p.h> +#include <qdesigner_propertycommand_p.h> +#include <qdesigner_utils_p.h> +#include <qlayout_widget_p.h> +#include <connectionedit_p.h> + +#include <QtCore/qdebug.h> +#include <QtGui/QLabel> +#include <QtGui/QMenu> +#include <QtGui/QAction> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +static const char *buddyPropertyC = "buddy"; + +static bool canBeBuddy(QWidget *w, QDesignerFormWindowInterface *form) +{ + if (qobject_cast<const QLayoutWidget*>(w) || qobject_cast<const QLabel*>(w)) + return false; + if (w == form->mainContainer() || w->isHidden() ) + return false; + + QExtensionManager *ext = form->core()->extensionManager(); + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(ext, w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + const Qt::FocusPolicy q = static_cast<Qt::FocusPolicy>(qdesigner_internal::Utils::valueOf(sheet->property(index), &ok)); + return ok && q != Qt::NoFocus; + } + } + return false; +} + +static QString buddy(QLabel *label, QDesignerFormEditorInterface *core) +{ + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), label); + if (sheet == 0) + return QString(); + const int prop_idx = sheet->indexOf(QLatin1String(buddyPropertyC)); + if (prop_idx == -1) + return QString(); + return sheet->property(prop_idx).toString(); +} + +typedef QList<QLabel*> LabelList; + +namespace qdesigner_internal { + +/******************************************************************************* +** BuddyEditor +*/ + +BuddyEditor::BuddyEditor(QDesignerFormWindowInterface *form, QWidget *parent) : + ConnectionEdit(parent, form), + m_formWindow(form), + m_updating(false) +{ +} + + +QWidget *BuddyEditor::widgetAt(const QPoint &pos) const +{ + QWidget *w = ConnectionEdit::widgetAt(pos); + + while (w != 0 && !m_formWindow->isManaged(w)) + w = w->parentWidget(); + if (!w) + return w; + + if (state() == Editing) { + QLabel *label = qobject_cast<QLabel*>(w); + if (label == 0) + return 0; + const int cnt = connectionCount(); + for (int i = 0; i < cnt; ++i) { + Connection *con = connection(i); + if (con->widget(EndPoint::Source) == w) + return 0; + } + } else { + if (!canBeBuddy(w, m_formWindow)) + return 0; + } + + return w; +} + +Connection *BuddyEditor::createConnection(QWidget *source, QWidget *destination) +{ + return new Connection(this, source, destination); +} + +QDesignerFormWindowInterface *BuddyEditor::formWindow() const +{ + return m_formWindow; +} + +void BuddyEditor::updateBackground() +{ + if (m_updating || background() == 0) + return; + ConnectionEdit::updateBackground(); + + m_updating = true; + QList<Connection *> newList; + const LabelList label_list = qFindChildren<QLabel*>(background()); + foreach (QLabel *label, label_list) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + continue; + + const QList<QWidget *> targets = qFindChildren<QWidget*>(background(), buddy_name); + if (targets.isEmpty()) + continue; + + QWidget *target = 0; + + QListIterator<QWidget *> it(targets); + while (it.hasNext()) { + QWidget *widget = it.next(); + if (widget && !widget->isHidden()) { + target = widget; + break; + } + } + + if (target == 0) + continue; + + Connection *con = new Connection(this); + con->setEndPoint(EndPoint::Source, label, widgetRect(label).center()); + con->setEndPoint(EndPoint::Target, target, widgetRect(target).center()); + newList.append(con); + } + + QList<Connection *> toRemove; + + const int c = connectionCount(); + for (int i = 0; i < c; i++) { + Connection *con = connection(i); + QObject *source = con->object(EndPoint::Source); + QObject *target = con->object(EndPoint::Target); + bool found = false; + QListIterator<Connection *> it(newList); + while (it.hasNext()) { + Connection *newConn = it.next(); + if (newConn->object(EndPoint::Source) == source && newConn->object(EndPoint::Target) == target) { + found = true; + break; + } + } + if (found == false) + toRemove.append(con); + } + if (!toRemove.isEmpty()) { + DeleteConnectionsCommand command(this, toRemove); + command.redo(); + foreach (Connection *con, toRemove) + delete takeConnection(con); + } + + QListIterator<Connection *> it(newList); + while (it.hasNext()) { + Connection *newConn = it.next(); + + bool found = false; + const int c = connectionCount(); + for (int i = 0; i < c; i++) { + Connection *con = connection(i); + if (con->object(EndPoint::Source) == newConn->object(EndPoint::Source) && + con->object(EndPoint::Target) == newConn->object(EndPoint::Target)) { + found = true; + break; + } + } + if (found == false) { + AddConnectionCommand command(this, newConn); + command.redo(); + } else { + delete newConn; + } + } + m_updating = false; +} + +void BuddyEditor::setBackground(QWidget *background) +{ + clear(); + ConnectionEdit::setBackground(background); + + const LabelList label_list = qFindChildren<QLabel*>(background); + foreach (QLabel *label, label_list) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + continue; + QWidget *target = qFindChild<QWidget*>(background, buddy_name); + if (target == 0) + continue; + + Connection *con = new Connection(this); + con->setEndPoint(EndPoint::Source, label, widgetRect(label).center()); + con->setEndPoint(EndPoint::Target, target, widgetRect(target).center()); + addConnection(con); + } +} + +static QUndoCommand *createBuddyCommand(QDesignerFormWindowInterface *fw, QLabel *label, QWidget *buddy) +{ + SetPropertyCommand *command = new SetPropertyCommand(fw); + command->init(label, QLatin1String(buddyPropertyC), buddy->objectName()); + command->setText(BuddyEditor::tr("Add buddy")); + return command; +} + +void BuddyEditor::endConnection(QWidget *target, const QPoint &pos) +{ + Connection *tmp_con = newlyAddedConnection(); + Q_ASSERT(tmp_con != 0); + + tmp_con->setEndPoint(EndPoint::Target, target, pos); + + QWidget *source = tmp_con->widget(EndPoint::Source); + Q_ASSERT(source != 0); + Q_ASSERT(target != 0); + setEnabled(false); + Connection *new_con = createConnection(source, target); + setEnabled(true); + if (new_con != 0) { + new_con->setEndPoint(EndPoint::Source, source, tmp_con->endPointPos(EndPoint::Source)); + new_con->setEndPoint(EndPoint::Target, target, tmp_con->endPointPos(EndPoint::Target)); + + selectNone(); + addConnection(new_con); + QLabel *source = qobject_cast<QLabel*>(new_con->widget(EndPoint::Source)); + QWidget *target = new_con->widget(EndPoint::Target); + if (source) { + undoStack()->push(createBuddyCommand(m_formWindow, source, target)); + } else { + qDebug("BuddyEditor::endConnection(): not a label"); + } + setSelected(new_con, true); + } + + clearNewlyAddedConnection(); + findObjectsUnderMouse(mapFromGlobal(QCursor::pos())); +} + +void BuddyEditor::widgetRemoved(QWidget *widget) +{ + QList<QWidget*> child_list = qFindChildren<QWidget*>(widget); + child_list.prepend(widget); + + ConnectionSet remove_set; + foreach (QWidget *w, child_list) { + const ConnectionList &cl = connectionList(); + foreach (Connection *con, cl) { + if (con->widget(EndPoint::Source) == w || con->widget(EndPoint::Target) == w) + remove_set.insert(con, con); + } + } + + if (!remove_set.isEmpty()) { + undoStack()->beginMacro(tr("Remove buddies")); + foreach (Connection *con, remove_set) { + setSelected(con, false); + con->update(); + QWidget *source = con->widget(EndPoint::Source); + if (qobject_cast<QLabel*>(source) == 0) { + qDebug("BuddyConnection::widgetRemoved(): not a label"); + } else { + ResetPropertyCommand *command = new ResetPropertyCommand(formWindow()); + command->init(source, QLatin1String(buddyPropertyC)); + undoStack()->push(command); + } + delete takeConnection(con); + } + undoStack()->endMacro(); + } +} + +void BuddyEditor::deleteSelected() +{ + const ConnectionSet selectedConnections = selection(); // want copy for unselect + if (selectedConnections.isEmpty()) + return; + + undoStack()->beginMacro(tr("Remove %n buddies", 0, selectedConnections.size())); + foreach (Connection *con, selectedConnections) { + setSelected(con, false); + con->update(); + QWidget *source = con->widget(EndPoint::Source); + if (qobject_cast<QLabel*>(source) == 0) { + qDebug("BuddyConnection::deleteSelected(): not a label"); + } else { + ResetPropertyCommand *command = new ResetPropertyCommand(formWindow()); + command->init(source, QLatin1String(buddyPropertyC)); + undoStack()->push(command); + } + delete takeConnection(con); + } + undoStack()->endMacro(); +} + +void BuddyEditor::autoBuddy() +{ + // Any labels? + LabelList labelList = qFindChildren<QLabel*>(background()); + if (labelList.empty()) + return; + // Find already used buddies + QWidgetList usedBuddies; + const ConnectionList &beforeConnections = connectionList(); + foreach (const Connection *c, beforeConnections) + usedBuddies.push_back(c->widget(EndPoint::Target)); + // Find potential new buddies, keep lists in sync + QWidgetList buddies; + for (LabelList::iterator it = labelList.begin(); it != labelList.end(); ) { + QLabel *label = *it; + QWidget *newBuddy = 0; + if (m_formWindow->isManaged(label)) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + newBuddy = findBuddy(label, usedBuddies); + } + if (newBuddy) { + buddies.push_back(newBuddy); + usedBuddies.push_back(newBuddy); + ++it; + } else { + it = labelList.erase(it); + } + } + // Add the list in one go. + if (labelList.empty()) + return; + const int count = labelList.size(); + Q_ASSERT(count == buddies.size()); + undoStack()->beginMacro(tr("Add %n buddies", 0, count)); + for (int i = 0; i < count; i++) + undoStack()->push(createBuddyCommand(m_formWindow, labelList.at(i), buddies.at(i))); + undoStack()->endMacro(); + // Now select all new ones + const ConnectionList &connections = connectionList(); + foreach (Connection *con, connections) + setSelected(con, buddies.contains(con->widget(EndPoint::Target))); +} + +// Geometrically find a potential buddy for label by checking neighbouring children of parent +QWidget *BuddyEditor::findBuddy(QLabel *l, const QWidgetList &existingBuddies) const +{ + enum { DeltaX = 5 }; + const QWidget *parent = l->parentWidget(); + // Try to find next managed neighbour on horizontal line + const QRect geom = l->geometry(); + const int y = geom.center().y(); + QWidget *neighbour = 0; + switch (QApplication::layoutDirection()) { + case Qt::LeftToRight: { // Walk right to find next managed neighbour + const int xEnd = parent->size().width(); + for (int x = geom.right() + 1; x < xEnd; x += DeltaX) + if (QWidget *c = parent->childAt (x, y)) + if (m_formWindow->isManaged(c)) { + neighbour = c; + break; + } + } + break; + case Qt::RightToLeft: // Walk left to find next managed neighbour + for (int x = geom.x() - 1; x >= 0; x -= DeltaX) + if (QWidget *c = parent->childAt (x, y)) + if (m_formWindow->isManaged(c)) { + neighbour = c; + break; + } + break; + } + if (neighbour && !existingBuddies.contains(neighbour) && canBeBuddy(neighbour, m_formWindow)) + return neighbour; + + return 0; +} + +void BuddyEditor::createContextMenu(QMenu &menu) +{ + QAction *autoAction = menu.addAction(tr("Set automatically")); + connect(autoAction, SIGNAL(triggered()), this, SLOT(autoBuddy())); + menu.addSeparator(); + ConnectionEdit::createContextMenu(menu); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/buddyeditor/buddyeditor.h b/tools/designer/src/components/buddyeditor/buddyeditor.h new file mode 100644 index 0000000..4f8f8d4 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_H +#define BUDDYEDITOR_H + +#include "buddyeditor_global.h" + +#include <connectionedit_p.h> +#include <QtCore/QPointer> +#include <QtCore/QSet> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +class QLabel; + +namespace qdesigner_internal { + +class QT_BUDDYEDITOR_EXPORT BuddyEditor : public ConnectionEdit +{ + Q_OBJECT + +public: + BuddyEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const; + virtual void setBackground(QWidget *background); + virtual void deleteSelected(); + +public slots: + virtual void updateBackground(); + virtual void widgetRemoved(QWidget *w); + void autoBuddy(); + +protected: + virtual QWidget *widgetAt(const QPoint &pos) const; + virtual Connection *createConnection(QWidget *source, QWidget *destination); + virtual void endConnection(QWidget *target, const QPoint &pos); + virtual void createContextMenu(QMenu &menu); + +private: + QWidget *findBuddy(QLabel *l, const QWidgetList &existingBuddies) const; + + QPointer<QDesignerFormWindowInterface> m_formWindow; + bool m_updating; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/tools/designer/src/components/buddyeditor/buddyeditor.pri b/tools/designer/src/components/buddyeditor/buddyeditor.pri new file mode 100644 index 0000000..c507aa0 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor.pri @@ -0,0 +1,16 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/buddyeditor.h \ + $$PWD/buddyeditor_plugin.h \ + $$PWD/buddyeditor_tool.h \ + $$PWD/buddyeditor_global.h + +SOURCES += \ + $$PWD/buddyeditor.cpp \ + $$PWD/buddyeditor_tool.cpp \ + $$PWD/buddyeditor_plugin.cpp \ + $$PWD/buddyeditor_instance.cpp diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_global.h b/tools/designer/src/components/buddyeditor/buddyeditor_global.h new file mode 100644 index 0000000..490f591 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_GLOBAL_H +#define BUDDYEDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_BUDDYEDITOR_LIBRARY +# define QT_BUDDYEDITOR_EXPORT +#else +# define QT_BUDDYEDITOR_EXPORT +#endif +#else +#define QT_BUDDYEDITOR_EXPORT +#endif + +#endif // BUDDYEDITOR_GLOBAL_H diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_instance.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_instance.cpp new file mode 100644 index 0000000..bcfa415 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_instance.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qplugin.h> + +#include "buddyeditor_plugin.h" + +QT_USE_NAMESPACE + +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(BuddyEditorPlugin) diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp new file mode 100644 index 0000000..98fff8c --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::BuddyEditorPlugin +*/ + +#include <QtGui/QAction> + +#include "buddyeditor_plugin.h" +#include "buddyeditor_tool.h" + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QDesignerFormEditorInterface> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +BuddyEditorPlugin::BuddyEditorPlugin() + : m_initialized(false) +{ +} + +BuddyEditorPlugin::~BuddyEditorPlugin() +{ +} + +bool BuddyEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void BuddyEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Buddies"), this); + m_action->setObjectName(QLatin1String("__qt_edit_buddies_action")); + m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); + m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +QDesignerFormEditorInterface *BuddyEditorPlugin::core() const +{ + return m_core; +} + +void BuddyEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + BuddyEditorTool *tool = new BuddyEditorTool(formWindow, this); + m_tools[formWindow] = tool; + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + formWindow->registerTool(tool); +} + +void BuddyEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + BuddyEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *BuddyEditorPlugin::action() const +{ + return m_action; +} + +void BuddyEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.h b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.h new file mode 100644 index 0000000..79f3f49 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_PLUGIN_H +#define BUDDYEDITOR_PLUGIN_H + +#include "buddyeditor_global.h" + +#include <QtDesigner/QDesignerFormEditorPluginInterface> + +#include <QtCore/QPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class BuddyEditorTool; + +class QT_BUDDYEDITOR_EXPORT BuddyEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + BuddyEditorPlugin(); + virtual ~BuddyEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer<QDesignerFormEditorInterface> m_core; + QHash<QDesignerFormWindowInterface*, BuddyEditorTool*> m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUDDYEDITOR_PLUGIN_H diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp new file mode 100644 index 0000000..68a6030 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::BuddyEditorTool +*/ + +#include "buddyeditor_tool.h" +#include "buddyeditor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +BuddyEditorTool::BuddyEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Buddies"), this)) +{ +} + +BuddyEditorTool::~BuddyEditorTool() +{ +} + +QDesignerFormEditorInterface *BuddyEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *BuddyEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool BuddyEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(event); + + return false; +} + +QWidget *BuddyEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new BuddyEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); + } + + return m_editor; +} + +void BuddyEditorTool::activated() +{ + m_editor->enableUpdateBackground(true); +} + +void BuddyEditorTool::deactivated() +{ + m_editor->enableUpdateBackground(false); +} + +QAction *BuddyEditorTool::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_tool.h b/tools/designer/src/components/buddyeditor/buddyeditor_tool.h new file mode 100644 index 0000000..dee43a0 --- /dev/null +++ b/tools/designer/src/components/buddyeditor/buddyeditor_tool.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_TOOL_H +#define BUDDYEDITOR_TOOL_H + +#include "buddyeditor_global.h" + +#include <QtCore/QPointer> + +#include <QtDesigner/QDesignerFormWindowToolInterface> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class BuddyEditor; + +class QT_BUDDYEDITOR_EXPORT BuddyEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit BuddyEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~BuddyEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer<BuddyEditor> m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUDDYEDITOR_TOOL_H diff --git a/tools/designer/src/components/component.pri b/tools/designer/src/components/component.pri new file mode 100644 index 0000000..c2fc10d --- /dev/null +++ b/tools/designer/src/components/component.pri @@ -0,0 +1,2 @@ + +TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end diff --git a/tools/designer/src/components/components.pro b/tools/designer/src/components/components.pro new file mode 100644 index 0000000..97d79b4 --- /dev/null +++ b/tools/designer/src/components/components.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = lib diff --git a/tools/designer/src/components/formeditor/brushmanagerproxy.cpp b/tools/designer/src/components/formeditor/brushmanagerproxy.cpp new file mode 100644 index 0000000..b1c056e --- /dev/null +++ b/tools/designer/src/components/formeditor/brushmanagerproxy.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtbrushmanager.h" +#include "brushmanagerproxy.h" +#include "qsimpleresource_p.h" +#include "qdesigner_utils_p.h" +#include "ui4_p.h" + +#include <QtXml/QXmlStreamWriter> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class BrushManagerProxyPrivate +{ + BrushManagerProxy *q_ptr; + Q_DECLARE_PUBLIC(BrushManagerProxy) + +public: + BrushManagerProxyPrivate(BrushManagerProxy *bp, QDesignerFormEditorInterface *core); + void brushAdded(const QString &name, const QBrush &brush); + void brushRemoved(const QString &name); + QString uniqueBrushFileName(const QString &brushName) const; + + QtBrushManager *m_Manager; + QString m_designerFolder; + const QString m_BrushFolder; + QString m_BrushPath; + QDesignerFormEditorInterface *m_Core; + QMap<QString, QString> m_FileToBrush; + QMap<QString, QString> m_BrushToFile; +}; + +BrushManagerProxyPrivate::BrushManagerProxyPrivate(BrushManagerProxy *bp, QDesignerFormEditorInterface *core) : + q_ptr(bp), + m_Manager(0), + m_BrushFolder(QLatin1String("brushes")), + m_Core(core) +{ + m_designerFolder = QDir::homePath(); + m_designerFolder += QDir::separator(); + m_designerFolder += QLatin1String(".designer"); + m_BrushPath = m_designerFolder; + m_BrushPath += QDir::separator(); + m_BrushPath += m_BrushFolder; +} +} // namespace qdesigner_internal + +using namespace qdesigner_internal; + +void BrushManagerProxyPrivate::brushAdded(const QString &name, const QBrush &brush) +{ + const QString filename = uniqueBrushFileName(name); + + QDir designerDir(m_designerFolder); + if (!designerDir.exists(m_BrushFolder)) + designerDir.mkdir(m_BrushFolder); + + QFile file(m_BrushPath + QDir::separator() +filename); + if (file.open(QIODevice::WriteOnly)) { + QSimpleResource resource(m_Core); + + DomBrush *dom = resource.saveBrush(brush); + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + writer.writeStartElement(QLatin1String("description")); + writer.writeAttribute(QLatin1String("name"), name); + dom->write(writer); + writer.writeEndElement(); + writer.writeEndDocument(); + + delete dom; + file.close(); + + m_FileToBrush[filename] = name; + m_BrushToFile[name] = filename; + } +} + +void BrushManagerProxyPrivate::brushRemoved(const QString &name) +{ + QDir brushDir(m_BrushPath); + + QString filename = m_BrushToFile[name]; + brushDir.remove(filename); + m_BrushToFile.remove(name); + m_FileToBrush.remove(filename); +} + +QString BrushManagerProxyPrivate::uniqueBrushFileName(const QString &brushName) const +{ + const QString extension = QLatin1String(".br"); + QString filename = brushName.toLower(); + filename += extension; + int i = 0; + while (m_FileToBrush.contains(filename)) { + filename = brushName.toLower(); + filename += QString::number(++i); + filename += extension; + } + return filename; +} + + +BrushManagerProxy::BrushManagerProxy(QDesignerFormEditorInterface *core, QObject *parent) + : QObject(parent) +{ + d_ptr = new BrushManagerProxyPrivate(this, core); +} + +BrushManagerProxy::~BrushManagerProxy() +{ + delete d_ptr; +} + +void BrushManagerProxy::setBrushManager(QtBrushManager *manager) +{ + if (d_ptr->m_Manager == manager) + return; + + if (d_ptr->m_Manager) { + disconnect(d_ptr->m_Manager, SIGNAL(brushAdded(const QString &, const QBrush &)), + this, SLOT(brushAdded(const QString &, const QBrush &))); + disconnect(d_ptr->m_Manager, SIGNAL(brushRemoved(const QString &)), + this, SLOT(brushRemoved(const QString &))); + } + + d_ptr->m_Manager = manager; + + if (!d_ptr->m_Manager) + return; + + // clear the manager + QMap<QString, QBrush> brushes = d_ptr->m_Manager->brushes(); + QMap<QString, QBrush>::ConstIterator it = brushes.constBegin(); + while (it != brushes.constEnd()) { + QString name = it.key(); + d_ptr->m_Manager->removeBrush(name); + + it++; + } + + // fill up the manager from compiled resources or from brush folder here + const QString nameAttribute = QLatin1String("name"); + const QString brush = QLatin1String("brush"); + const QString description = QLatin1String("description"); + + QDir brushDir(d_ptr->m_BrushPath); + bool customBrushesExist = brushDir.exists(); + if (customBrushesExist) { + // load brushes from brush folder + QStringList nameFilters; + nameFilters.append(QLatin1String("*.br")); + + QFileInfoList infos = brushDir.entryInfoList(nameFilters); + QListIterator<QFileInfo> it(infos); + while (it.hasNext()) { + const QFileInfo fi = it.next(); + + QString filename = fi.absoluteFilePath(); + + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + QXmlStreamReader reader(&file); + + //<description name="black" > + // <brush brushstyle="SolidPattern" > + // <color alpha="255" .../> + // </brush> + //</description> + + QString descname; + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + const QString tag = reader.name().toString().toLower(); + if (tag == description) { + if (!reader.attributes().hasAttribute(nameAttribute)) + reader.raiseError(tr("The element '%1' is missing the required attribute '%2'.") + .arg(tag, nameAttribute)); + else + descname = reader.attributes().value(nameAttribute).toString(); + continue; + } + if (tag == brush) { + DomBrush brush; + brush.read(reader); + + if (descname.isEmpty()) { + reader.raiseError(tr("Empty brush name encountered.")); + } else { + QSimpleResource resource(d_ptr->m_Core); + QBrush br = resource.setupBrush(&brush); + d_ptr->m_Manager->addBrush(descname, br); + d_ptr->m_FileToBrush[filename] = descname; + d_ptr->m_BrushToFile[descname] = filename; + } + continue; + } + reader.raiseError(tr("An unexpected element '%1' was encountered.").arg(tag)); + } + } + + file.close(); + + if (reader.hasError()) { + qdesigner_internal::designerWarning(tr("An error occurred when reading the brush definition file '%1' at line line %2, column %3: %4") + .arg(fi.fileName()) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString())); + continue; + } + } + } + } + + connect(d_ptr->m_Manager, SIGNAL(brushAdded(QString,QBrush)), + this, SLOT(brushAdded(QString, QBrush))); + connect(d_ptr->m_Manager, SIGNAL(brushRemoved(QString)), + this, SLOT(brushRemoved(QString))); + + if (!customBrushesExist) { + // load brushes from resources + QFile qrcFile(QLatin1String(":trolltech/brushes/defaultbrushes.xml")); + if (!qrcFile.open(QIODevice::ReadOnly)) + Q_ASSERT(0); + + QXmlStreamReader reader(&qrcFile); + + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().toString().toLower() == QLatin1String("description")) { + const QString name = reader.attributes().value(nameAttribute).toString(); + do { // forward to <brush> element, which DomBrush expects + reader.readNext(); + } while (!reader.atEnd() && reader.tokenType() != QXmlStreamReader::StartElement); + DomBrush brushDom; + brushDom.read(reader); + if (!reader.hasError()) { + QSimpleResource resource(d_ptr->m_Core); + QBrush br = resource.setupBrush(&brushDom); + d_ptr->m_Manager->addBrush(name, br); + } + } + } + } + if (reader.hasError()) { + // Should never happen + qdesigner_internal::designerWarning(tr("An error occurred when reading the resource file '%1' at line %2, column %3: %4") + .arg(qrcFile.fileName()) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString())); + } + + qrcFile.close(); + } +} + +QT_END_NAMESPACE + +#include "moc_brushmanagerproxy.cpp" diff --git a/tools/designer/src/components/formeditor/brushmanagerproxy.h b/tools/designer/src/components/formeditor/brushmanagerproxy.h new file mode 100644 index 0000000..cbe50ae --- /dev/null +++ b/tools/designer/src/components/formeditor/brushmanagerproxy.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BRUSHMANAGERPROXY_H +#define BRUSHMANAGERPROXY_H + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QtBrushManager; +class BrushManagerProxyPrivate; + +class BrushManagerProxy : public QObject +{ + Q_OBJECT +public: + explicit BrushManagerProxy(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~BrushManagerProxy(); + + void setBrushManager(QtBrushManager *manager); + +private: + BrushManagerProxyPrivate *d_ptr; + Q_DECLARE_PRIVATE(BrushManagerProxy) + Q_DISABLE_COPY(BrushManagerProxy) + Q_PRIVATE_SLOT(d_func(), void brushAdded(const QString &, const QBrush &)) + Q_PRIVATE_SLOT(d_func(), void brushRemoved(const QString &name)) +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/tools/designer/src/components/formeditor/default_actionprovider.cpp b/tools/designer/src/components/formeditor/default_actionprovider.cpp new file mode 100644 index 0000000..49bf095 --- /dev/null +++ b/tools/designer/src/components/formeditor/default_actionprovider.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_actionprovider.h" +#include "invisible_widget_p.h" +#include "qdesigner_toolbar_p.h" + +#include <QtGui/QAction> +#include <QtGui/QApplication> +#include <QtCore/QRect> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ ActionProviderBase: +// Draws the drag indicator when dragging an action over a widget +// that receives action Dnd, such as ToolBar, Menu or MenuBar. +ActionProviderBase::ActionProviderBase(QWidget *widget) : + m_indicator(new InvisibleWidget(widget)) +{ + Q_ASSERT(widget != 0); + + m_indicator->setAutoFillBackground(true); + m_indicator->setBackgroundRole(QPalette::Window); + + QPalette p; + p.setColor(m_indicator->backgroundRole(), Qt::red); + m_indicator->setPalette(p); + m_indicator->hide(); +} + +enum { indicatorSize = 2 }; + +// Position an indicator horizontally over the rectangle, indicating +// 'Insert before' (left or right according to layout direction) +static inline QRect horizontalIndicatorRect(const QRect &rect) +{ + const Qt::LayoutDirection layoutDirection = QApplication::layoutDirection(); + // Position right? + QRect rc = QRect(rect.x(), 0, indicatorSize, rect.height() - 1); + if (layoutDirection == Qt::RightToLeft) + rc.moveLeft(rc.x() + rect.width() - indicatorSize); + return rc; +} + +// Position an indicator vertically over the rectangle, indicating 'Insert before' (top) +static inline QRect verticalIndicatorRect(const QRect &rect) +{ + return QRect(0, rect.top(), rect.width() - 1, indicatorSize); +} + +// Determine the geometry of the indicator by retrieving +// the action under mouse and positioning the bar within its geometry. +QRect ActionProviderBase::indicatorGeometry(const QPoint &pos) const +{ + QAction *action = actionAt(pos); + if (!action) + return QRect(); + QRect rc = actionGeometry(action); + return orientation() == Qt::Horizontal ? horizontalIndicatorRect(rc) : verticalIndicatorRect(rc); +} + +// Adjust the indicator while dragging. (-1,1) is called to finish a DND operation +void ActionProviderBase::adjustIndicator(const QPoint &pos) +{ + if (pos == QPoint(-1, -1)) { + m_indicator->hide(); + return; + } + const QRect ig = indicatorGeometry(pos); + if (ig.isValid()) { + m_indicator->setGeometry(ig); + QPalette p = m_indicator->palette(); + if (p.color(m_indicator->backgroundRole()) != Qt::red) { + p.setColor(m_indicator->backgroundRole(), Qt::red); + m_indicator->setPalette(p); + } + m_indicator->show(); + m_indicator->raise(); + } else { + m_indicator->hide(); + } +} + +// ------------- QToolBarActionProvider +QToolBarActionProvider::QToolBarActionProvider(QToolBar *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QToolBarActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QToolBarActionProvider::actionAt(const QPoint &pos) const +{ + return ToolBarEventFilter::actionAt(m_widget, pos); +} + +Qt::Orientation QToolBarActionProvider::orientation() const +{ + return m_widget->orientation(); +} + +QRect QToolBarActionProvider::indicatorGeometry(const QPoint &pos) const +{ + const QRect actionRect = ActionProviderBase::indicatorGeometry(pos); + if (actionRect.isValid()) + return actionRect; + // Toolbar differs in that is has no dummy placeholder to 'insert before' + // when intending to append. Check the free area. + const QRect freeArea = ToolBarEventFilter::freeArea(m_widget); + if (!freeArea.contains(pos)) + return QRect(); + return orientation() == Qt::Horizontal ? horizontalIndicatorRect(freeArea) : verticalIndicatorRect(freeArea); +} + +// ------------- QMenuBarActionProvider +QMenuBarActionProvider::QMenuBarActionProvider(QMenuBar *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QMenuBarActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QMenuBarActionProvider::actionAt(const QPoint &pos) const +{ + return m_widget->actionAt(pos); +} + +Qt::Orientation QMenuBarActionProvider::orientation() const +{ + return Qt::Horizontal; +} + +// ------------- QMenuActionProvider +QMenuActionProvider::QMenuActionProvider(QMenu *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QMenuActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QMenuActionProvider::actionAt(const QPoint &pos) const +{ + return m_widget->actionAt(pos); +} + +Qt::Orientation QMenuActionProvider::orientation() const +{ + return Qt::Vertical; +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/default_actionprovider.h b/tools/designer/src/components/formeditor/default_actionprovider.h new file mode 100644 index 0000000..6c81ec6 --- /dev/null +++ b/tools/designer/src/components/formeditor/default_actionprovider.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_ACTIONPROVIDER_H +#define DEFAULT_ACTIONPROVIDER_H + +#include "formeditor_global.h" +#include "actionprovider_p.h" +#include <extensionfactory_p.h> + +#include <QtGui/QMenu> +#include <QtGui/QMenuBar> +#include <QtGui/QToolBar> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class FormWindow; + +class QT_FORMEDITOR_EXPORT ActionProviderBase: public QDesignerActionProviderExtension +{ +protected: + explicit ActionProviderBase(QWidget *widget); + +public: + virtual void adjustIndicator(const QPoint &pos); + virtual Qt::Orientation orientation() const = 0; + +protected: + virtual QRect indicatorGeometry(const QPoint &pos) const; + +private: + QWidget *m_indicator; +}; + +class QT_FORMEDITOR_EXPORT QToolBarActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QToolBarActionProvider(QToolBar *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +protected: + virtual QRect indicatorGeometry(const QPoint &pos) const; + +private: + QToolBar *m_widget; +}; + +class QT_FORMEDITOR_EXPORT QMenuBarActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QMenuBarActionProvider(QMenuBar *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +private: + QMenuBar *m_widget; +}; + +class QT_FORMEDITOR_EXPORT QMenuActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QMenuActionProvider(QMenu *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +private: + QMenu *m_widget; +}; + +typedef ExtensionFactory<QDesignerActionProviderExtension, QToolBar, QToolBarActionProvider> QToolBarActionProviderFactory; +typedef ExtensionFactory<QDesignerActionProviderExtension, QMenuBar, QMenuBarActionProvider> QMenuBarActionProviderFactory; +typedef ExtensionFactory<QDesignerActionProviderExtension, QMenu, QMenuActionProvider> QMenuActionProviderFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_ACTIONPROVIDER_H diff --git a/tools/designer/src/components/formeditor/default_container.cpp b/tools/designer/src/components/formeditor/default_container.cpp new file mode 100644 index 0000000..eb3cd4f --- /dev/null +++ b/tools/designer/src/components/formeditor/default_container.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_container.h" +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +template <class Container> +static inline void setCurrentContainerIndex(int index, Container *container) +{ + const bool blocked = container->signalsBlocked(); + container->blockSignals(true); + container->setCurrentIndex(index); + container->blockSignals(blocked); +} + +static inline void ensureNoParent(QWidget *widget) +{ + if (widget->parentWidget()) + widget->setParent(0); +} + +static const char *PageLabel = "Page"; + +namespace qdesigner_internal { + +// --------- QStackedWidgetContainer +QStackedWidgetContainer::QStackedWidgetContainer(QStackedWidget *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QStackedWidgetContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QStackedWidgetContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addWidget(widget); +} + +void QStackedWidgetContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertWidget(index, widget); +} + +void QStackedWidgetContainer::remove(int index) +{ + m_widget->removeWidget(widget(index)); +} + +// --------- QTabWidgetContainer +QTabWidgetContainer::QTabWidgetContainer(QTabWidget *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QTabWidgetContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QTabWidgetContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addTab(widget, QString::fromUtf8(PageLabel)); +} + +void QTabWidgetContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertTab(index, widget, QString::fromUtf8(PageLabel)); +} + +void QTabWidgetContainer::remove(int index) +{ + m_widget->removeTab(index); +} + +// ------------------- QToolBoxContainer +QToolBoxContainer::QToolBoxContainer(QToolBox *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QToolBoxContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QToolBoxContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addItem(widget, QString::fromUtf8(PageLabel)); +} + +void QToolBoxContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertItem(index, widget, QString::fromUtf8(PageLabel)); +} + +void QToolBoxContainer::remove(int index) +{ + m_widget->removeItem(index); +} + +// ------------------- QScrollAreaContainer +// We pass on active=true only if there are no children yet. +// If there are children, it is a legacy custom widget QScrollArea that has an internal, +// unmanaged child, in which case we deactivate the extension (otherwise we crash). +// The child will then not show up in the task menu + +QScrollAreaContainer::QScrollAreaContainer(QScrollArea *widget, QObject *parent) : + QObject(parent), + SingleChildContainer<QScrollArea>(widget, widget->widget() == 0) +{ +} +// ------------------- QDockWidgetContainer +QDockWidgetContainer::QDockWidgetContainer(QDockWidget *widget, QObject *parent) : + QObject(parent), + SingleChildContainer<QDockWidget>(widget) +{ +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/default_container.h b/tools/designer/src/components/formeditor/default_container.h new file mode 100644 index 0000000..e8547638 --- /dev/null +++ b/tools/designer/src/components/formeditor/default_container.h @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_CONTAINER_H +#define DEFAULT_CONTAINER_H + +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/extension.h> +#include <extensionfactory_p.h> + +#include <QtGui/QStackedWidget> +#include <QtGui/QTabWidget> +#include <QtGui/QToolBox> +#include <QtGui/QScrollArea> +#include <QtGui/QDockWidget> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ QStackedWidgetContainer +class QStackedWidgetContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QStackedWidgetContainer(QStackedWidget *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QStackedWidget *m_widget; +}; + +// ------------ QTabWidgetContainer +class QTabWidgetContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QTabWidgetContainer(QTabWidget *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QTabWidget *m_widget; +}; + +// ------------ QToolBoxContainer +class QToolBoxContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QToolBoxContainer(QToolBox *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QToolBox *m_widget; +}; + +// ------------ SingleChildContainer: +// Template for containers that have a single child widget using widget()/setWidget(). + +template <class Container> +class SingleChildContainer: public QDesignerContainerExtension +{ +protected: + explicit SingleChildContainer(Container *widget, bool active = true); +public: + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int /*index*/) {} + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int /*index*/) {} + +private: + const bool m_active; + Container *m_container; +}; + +template <class Container> +SingleChildContainer<Container>::SingleChildContainer(Container *widget, bool active) : + m_active(active), + m_container(widget) +{ +} + +template <class Container> +int SingleChildContainer<Container>::count() const +{ + return m_active && m_container->widget() ? 1 : 0; +} + +template <class Container> +QWidget *SingleChildContainer<Container>::widget(int /* index */) const +{ + return m_container->widget(); +} + +template <class Container> +int SingleChildContainer<Container>::currentIndex() const +{ + return m_active && m_container->widget() ? 0 : -1; +} + +template <class Container> +void SingleChildContainer<Container>::addWidget(QWidget *widget) +{ + Q_ASSERT(m_container->widget() == 0); + widget->setParent(m_container); + m_container->setWidget(widget); +} + +template <class Container> +void SingleChildContainer<Container>::insertWidget(int /* index */, QWidget *widget) +{ + addWidget(widget); +} + +// ------------ QScrollAreaContainer +class QScrollAreaContainer: public QObject, public SingleChildContainer<QScrollArea> +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QScrollAreaContainer(QScrollArea *widget, QObject *parent = 0); +}; + +// --------------- QDockWidgetContainer +class QDockWidgetContainer: public QObject, public SingleChildContainer<QDockWidget> +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QDockWidgetContainer(QDockWidget *widget, QObject *parent = 0); +}; + +typedef ExtensionFactory<QDesignerContainerExtension, QStackedWidget, QStackedWidgetContainer> QDesignerStackedWidgetContainerFactory; +typedef ExtensionFactory<QDesignerContainerExtension, QTabWidget, QTabWidgetContainer> QDesignerTabWidgetContainerFactory; +typedef ExtensionFactory<QDesignerContainerExtension, QToolBox, QToolBoxContainer> QDesignerToolBoxContainerFactory; +typedef ExtensionFactory<QDesignerContainerExtension, QScrollArea, QScrollAreaContainer> QScrollAreaContainerFactory; +typedef ExtensionFactory<QDesignerContainerExtension, QDockWidget, QDockWidgetContainer> QDockWidgetContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_CONTAINER_H diff --git a/tools/designer/src/components/formeditor/default_layoutdecoration.cpp b/tools/designer/src/components/formeditor/default_layoutdecoration.cpp new file mode 100644 index 0000000..5558068 --- /dev/null +++ b/tools/designer/src/components/formeditor/default_layoutdecoration.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_layoutdecoration.h" +#include "qlayout_widget_p.h" + +#include <layoutinfo_p.h> + +#include <QtDesigner/QDesignerMetaDataBaseItemInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---- QDesignerLayoutDecorationFactory ---- +QDesignerLayoutDecorationFactory::QDesignerLayoutDecorationFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *QDesignerLayoutDecorationFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (!object->isWidgetType() || iid != Q_TYPEID(QDesignerLayoutDecorationExtension)) + return 0; + + QWidget *widget = qobject_cast<QWidget*>(object); + + if (const QLayoutWidget *layoutWidget = qobject_cast<const QLayoutWidget*>(widget)) + return QLayoutSupport::createLayoutSupport(layoutWidget->formWindow(), widget, parent); + + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) + if (LayoutInfo::managedLayout(fw->core(), widget)) + return QLayoutSupport::createLayoutSupport(fw, widget, parent); + + return 0; +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/default_layoutdecoration.h b/tools/designer/src/components/formeditor/default_layoutdecoration.h new file mode 100644 index 0000000..770372f --- /dev/null +++ b/tools/designer/src/components/formeditor/default_layoutdecoration.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_LAYOUTDECORATION_H +#define DEFAULT_LAYOUTDECORATION_H + +#include "formeditor_global.h" +#include <QtDesigner/QDesignerLayoutDecorationExtension> +#include <QtDesigner/default_extensionfactory.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +class QDesignerLayoutDecorationFactory: public QExtensionFactory +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionFactory) +public: + explicit QDesignerLayoutDecorationFactory(QExtensionManager *parent = 0); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_LAYOUTDECORATION_H diff --git a/tools/designer/src/components/formeditor/defaultbrushes.xml b/tools/designer/src/components/formeditor/defaultbrushes.xml new file mode 100644 index 0000000..88035c3 --- /dev/null +++ b/tools/designer/src/components/formeditor/defaultbrushes.xml @@ -0,0 +1,542 @@ +<brushes> + <description name="French" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="1" coordinatemode="StretchToDeviceMode" endy="0" > + <gradientstop position="0" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.323" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.343" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.656" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.676" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="German" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="0" coordinatemode="StretchToDeviceMode" endy="1" > + <gradientstop position="0" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.323" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.343" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.656" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.676" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Greek" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="0" coordinatemode="StretchToDeviceMode" endy="1" > + <gradientstop position="0" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.09" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.105" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.205" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.22" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.32" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.335" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.435" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.45" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.55" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.565" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.665" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.68" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.78" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="0.795" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.895" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.91" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>0</red> + <green>176</green> + <blue>221</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Italian" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="1" coordinatemode="StretchToDeviceMode" endy="0" > + <gradientstop position="0" > + <color alpha="255" > + <red>60</red> + <green>160</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.323" > + <color alpha="255" > + <red>60</red> + <green>160</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.343" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.656" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.676" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Japanese" > + <brush brushstyle="RadialGradientPattern" > + <gradient focalx="0.5" focaly="0.5" radius="0.5" spread="PadSpread" type="RadialGradient" coordinatemode="StretchToDeviceMode" centralx="0.5" centraly="0.5" > + <gradientstop position="0" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.49" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.51" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Norwegian" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="1" coordinatemode="StretchToDeviceMode" endy="0" > + <gradientstop position="0" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.225" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.25" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.275" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.3" > + <color alpha="255" > + <red>5</red> + <green>0</green> + <blue>70</blue> + </color> + </gradientstop> + <gradientstop position="0.4" > + <color alpha="255" > + <red>5</red> + <green>0</green> + <blue>70</blue> + </color> + </gradientstop> + <gradientstop position="0.425" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.45" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.475" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Polish" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="0" coordinatemode="StretchToDeviceMode" endy="1" > + <gradientstop position="0" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.475" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </gradientstop> + <gradientstop position="0.525" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="Spanish" > + <brush brushstyle="LinearGradientPattern" > + <gradient spread="PadSpread" startx="0" starty="0" type="LinearGradient" endx="0" coordinatemode="StretchToDeviceMode" endy="1" > + <gradientstop position="0" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.24" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.26" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.74" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="0.76" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + <gradientstop position="1" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </gradientstop> + </gradient> + </brush> + </description> + <description name="black" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </brush> + </description> + <description name="blue" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>0</green> + <blue>255</blue> + </color> + </brush> + </description> + <description name="cyan" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </description> + <description name="green" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </brush> + </description> + <description name="magenta" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>255</blue> + </color> + </brush> + </description> + <description name="red" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </brush> + </description> + <description name="white" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </description> + <description name="yellow" > + <brush brushstyle="SolidPattern" > + <color alpha="255" > + <red>255</red> + <green>255</green> + <blue>0</blue> + </color> + </brush> + </description> +</brushes> diff --git a/tools/designer/src/components/formeditor/deviceprofiledialog.cpp b/tools/designer/src/components/formeditor/deviceprofiledialog.cpp new file mode 100644 index 0000000..995bc3f --- /dev/null +++ b/tools/designer/src/components/formeditor/deviceprofiledialog.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceprofiledialog.h" +#include "ui_deviceprofiledialog.h" + +#include <abstractdialoggui_p.h> +#include <deviceprofile_p.h> + +#include <QtGui/QDialogButtonBox> +#include <QtGui/QVBoxLayout> +#include <QtGui/QPushButton> +#include <QtGui/QStyleFactory> +#include <QtGui/QFontDatabase> + +#include <QtCore/QFileInfo> +#include <QtCore/QFile> + +QT_BEGIN_NAMESPACE + +static const char *profileExtensionC = "qdp"; + +static inline QString fileFilter() +{ + return qdesigner_internal::DeviceProfileDialog::tr("Device Profiles (*.%1)").arg(QLatin1String(profileExtensionC)); +} + +// Populate a combo with a sequence of integers, also set them as data. +template <class IntIterator> + static void populateNumericCombo(IntIterator i1, IntIterator i2, QComboBox *cb) +{ + QString s; + cb->setEditable(false); + for ( ; i1 != i2 ; ++i1) { + const int n = *i1; + s.setNum(n); + cb->addItem(s, QVariant(n)); + } +} + +namespace qdesigner_internal { + +DeviceProfileDialog::DeviceProfileDialog(QDesignerDialogGuiInterface *dlgGui, QWidget *parent) : + QDialog(parent), + m_ui(new Ui::DeviceProfileDialog), + m_dlgGui(dlgGui) +{ + setModal(true); + m_ui->setupUi(this); + + const QList<int> standardFontSizes = QFontDatabase::standardSizes(); + populateNumericCombo(standardFontSizes.constBegin(), standardFontSizes.constEnd(), m_ui->m_systemFontSizeCombo); + + // Styles + const QStringList styles = QStyleFactory::keys(); + m_ui->m_styleCombo->addItem(tr("Default"), QVariant(QString())); + const QStringList::const_iterator cend = styles.constEnd(); + for (QStringList::const_iterator it = styles.constBegin(); it != cend; ++it) + m_ui->m_styleCombo->addItem(*it, *it); + + connect(m_ui->m_nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(nameChanged(QString))); + connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_ui->buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); + // Note that Load/Save emit accepted() of the button box.. + connect(m_ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(save())); + connect(m_ui->buttonBox->button(QDialogButtonBox::Open), SIGNAL(clicked()), this, SLOT(open())); +} + +DeviceProfileDialog::~DeviceProfileDialog() +{ + delete m_ui; +} + +DeviceProfile DeviceProfileDialog::deviceProfile() const +{ + DeviceProfile rc; + rc.setName(m_ui->m_nameLineEdit->text()); + rc.setFontFamily(m_ui->m_systemFontComboBox->currentFont().family()); + rc.setFontPointSize(m_ui->m_systemFontSizeCombo->itemData(m_ui->m_systemFontSizeCombo->currentIndex()).toInt()); + + int dpiX, dpiY; + m_ui->m_dpiChooser->getDPI(&dpiX, &dpiY); + rc.setDpiX(dpiX); + rc.setDpiY(dpiY); + + rc.setStyle(m_ui->m_styleCombo->itemData(m_ui->m_styleCombo->currentIndex()).toString()); + + return rc; +} + +void DeviceProfileDialog::setDeviceProfile(const DeviceProfile &s) +{ + m_ui->m_nameLineEdit->setText(s.name()); + m_ui->m_systemFontComboBox->setCurrentFont(QFont(s.fontFamily())); + const int fontSizeIndex = m_ui->m_systemFontSizeCombo->findData(QVariant(s.fontPointSize())); + m_ui->m_systemFontSizeCombo->setCurrentIndex(fontSizeIndex != -1 ? fontSizeIndex : 0); + m_ui->m_dpiChooser->setDPI(s.dpiX(), s.dpiY()); + const int styleIndex = m_ui->m_styleCombo->findData(s.style()); + m_ui->m_styleCombo->setCurrentIndex(styleIndex != -1 ? styleIndex : 0); +} + +void DeviceProfileDialog::setOkButtonEnabled(bool v) +{ + m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(v); +} + +bool DeviceProfileDialog::showDialog(const QStringList &existingNames) +{ + m_existingNames = existingNames; + m_ui->m_nameLineEdit->setFocus(Qt::OtherFocusReason); + nameChanged(m_ui->m_nameLineEdit->text()); + return exec() == Accepted; +} + +void DeviceProfileDialog::nameChanged(const QString &name) +{ + const bool invalid = name.isEmpty() || m_existingNames.indexOf(name) != -1; + setOkButtonEnabled(!invalid); +} + +void DeviceProfileDialog::save() +{ + QString fn = m_dlgGui->getSaveFileName(this, tr("Save Profile"), QString(), fileFilter()); + if (fn.isEmpty()) + return; + if (QFileInfo(fn).completeSuffix().isEmpty()) { + fn += QLatin1Char('.'); + fn += QLatin1String(profileExtensionC); + } + + QFile file(fn); + if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) { + critical(tr("Save Profile - Error"), tr("Unable to open the file '%1' for writing: %2").arg(fn, file.errorString())); + return; + } + file.write(deviceProfile().toXml().toUtf8()); +} + +void DeviceProfileDialog::open() +{ + const QString fn = m_dlgGui->getOpenFileName(this, tr("Open profile"), QString(), fileFilter()); + if (fn.isEmpty()) + return; + + QFile file(fn); + if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) { + critical(tr("Open Profile - Error"), tr("Unable to open the file '%1' for reading: %2").arg(fn, file.errorString())); + return; + } + QString errorMessage; + DeviceProfile newSettings; + if (!newSettings.fromXml(QString::fromUtf8(file.readAll()), &errorMessage)) { + critical(tr("Open Profile - Error"), tr("'%1' is not a valid profile: %2").arg(fn, errorMessage)); + return; + } + setDeviceProfile(newSettings); +} + +void DeviceProfileDialog::critical(const QString &title, const QString &msg) +{ + m_dlgGui->message(this, QDesignerDialogGuiInterface::OtherMessage, QMessageBox::Critical, title, msg); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/deviceprofiledialog.h b/tools/designer/src/components/formeditor/deviceprofiledialog.h new file mode 100644 index 0000000..dafcd77 --- /dev/null +++ b/tools/designer/src/components/formeditor/deviceprofiledialog.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef SYSTEMSETTINGSDIALOG_H +#define SYSTEMSETTINGSDIALOG_H + +#include <QtGui/QDialog> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +namespace Ui { + class DeviceProfileDialog; +} + +class QDesignerDialogGuiInterface; + +class QDialogButtonBox; + +namespace qdesigner_internal { + +class DeviceProfile; + +/* DeviceProfileDialog: Widget to edit system settings for embedded design */ + +class DeviceProfileDialog : public QDialog +{ + Q_DISABLE_COPY(DeviceProfileDialog) + Q_OBJECT +public: + explicit DeviceProfileDialog(QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0); + ~DeviceProfileDialog(); + + DeviceProfile deviceProfile() const; + void setDeviceProfile(const DeviceProfile &s); + + bool showDialog(const QStringList &existingNames); + +private slots: + void setOkButtonEnabled(bool); + void nameChanged(const QString &name); + void save(); + void open(); + +private: + void critical(const QString &title, const QString &msg); + Ui::DeviceProfileDialog *m_ui; + QDesignerDialogGuiInterface *m_dlgGui; + QStringList m_existingNames; +}; +} + +QT_END_NAMESPACE + +#endif // SYSTEMSETTINGSDIALOG_H diff --git a/tools/designer/src/components/formeditor/deviceprofiledialog.ui b/tools/designer/src/components/formeditor/deviceprofiledialog.ui new file mode 100644 index 0000000..3186c57 --- /dev/null +++ b/tools/designer/src/components/formeditor/deviceprofiledialog.ui @@ -0,0 +1,100 @@ +<ui version="4.0" > + <class>DeviceProfileDialog</class> + <widget class="QDialog" name="dialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>348</width> + <height>209</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QWidget" native="1" name="SystemSettingsWidget" > + <layout class="QFormLayout" name="formLayout" > + <item row="1" column="0" > + <widget class="QLabel" name="m_systemFontFamilyLabel" > + <property name="text" > + <string>&Family</string> + </property> + <property name="buddy" > + <cstring>m_systemFontComboBox</cstring> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QFontComboBox" name="m_systemFontComboBox" /> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="m_systemFontSizeLabel" > + <property name="text" > + <string>&Point Size</string> + </property> + <property name="buddy" > + <cstring>m_systemFontSizeCombo</cstring> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QComboBox" name="m_systemFontSizeCombo" /> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="m_styleLabel" > + <property name="text" > + <string>Style</string> + </property> + <property name="buddy" > + <cstring>m_styleCombo</cstring> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QComboBox" name="m_styleCombo" /> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="m_systemDPILabel" > + <property name="text" > + <string>Device DPI</string> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="qdesigner_internal::DPI_Chooser" native="1" name="m_dpiChooser" /> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="m_nameLabel" > + <property name="text" > + <string>Name</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="m_nameLineEdit" /> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>qdesigner_internal::DPI_Chooser</class> + <extends>QWidget</extends> + <header>dpi_chooser.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/tools/designer/src/components/formeditor/dpi_chooser.cpp b/tools/designer/src/components/formeditor/dpi_chooser.cpp new file mode 100644 index 0000000..d766e31 --- /dev/null +++ b/tools/designer/src/components/formeditor/dpi_chooser.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dpi_chooser.h" + +#include <deviceprofile_p.h> + +#include <QtGui/QComboBox> +#include <QtGui/QSpinBox> +#include <QtGui/QLabel> +#include <QtGui/QVBoxLayout> +#include <QtGui/QHBoxLayout> +#include <QtGui/QPushButton> +#include <QtGui/QCheckBox> + +QT_BEGIN_NAMESPACE + +enum { minDPI = 50, maxDPI = 400 }; + +namespace qdesigner_internal { + +// Entry struct for predefined values +struct DPI_Entry { + int dpiX; + int dpiY; + const char *description; +}; + +const struct DPI_Entry dpiEntries[] = { + //: Embedded device standard screen resolution + { 96, 96, QT_TRANSLATE_NOOP("DPI_Chooser", "Standard (96 x 96)") }, + //: Embedded device screen resolution + { 179, 185, QT_TRANSLATE_NOOP("DPI_Chooser", "Greenphone (179 x 185)") }, + //: Embedded device high definition screen resolution + { 192, 192, QT_TRANSLATE_NOOP("DPI_Chooser", "High (192 x 192)") } +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(const struct qdesigner_internal::DPI_Entry*); + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------- DPI_Chooser + +DPI_Chooser::DPI_Chooser(QWidget *parent) : + QWidget(parent), + m_systemEntry(new DPI_Entry), + m_predefinedCombo(new QComboBox), + m_dpiXSpinBox(new QSpinBox), + m_dpiYSpinBox(new QSpinBox) +{ + // Predefined settings: System + DeviceProfile::systemResolution(&(m_systemEntry->dpiX), &(m_systemEntry->dpiY)); + m_systemEntry->description = 0; + const struct DPI_Entry *systemEntry = m_systemEntry; + //: System resolution + m_predefinedCombo->addItem(tr("System (%1 x %2)").arg(m_systemEntry->dpiX).arg(m_systemEntry->dpiY), qVariantFromValue(systemEntry)); + // Devices. Exclude the system values as not to duplicate the entries + const int predefinedCount = sizeof(dpiEntries)/sizeof(DPI_Entry); + const struct DPI_Entry *ecend = dpiEntries + predefinedCount; + for (const struct DPI_Entry *it = dpiEntries; it < ecend; ++it) + if (it->dpiX != m_systemEntry->dpiX || it->dpiY != m_systemEntry->dpiY) + m_predefinedCombo->addItem(tr(it->description), qVariantFromValue(it)); + m_predefinedCombo->addItem(tr("User defined")); + + setFocusProxy(m_predefinedCombo); + m_predefinedCombo->setEditable(false); + m_predefinedCombo->setCurrentIndex(0); + connect(m_predefinedCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(syncSpinBoxes())); + // top row with predefined settings + QVBoxLayout *vBoxLayout = new QVBoxLayout; + vBoxLayout->setMargin(0); + vBoxLayout->addWidget(m_predefinedCombo); + // Spin box row + QHBoxLayout *hBoxLayout = new QHBoxLayout; + hBoxLayout->setMargin(0); + + m_dpiXSpinBox->setMinimum(minDPI); + m_dpiXSpinBox->setMaximum(maxDPI); + hBoxLayout->addWidget(m_dpiXSpinBox); + //: DPI X/Y separator + hBoxLayout->addWidget(new QLabel(tr(" x "))); + + m_dpiYSpinBox->setMinimum(minDPI); + m_dpiYSpinBox->setMaximum(maxDPI); + hBoxLayout->addWidget(m_dpiYSpinBox); + + hBoxLayout->addStretch(); + vBoxLayout->addLayout(hBoxLayout); + setLayout(vBoxLayout); + + syncSpinBoxes(); +} + +DPI_Chooser::~DPI_Chooser() +{ + delete m_systemEntry; +} + +void DPI_Chooser::getDPI(int *dpiX, int *dpiY) const +{ + *dpiX = m_dpiXSpinBox->value(); + *dpiY = m_dpiYSpinBox->value(); +} + +void DPI_Chooser::setDPI(int dpiX, int dpiY) +{ + // Default to system if it is something weird + const bool valid = dpiX >= minDPI && dpiX <= maxDPI && dpiY >= minDPI && dpiY <= maxDPI; + if (!valid) { + m_predefinedCombo->setCurrentIndex(0); + return; + } + // Try to find the values among the predefined settings + const int count = m_predefinedCombo->count(); + int predefinedIndex = -1; + for (int i = 0; i < count; i++) { + const QVariant data = m_predefinedCombo->itemData(i); + if (data.type() != QVariant::Invalid) { + const struct DPI_Entry *entry = qvariant_cast<const struct DPI_Entry *>(data); + if (entry->dpiX == dpiX && entry->dpiY == dpiY) { + predefinedIndex = i; + break; + } + } + } + if (predefinedIndex != -1) { + m_predefinedCombo->setCurrentIndex(predefinedIndex); // triggers syncSpinBoxes() + } else { + setUserDefinedValues(dpiX, dpiY); + } +} + +void DPI_Chooser::setUserDefinedValues(int dpiX, int dpiY) +{ + const bool blocked = m_predefinedCombo->blockSignals(true); + m_predefinedCombo->setCurrentIndex(m_predefinedCombo->count() - 1); + m_predefinedCombo->blockSignals(blocked); + + m_dpiXSpinBox->setEnabled(true); + m_dpiYSpinBox->setEnabled(true); + m_dpiXSpinBox->setValue(dpiX); + m_dpiYSpinBox->setValue(dpiY); +} + +void DPI_Chooser::syncSpinBoxes() +{ + const int predefIdx = m_predefinedCombo->currentIndex(); + const QVariant data = m_predefinedCombo->itemData(predefIdx); + + // Predefined mode in which spin boxes are disabled or user defined? + const bool userSetting = data.type() == QVariant::Invalid; + m_dpiXSpinBox->setEnabled(userSetting); + m_dpiYSpinBox->setEnabled(userSetting); + + if (!userSetting) { + const struct DPI_Entry *entry = qvariant_cast<const struct DPI_Entry *>(data); + m_dpiXSpinBox->setValue(entry->dpiX); + m_dpiYSpinBox->setValue(entry->dpiY); + } +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/dpi_chooser.h b/tools/designer/src/components/formeditor/dpi_chooser.h new file mode 100644 index 0000000..f8ca810 --- /dev/null +++ b/tools/designer/src/components/formeditor/dpi_chooser.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DPICHOOSER_H +#define DPICHOOSER_H + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QSpinBox; +class QComboBox; + +namespace qdesigner_internal { + +struct DPI_Entry; + +/* Let the user choose a DPI settings */ +class DPI_Chooser : public QWidget { + Q_DISABLE_COPY(DPI_Chooser) + Q_OBJECT + +public: + explicit DPI_Chooser(QWidget *parent = 0); + ~DPI_Chooser(); + + void getDPI(int *dpiX, int *dpiY) const; + void setDPI(int dpiX, int dpiY); + +private slots: + void syncSpinBoxes(); + +private: + void setUserDefinedValues(int dpiX, int dpiY); + + struct DPI_Entry *m_systemEntry; + QComboBox *m_predefinedCombo; + QSpinBox *m_dpiXSpinBox; + QSpinBox *m_dpiYSpinBox; +}; +} + +QT_END_NAMESPACE + +#endif // DPICHOOSER_H diff --git a/tools/designer/src/components/formeditor/embeddedoptionspage.cpp b/tools/designer/src/components/formeditor/embeddedoptionspage.cpp new file mode 100644 index 0000000..bf3f3f1 --- /dev/null +++ b/tools/designer/src/components/formeditor/embeddedoptionspage.cpp @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::EmbeddedOptionsControl +*/ + +#include "embeddedoptionspage.h" +#include "deviceprofiledialog.h" +#include "widgetfactory_p.h" +#include "formwindowmanager.h" + +#include <deviceprofile_p.h> +#include <iconloader_p.h> +#include <shared_settings_p.h> +#include <abstractdialoggui_p.h> +#include <formwindowbase_p.h> + + +// SDK +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtGui/QLabel> +#include <QtGui/QHBoxLayout> +#include <QtGui/QVBoxLayout> +#include <QtGui/QApplication> +#include <QtGui/QComboBox> +#include <QtGui/QToolButton> +#include <QtGui/QMessageBox> +#include <QtGui/QLabel> +#include <QtGui/QGroupBox> + +#include <QtCore/QSet> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +typedef QList<DeviceProfile> DeviceProfileList; + +enum { profileComboIndexOffset = 1 }; + +// Sort by name. Used by template, do not make it static! +bool deviceProfileLessThan(const DeviceProfile &d1, const DeviceProfile &d2) +{ + return d1.name().toLower() < d2.name().toLower(); +} + +static bool ask(QWidget *parent, + QDesignerDialogGuiInterface *dlgui, + const QString &title, + const QString &what) +{ + return dlgui->message(parent, QDesignerDialogGuiInterface::OtherMessage, + QMessageBox::Question, title, what, + QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; +} + +// ------------ EmbeddedOptionsControlPrivate +class EmbeddedOptionsControlPrivate { + Q_DISABLE_COPY(EmbeddedOptionsControlPrivate) +public: + EmbeddedOptionsControlPrivate(QDesignerFormEditorInterface *core); + void init(EmbeddedOptionsControl *q); + + bool isDirty() const { return m_dirty; } + + void loadSettings(); + void saveSettings(); + void slotAdd(); + void slotEdit(); + void slotDelete(); + void slotProfileIndexChanged(int); + +private: + QStringList existingProfileNames() const; + void sortAndPopulateProfileCombo(); + void updateState(); + void updateDescriptionLabel(); + + QDesignerFormEditorInterface *m_core; + QComboBox *m_profileCombo; + QToolButton *m_addButton; + QToolButton *m_editButton; + QToolButton *m_deleteButton; + QLabel *m_descriptionLabel; + + DeviceProfileList m_sortedProfiles; + EmbeddedOptionsControl *m_q; + bool m_dirty; + QSet<QString> m_usedProfiles; +}; + +EmbeddedOptionsControlPrivate::EmbeddedOptionsControlPrivate(QDesignerFormEditorInterface *core) : + m_core(core), + m_profileCombo(new QComboBox), + m_addButton(new QToolButton), + m_editButton(new QToolButton), + m_deleteButton(new QToolButton), + m_descriptionLabel(new QLabel), + m_q(0), + m_dirty(false) +{ + m_descriptionLabel->setMinimumHeight(80); + // Determine used profiles to lock them + const QDesignerFormWindowManagerInterface *fwm = core->formWindowManager(); + if (const int fwCount = fwm->formWindowCount()) { + for (int i = 0; i < fwCount; i++) + if (const FormWindowBase *fwb = qobject_cast<const FormWindowBase *>(fwm->formWindow(i))) { + const QString deviceProfileName = fwb->deviceProfileName(); + if (!deviceProfileName.isEmpty()) + m_usedProfiles.insert(deviceProfileName); + } + } +} + +void EmbeddedOptionsControlPrivate::init(EmbeddedOptionsControl *q) +{ + m_q = q; + QVBoxLayout *vLayout = new QVBoxLayout; + QHBoxLayout *hLayout = new QHBoxLayout; + m_profileCombo->setMinimumWidth(200); + m_profileCombo->setEditable(false); + hLayout->addWidget(m_profileCombo); + m_profileCombo->addItem(EmbeddedOptionsControl::tr("None")); + EmbeddedOptionsControl::connect(m_profileCombo, SIGNAL(currentIndexChanged(int)), m_q, SLOT(slotProfileIndexChanged(int))); + + m_addButton->setIcon(createIconSet(QString::fromUtf8("plus.png"))); + m_addButton->setToolTip(EmbeddedOptionsControl::tr("Add a profile")); + EmbeddedOptionsControl::connect(m_addButton, SIGNAL(clicked()), m_q, SLOT(slotAdd())); + hLayout->addWidget(m_addButton); + + EmbeddedOptionsControl::connect(m_editButton, SIGNAL(clicked()), m_q, SLOT(slotEdit())); + m_editButton->setIcon(createIconSet(QString::fromUtf8("edit.png"))); + m_editButton->setToolTip(EmbeddedOptionsControl::tr("Edit the selected profile")); + hLayout->addWidget(m_editButton); + + m_deleteButton->setIcon(createIconSet(QString::fromUtf8("minus.png"))); + m_deleteButton->setToolTip(EmbeddedOptionsControl::tr("Delete the selected profile")); + EmbeddedOptionsControl::connect(m_deleteButton, SIGNAL(clicked()), m_q, SLOT(slotDelete())); + hLayout->addWidget(m_deleteButton); + + hLayout->addStretch(); + vLayout->addLayout(hLayout); + vLayout->addWidget(m_descriptionLabel); + m_q->setLayout(vLayout); +} + +QStringList EmbeddedOptionsControlPrivate::existingProfileNames() const +{ + QStringList rc; + const DeviceProfileList::const_iterator dcend = m_sortedProfiles.constEnd(); + for (DeviceProfileList::const_iterator it = m_sortedProfiles.constBegin(); it != dcend; ++it) + rc.push_back(it->name()); + return rc; +} + +void EmbeddedOptionsControlPrivate::slotAdd() +{ + DeviceProfileDialog dlg(m_core->dialogGui(), m_q); + dlg.setWindowTitle(EmbeddedOptionsControl::tr("Add Profile")); + // Create a new profile with a new, unique name + DeviceProfile settings; + settings.fromSystem(); + dlg.setDeviceProfile(settings); + + const QStringList names = existingProfileNames(); + const QString newNamePrefix = EmbeddedOptionsControl::tr("New profile"); + QString newName = newNamePrefix; + for (int i = 2; names.contains(newName); i++) { + newName = newNamePrefix; + newName += QString::number(i); + } + + settings.setName(newName); + dlg.setDeviceProfile(settings); + if (dlg.showDialog(names)) { + const DeviceProfile newProfile = dlg.deviceProfile(); + m_sortedProfiles.push_back(newProfile); + // Maintain sorted order + sortAndPopulateProfileCombo(); + const int index = m_profileCombo->findText(newProfile.name()); + m_profileCombo->setCurrentIndex(index); + m_dirty = true; + } +} + +void EmbeddedOptionsControlPrivate::slotEdit() +{ + const int index = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (index < 0) + return; + + // Edit the profile, compile a list of existing names + // excluding current one. re-insert if changed, + // re-sort if name changed. + const DeviceProfile oldProfile = m_sortedProfiles.at(index); + const QString oldName = oldProfile.name(); + QStringList names = existingProfileNames(); + names.removeAll(oldName); + + DeviceProfileDialog dlg(m_core->dialogGui(), m_q); + dlg.setWindowTitle(EmbeddedOptionsControl::tr("Edit Profile")); + dlg.setDeviceProfile(oldProfile); + if (dlg.showDialog(names)) { + const DeviceProfile newProfile = dlg.deviceProfile(); + if (newProfile != oldProfile) { + m_dirty = true; + m_sortedProfiles[index] = newProfile; + if (newProfile.name() != oldName) { + sortAndPopulateProfileCombo(); + const int index = m_profileCombo->findText(newProfile.name()); + m_profileCombo->setCurrentIndex(index); + } else { + updateDescriptionLabel(); + } + + } + } +} + +void EmbeddedOptionsControlPrivate::slotDelete() +{ + const int index = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (index < 0) + return; + const QString name = m_sortedProfiles.at(index).name(); + if (ask(m_q, m_core->dialogGui(), + EmbeddedOptionsControl::tr("Delete Profile"), + EmbeddedOptionsControl::tr("Would you like to delete the profile '%1'?").arg(name))) { + m_profileCombo->setCurrentIndex(0); + m_sortedProfiles.removeAt(index); + m_profileCombo->removeItem(index + profileComboIndexOffset); + m_dirty = true; + } +} + +void EmbeddedOptionsControlPrivate::sortAndPopulateProfileCombo() +{ + // Clear items until only "None" is left + for (int i = m_profileCombo->count() - 1; i > 0; i--) + m_profileCombo->removeItem(i); + if (!m_sortedProfiles.empty()) { + qSort(m_sortedProfiles.begin(), m_sortedProfiles.end(), deviceProfileLessThan); + m_profileCombo->addItems(existingProfileNames()); + } +} + +void EmbeddedOptionsControlPrivate::loadSettings() +{ + const QDesignerSharedSettings settings(m_core); + m_sortedProfiles = settings.deviceProfiles(); + sortAndPopulateProfileCombo(); + // Index: 0 is "None" + const int settingsIndex = settings.currentDeviceProfileIndex(); + const int profileIndex = settingsIndex >= 0 && settingsIndex < m_sortedProfiles.size() ? settingsIndex + profileComboIndexOffset : 0; + m_profileCombo->setCurrentIndex(profileIndex); + updateState(); + m_dirty = false; +} + +void EmbeddedOptionsControlPrivate::saveSettings() +{ + QDesignerSharedSettings settings(m_core); + settings.setDeviceProfiles(m_sortedProfiles); + // Index: 0 is "None" + settings.setCurrentDeviceProfileIndex(m_profileCombo->currentIndex() - profileComboIndexOffset); + m_dirty = false; +} + +//: Format embedded device profile description +static const char *descriptionFormat = QT_TRANSLATE_NOOP("EmbeddedOptionsControl", +"<html>" +"<table>" +"<tr><td><b>Font</b></td><td>%1, %2</td></tr>" +"<tr><td><b>Style</b></td><td>%3</td></tr>" +"<tr><td><b>Resolution</b></td><td>%4 x %5</td></tr>" +"</table>" +"</html>"); + +static inline QString description(const DeviceProfile& p) +{ + QString styleName = p.style(); + if (styleName.isEmpty()) + styleName = EmbeddedOptionsControl::tr("Default"); + return EmbeddedOptionsControl::tr(descriptionFormat). + arg(p.fontFamily()).arg(p.fontPointSize()).arg(styleName).arg(p.dpiX()).arg(p.dpiY()); +} + +void EmbeddedOptionsControlPrivate::updateDescriptionLabel() +{ + const int profileIndex = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (profileIndex >= 0) { + m_descriptionLabel->setText(description(m_sortedProfiles.at(profileIndex))); + } else { + m_descriptionLabel->clear(); + } +} + +void EmbeddedOptionsControlPrivate::updateState() +{ + const int profileIndex = m_profileCombo->currentIndex() - profileComboIndexOffset; + // Allow for changing/deleting only if it is not in use + bool modifyEnabled = false; + if (profileIndex >= 0) + modifyEnabled = !m_usedProfiles.contains(m_sortedProfiles.at(profileIndex).name()); + m_editButton->setEnabled(modifyEnabled); + m_deleteButton->setEnabled(modifyEnabled); + updateDescriptionLabel(); +} + +void EmbeddedOptionsControlPrivate::slotProfileIndexChanged(int) +{ + updateState(); + m_dirty = true; +} + +// ------------- EmbeddedOptionsControl +EmbeddedOptionsControl::EmbeddedOptionsControl(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_d(new EmbeddedOptionsControlPrivate(core)) +{ + m_d->init(this); +} + +EmbeddedOptionsControl::~EmbeddedOptionsControl() +{ + delete m_d; +} + +void EmbeddedOptionsControl::slotAdd() +{ + m_d->slotAdd(); +} + +void EmbeddedOptionsControl::slotEdit() +{ + m_d->slotEdit(); +} + +void EmbeddedOptionsControl::slotDelete() +{ + m_d->slotDelete(); +} + +void EmbeddedOptionsControl::loadSettings() +{ + m_d->loadSettings(); +} + +void EmbeddedOptionsControl::saveSettings() +{ + m_d->saveSettings(); +} + +void EmbeddedOptionsControl::slotProfileIndexChanged(int i) +{ + m_d->slotProfileIndexChanged(i); +} + +bool EmbeddedOptionsControl::isDirty() const +{ + return m_d->isDirty(); +} + +// EmbeddedOptionsPage: +EmbeddedOptionsPage::EmbeddedOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString EmbeddedOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("EmbeddedOptionsPage", "Embedded Design"); +} + +QWidget *EmbeddedOptionsPage::createPage(QWidget *parent) +{ + QWidget *optionsWidget = new QWidget(parent); + + QVBoxLayout *optionsVLayout = new QVBoxLayout(); + + //: EmbeddedOptionsControl group box" + QGroupBox *gb = new QGroupBox(QCoreApplication::translate("EmbeddedOptionsPage", "Device Profiles")); + QVBoxLayout *gbVLayout = new QVBoxLayout(); + m_embeddedOptionsControl = new EmbeddedOptionsControl(m_core); + m_embeddedOptionsControl->loadSettings(); + gbVLayout->addWidget(m_embeddedOptionsControl); + gb->setLayout(gbVLayout); + optionsVLayout->addWidget(gb); + + optionsVLayout->addStretch(1); + + // Outer layout to give it horizontal stretch + QHBoxLayout *optionsHLayout = new QHBoxLayout(); + optionsHLayout->addLayout(optionsVLayout); + optionsHLayout->addStretch(1); + optionsWidget->setLayout(optionsHLayout); + return optionsWidget; +} + +void EmbeddedOptionsPage::apply() +{ + if (!m_embeddedOptionsControl || !m_embeddedOptionsControl->isDirty()) + return; + + m_embeddedOptionsControl->saveSettings(); + if (FormWindowManager *fw = qobject_cast<qdesigner_internal::FormWindowManager *>(m_core->formWindowManager())) + fw->deviceProfilesChanged(); +} + +void EmbeddedOptionsPage::finish() +{ +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/embeddedoptionspage.h b/tools/designer/src/components/formeditor/embeddedoptionspage.h new file mode 100644 index 0000000..6b76d38 --- /dev/null +++ b/tools/designer/src/components/formeditor/embeddedoptionspage.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EMBEDDEDOPTIONSPAGE_H +#define EMBEDDEDOPTIONSPAGE_H + +#include <QtDesigner/private/abstractoptionspage_p.h> +#include <QtCore/QPointer> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class EmbeddedOptionsControlPrivate; + +/* EmbeddedOptions Control. Presents the user with a list of embedded + * device profiles he can modify/add/delete. */ +class EmbeddedOptionsControl : public QWidget { + Q_DISABLE_COPY(EmbeddedOptionsControl) + Q_OBJECT +public: + explicit EmbeddedOptionsControl(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~EmbeddedOptionsControl(); + + bool isDirty() const; + +public slots: + void loadSettings(); + void saveSettings(); + +private slots: + void slotAdd(); + void slotEdit(); + void slotDelete(); + void slotProfileIndexChanged(int); + +private: + EmbeddedOptionsControlPrivate *m_d; +}; + +// EmbeddedOptionsPage +class EmbeddedOptionsPage : public QDesignerOptionsPageInterface +{ + Q_DISABLE_COPY(EmbeddedOptionsPage) +public: + explicit EmbeddedOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void finish(); + virtual void apply(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer<EmbeddedOptionsControl> m_embeddedOptionsControl; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // EMBEDDEDOPTIONSPAGE_H diff --git a/tools/designer/src/components/formeditor/formeditor.cpp b/tools/designer/src/components/formeditor/formeditor.cpp new file mode 100644 index 0000000..b09ffab --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formeditor.h" +#include "formeditor_optionspage.h" +#include "embeddedoptionspage.h" +#include "templateoptionspage.h" +#include "metadatabase_p.h" +#include "widgetdatabase_p.h" +#include "widgetfactory_p.h" +#include "formwindowmanager.h" +#include "qmainwindow_container.h" +#include "qworkspace_container.h" +#include "qmdiarea_container.h" +#include "qwizard_container.h" +#include "default_container.h" +#include "default_layoutdecoration.h" +#include "default_actionprovider.h" +#include "qlayoutwidget_propertysheet.h" +#include "spacer_propertysheet.h" +#include "line_propertysheet.h" +#include "layout_propertysheet.h" +#include "qdesigner_stackedbox_p.h" +#include "qdesigner_toolbox_p.h" +#include "qdesigner_tabwidget_p.h" +#include "qtbrushmanager.h" +#include "brushmanagerproxy.h" +#include "iconcache.h" +#include "qtresourcemodel_p.h" +#include "qdesigner_integration_p.h" +#include "itemview_propertysheet.h" + +// sdk +#include <QtDesigner/QExtensionManager> + +// shared +#include <pluginmanager_p.h> +#include <qdesigner_taskmenu_p.h> +#include <qdesigner_membersheet_p.h> +#include <qdesigner_promotion_p.h> +#include <dialoggui_p.h> +#include <qdesigner_introspection_p.h> +#include <qdesigner_qsettings_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +FormEditor::FormEditor(QObject *parent) + : QDesignerFormEditorInterface(parent) +{ + setIntrospection(new QDesignerIntrospection); + setDialogGui(new DialogGui); + QDesignerPluginManager *pluginManager = new QDesignerPluginManager(this); + setPluginManager(pluginManager); + + WidgetDataBase *widgetDatabase = new WidgetDataBase(this, this); + setWidgetDataBase(widgetDatabase); + + MetaDataBase *metaDataBase = new MetaDataBase(this, this); + setMetaDataBase(metaDataBase); + + WidgetFactory *widgetFactory = new WidgetFactory(this, this); + setWidgetFactory(widgetFactory); + + FormWindowManager *formWindowManager = new FormWindowManager(this, this); + setFormManager(formWindowManager); + connect(formWindowManager, SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), widgetFactory, SLOT(formWindowAdded(QDesignerFormWindowInterface*))); + connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), widgetFactory, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); + + QExtensionManager *mgr = new QExtensionManager(this); + const QString containerExtensionId = Q_TYPEID(QDesignerContainerExtension); + + QDesignerStackedWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QDesignerTabWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QDesignerToolBoxContainerFactory::registerExtension(mgr, containerExtensionId); + QMainWindowContainerFactory::registerExtension(mgr, containerExtensionId); + QDockWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QScrollAreaContainerFactory::registerExtension(mgr, containerExtensionId); + QWorkspaceContainerFactory::registerExtension(mgr, containerExtensionId); + QMdiAreaContainerFactory::registerExtension(mgr, containerExtensionId); + QWizardContainerFactory::registerExtension(mgr, containerExtensionId); + + mgr->registerExtensions(new QDesignerLayoutDecorationFactory(mgr), + Q_TYPEID(QDesignerLayoutDecorationExtension)); + + const QString actionProviderExtensionId = Q_TYPEID(QDesignerActionProviderExtension); + QToolBarActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + QMenuBarActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + QMenuActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + + QDesignerDefaultPropertySheetFactory::registerExtension(mgr); + QLayoutWidgetPropertySheetFactory::registerExtension(mgr); + SpacerPropertySheetFactory::registerExtension(mgr); + LinePropertySheetFactory::registerExtension(mgr); + LayoutPropertySheetFactory::registerExtension(mgr); + QStackedWidgetPropertySheetFactory::registerExtension(mgr); + QToolBoxWidgetPropertySheetFactory::registerExtension(mgr); + QTabWidgetPropertySheetFactory::registerExtension(mgr); + QMdiAreaPropertySheetFactory::registerExtension(mgr); + QWorkspacePropertySheetFactory::registerExtension(mgr); + QWizardPagePropertySheetFactory::registerExtension(mgr); + QWizardPropertySheetFactory::registerExtension(mgr); + + QTreeViewPropertySheetFactory::registerExtension(mgr); + QTableViewPropertySheetFactory::registerExtension(mgr); + + const QString internalTaskMenuId = QLatin1String("QDesignerInternalTaskMenuExtension"); + QDesignerTaskMenuFactory::registerExtension(mgr, internalTaskMenuId); + + mgr->registerExtensions(new QDesignerMemberSheetFactory(mgr), + Q_TYPEID(QDesignerMemberSheetExtension)); + + setExtensionManager(mgr); + + setIconCache(new IconCache(this)); + + QtBrushManager *brushManager = new QtBrushManager(this); + setBrushManager(brushManager); + + BrushManagerProxy *brushProxy = new BrushManagerProxy(this, this); + brushProxy->setBrushManager(brushManager); + setPromotion(new QDesignerPromotion(this)); + + QtResourceModel *resourceModel = new QtResourceModel(this); + setResourceModel(resourceModel); + connect(resourceModel, SIGNAL(qrcFileModifiedExternally(const QString &)), + this, SLOT(slotQrcFileChangedExternally(const QString &))); + + QList<QDesignerOptionsPageInterface*> optionsPages; + optionsPages << new TemplateOptionsPage(this) << new FormEditorOptionsPage(this) << new EmbeddedOptionsPage(this); + setOptionsPages(optionsPages); + + setSettingsManager(new QDesignerQSettings()); +} + +FormEditor::~FormEditor() +{ +} + +void FormEditor::slotQrcFileChangedExternally(const QString &path) +{ + QDesignerIntegration *designerIntegration = qobject_cast<QDesignerIntegration *>(integration()); + if (!designerIntegration) + return; + + QDesignerIntegration::ResourceFileWatcherBehaviour behaviour = designerIntegration->resourceFileWatcherBehaviour(); + if (behaviour == QDesignerIntegration::NoWatcher) { + return; + } else if (behaviour == QDesignerIntegration::PromptAndReload) { + QMessageBox::StandardButton button = dialogGui()->message(topLevel(), QDesignerDialogGuiInterface::FileChangedMessage, QMessageBox::Warning, + tr("Resource File Changed"), + tr("The file \"%1\" has changed outside Designer. Do you want to reload it?").arg(path), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + if (button != QMessageBox::Yes) + return; + } + + resourceModel()->reload(path); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formeditor.h b/tools/designer/src/components/formeditor/formeditor.h new file mode 100644 index 0000000..2e0b819 --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_H +#define FORMEDITOR_H + +#include "formeditor_global.h" + +#include <QtDesigner/QDesignerFormEditorInterface> + +QT_BEGIN_NAMESPACE + +class QObject; + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormEditor: public QDesignerFormEditorInterface +{ + Q_OBJECT +public: + FormEditor(QObject *parent = 0); + virtual ~FormEditor(); +public slots: + void slotQrcFileChangedExternally(const QString &path); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMEDITOR_H diff --git a/tools/designer/src/components/formeditor/formeditor.pri b/tools/designer/src/components/formeditor/formeditor.pri new file mode 100644 index 0000000..bbe96d5 --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor.pri @@ -0,0 +1,75 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +FORMS += $$PWD/deviceprofiledialog.ui \ + $$PWD/formwindowsettings.ui \ + $$PWD/templateoptionspage.ui + +HEADERS += $$PWD/qdesigner_resource.h \ + $$PWD/formwindow.h \ + $$PWD/formwindow_widgetstack.h \ + $$PWD/formwindow_dnditem.h \ + $$PWD/formwindowcursor.h \ + $$PWD/widgetselection.h \ + $$PWD/formwindowmanager.h \ + $$PWD/formeditor.h \ + $$PWD/formeditor_global.h \ + $$PWD/qlayoutwidget_propertysheet.h \ + $$PWD/layout_propertysheet.h \ + $$PWD/spacer_propertysheet.h \ + $$PWD/line_propertysheet.h \ + $$PWD/default_container.h \ + $$PWD/default_actionprovider.h \ + $$PWD/qmainwindow_container.h \ + $$PWD/qworkspace_container.h \ + $$PWD/qmdiarea_container.h \ + $$PWD/qwizard_container.h \ + $$PWD/default_layoutdecoration.h \ + $$PWD/qtbrushmanager.h \ + $$PWD/brushmanagerproxy.h \ + $$PWD/iconcache.h \ + $$PWD/tool_widgeteditor.h \ + $$PWD/formeditor_optionspage.h \ + $$PWD/embeddedoptionspage.h \ + $$PWD/formwindowsettings.h \ + $$PWD/deviceprofiledialog.h \ + $$PWD/dpi_chooser.h \ + $$PWD/previewactiongroup.h \ + $$PWD/itemview_propertysheet.h \ + $$PWD/templateoptionspage.h + +SOURCES += $$PWD/qdesigner_resource.cpp \ + $$PWD/formwindow.cpp \ + $$PWD/formwindow_widgetstack.cpp \ + $$PWD/formwindow_dnditem.cpp \ + $$PWD/formwindowcursor.cpp \ + $$PWD/widgetselection.cpp \ + $$PWD/formwindowmanager.cpp \ + $$PWD/formeditor.cpp \ + $$PWD/qlayoutwidget_propertysheet.cpp \ + $$PWD/layout_propertysheet.cpp \ + $$PWD/spacer_propertysheet.cpp \ + $$PWD/line_propertysheet.cpp \ + $$PWD/qmainwindow_container.cpp \ + $$PWD/qworkspace_container.cpp \ + $$PWD/qmdiarea_container.cpp \ + $$PWD/qwizard_container.cpp \ + $$PWD/default_container.cpp \ + $$PWD/default_layoutdecoration.cpp \ + $$PWD/default_actionprovider.cpp \ + $$PWD/tool_widgeteditor.cpp \ + $$PWD/qtbrushmanager.cpp \ + $$PWD/brushmanagerproxy.cpp \ + $$PWD/iconcache.cpp \ + $$PWD/formeditor_optionspage.cpp \ + $$PWD/embeddedoptionspage.cpp \ + $$PWD/formwindowsettings.cpp \ + $$PWD/deviceprofiledialog.cpp \ + $$PWD/dpi_chooser.cpp \ + $$PWD/previewactiongroup.cpp \ + $$PWD/itemview_propertysheet.cpp \ + $$PWD/templateoptionspage.cpp + +RESOURCES += $$PWD/formeditor.qrc diff --git a/tools/designer/src/components/formeditor/formeditor.qrc b/tools/designer/src/components/formeditor/formeditor.qrc new file mode 100644 index 0000000..83cc9c7 --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor.qrc @@ -0,0 +1,173 @@ +<RCC> + <qresource prefix="/trolltech/formeditor"> + <file>images/submenu.png</file> + <file>images/cursors/arrow.png</file> + <file>images/cursors/busy.png</file> + <file>images/cursors/closedhand.png</file> + <file>images/cursors/cross.png</file> + <file>images/cursors/hand.png</file> + <file>images/cursors/hsplit.png</file> + <file>images/cursors/ibeam.png</file> + <file>images/cursors/no.png</file> + <file>images/cursors/openhand.png</file> + <file>images/cursors/sizeall.png</file> + <file>images/cursors/sizeb.png</file> + <file>images/cursors/sizef.png</file> + <file>images/cursors/sizeh.png</file> + <file>images/cursors/sizev.png</file> + <file>images/cursors/uparrow.png</file> + <file>images/cursors/vsplit.png</file> + <file>images/cursors/wait.png</file> + <file>images/cursors/whatsthis.png</file> + <file>images/emptyicon.png</file> + <file>images/filenew-16.png</file> + <file>images/fileopen-16.png</file> + <file>images/editdelete-16.png</file> + <file>images/plus-16.png</file> + <file>images/minus-16.png</file> + <file>images/prefix-add.png</file> + <file>images/downplus.png</file> + <file>images/leveldown.png</file> + <file>images/levelup.png</file> + <file>images/mac/adjustsize.png</file> + <file>images/mac/widgettool.png</file> + <file>images/mac/signalslottool.png</file> + <file>images/mac/tabordertool.png</file> + <file>images/mac/buddytool.png</file> + <file>images/mac/editbreaklayout.png</file> + <file>images/mac/editcopy.png</file> + <file>images/mac/editcut.png</file> + <file>images/mac/editdelete.png</file> + <file>images/mac/editgrid.png</file> + <file>images/mac/editform.png</file> + <file>images/mac/edithlayout.png</file> + <file>images/mac/edithlayoutsplit.png</file> + <file>images/mac/editlower.png</file> + <file>images/mac/editpaste.png</file> + <file>images/mac/editraise.png</file> + <file>images/mac/editvlayout.png</file> + <file>images/mac/editvlayoutsplit.png</file> + <file>images/mac/filenew.png</file> + <file>images/mac/insertimage.png</file> + <file>images/mac/undo.png</file> + <file>images/mac/redo.png</file> + <file>images/mac/fileopen.png</file> + <file>images/mac/filesave.png</file> + <file>images/mac/resourceeditortool.png</file> + <file>images/mac/plus.png</file> + <file>images/mac/minus.png</file> + <file>images/mac/back.png</file> + <file>images/mac/forward.png</file> + <file>images/mac/down.png</file> + <file>images/mac/up.png</file> + <file>images/qtlogo.png</file> + <file>images/qt3logo.png</file> + <file>images/resetproperty.png</file> + <file>images/sort.png</file> + <file>images/edit.png</file> + <file>images/reload.png</file> + <file>images/configure.png</file> + <file>images/color.png</file> + <file>images/dropdownbutton.png</file> + <file>images/widgets/calendarwidget.png</file> + <file>images/widgets/checkbox.png</file> + <file>images/widgets/columnview.png</file> + <file>images/widgets/combobox.png</file> + <file>images/widgets/commandlinkbutton.png</file> + <file>images/widgets/dateedit.png</file> + <file>images/widgets/datetimeedit.png</file> + <file>images/widgets/dial.png</file> + <file>images/widgets/dialogbuttonbox.png</file> + <file>images/widgets/dockwidget.png</file> + <file>images/widgets/doublespinbox.png</file> + <file>images/widgets/fontcombobox.png</file> + <file>images/widgets/frame.png</file> + <file>images/widgets/graphicsview.png</file> + <file>images/widgets/groupbox.png</file> + <file>images/widgets/hscrollbar.png</file> + <file>images/widgets/hslider.png</file> + <file>images/widgets/hsplit.png</file> + <file>images/widgets/label.png</file> + <file>images/widgets/lcdnumber.png</file> + <file>images/widgets/line.png</file> + <file>images/widgets/lineedit.png</file> + <file>images/widgets/listbox.png</file> + <file>images/widgets/listview.png</file> + <file>images/widgets/mdiarea.png</file> + <file>images/widgets/plaintextedit.png</file> + <file>images/widgets/progress.png</file> + <file>images/widgets/pushbutton.png</file> + <file>images/widgets/radiobutton.png</file> + <file>images/widgets/scrollarea.png</file> + <file>images/widgets/spacer.png</file> + <file>images/widgets/spinbox.png</file> + <file>images/widgets/table.png</file> + <file>images/widgets/tabwidget.png</file> + <file>images/widgets/textedit.png</file> + <file>images/widgets/timeedit.png</file> + <file>images/widgets/toolbox.png</file> + <file>images/widgets/toolbutton.png</file> + <file>images/widgets/vline.png</file> + <file>images/widgets/vscrollbar.png</file> + <file>images/widgets/vslider.png</file> + <file>images/widgets/vspacer.png</file> + <file>images/widgets/widget.png</file> + <file>images/widgets/widget.png</file> + <file>images/widgets/widgetstack.png</file> + <file>images/widgets/wizard.png</file> + <file>images/win/adjustsize.png</file> + <file>images/win/widgettool.png</file> + <file>images/win/signalslottool.png</file> + <file>images/win/tabordertool.png</file> + <file>images/win/buddytool.png</file> + <file>images/win/editbreaklayout.png</file> + <file>images/win/editcopy.png</file> + <file>images/win/editcut.png</file> + <file>images/win/editdelete.png</file> + <file>images/win/editgrid.png</file> + <file>images/win/editform.png</file> + <file>images/win/edithlayout.png</file> + <file>images/win/edithlayoutsplit.png</file> + <file>images/win/editlower.png</file> + <file>images/win/editpaste.png</file> + <file>images/win/editraise.png</file> + <file>images/win/editvlayout.png</file> + <file>images/win/editvlayoutsplit.png</file> + <file>images/win/filenew.png</file> + <file>images/win/insertimage.png</file> + <file>images/win/undo.png</file> + <file>images/win/redo.png</file> + <file>images/win/fileopen.png</file> + <file>images/win/filesave.png</file> + <file>images/win/resourceeditortool.png</file> + <file>images/win/plus.png</file> + <file>images/win/minus.png</file> + <file>images/win/textanchor.png</file> + <file>images/win/textbold.png</file> + <file>images/win/textitalic.png</file> + <file>images/win/textunder.png</file> + <file>images/win/textleft.png</file> + <file>images/win/textcenter.png</file> + <file>images/win/textright.png</file> + <file>images/win/textjustify.png</file> + <file>images/win/textsuperscript.png</file> + <file>images/win/textsubscript.png</file> + <file>images/win/back.png</file> + <file>images/win/forward.png</file> + <file>images/win/down.png</file> + <file>images/win/up.png</file> + <file>images/mac/textanchor.png</file> + <file>images/mac/textbold.png</file> + <file>images/mac/textitalic.png</file> + <file>images/mac/textunder.png</file> + <file>images/mac/textleft.png</file> + <file>images/mac/textcenter.png</file> + <file>images/mac/textright.png</file> + <file>images/mac/textjustify.png</file> + <file>images/mac/textsuperscript.png</file> + <file>images/mac/textsubscript.png</file> + </qresource> + <qresource prefix="/trolltech/brushes"> + <file>defaultbrushes.xml</file> + </qresource> +</RCC> diff --git a/tools/designer/src/components/formeditor/formeditor_global.h b/tools/designer/src/components/formeditor/formeditor_global.h new file mode 100644 index 0000000..0195f1b --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_GLOBAL_H +#define FORMEDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_FORMEDITOR_LIBRARY +# define QT_FORMEDITOR_EXPORT +#else +# define QT_FORMEDITOR_EXPORT +#endif +#else +#define QT_FORMEDITOR_EXPORT +#endif + +#endif // FORMEDITOR_GLOBAL_H diff --git a/tools/designer/src/components/formeditor/formeditor_optionspage.cpp b/tools/designer/src/components/formeditor/formeditor_optionspage.cpp new file mode 100644 index 0000000..0b20531 --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor_optionspage.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formeditor_optionspage.h" + +// shared +#include "formwindowbase_p.h" +#include "gridpanel_p.h" +#include "grid_p.h" +#include "previewconfigurationwidget_p.h" +#include "shared_settings_p.h" +#include "zoomwidget_p.h" + +// SDK +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtCore/QString> +#include <QtCore/QCoreApplication> +#include <QtGui/QGroupBox> +#include <QtGui/QVBoxLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QComboBox> + +QT_BEGIN_NAMESPACE + +typedef QList<int> IntList; + +namespace qdesigner_internal { + +// Zoom, currently for preview only +class ZoomSettingsWidget : public QGroupBox { + Q_DISABLE_COPY(ZoomSettingsWidget) +public: + explicit ZoomSettingsWidget(QWidget *parent = 0); + + void fromSettings(const QDesignerSharedSettings &s); + void toSettings(QDesignerSharedSettings &s) const; + +private: + QComboBox *m_zoomCombo; +}; + +ZoomSettingsWidget::ZoomSettingsWidget(QWidget *parent) : + QGroupBox(parent), + m_zoomCombo(new QComboBox) +{ + m_zoomCombo->setEditable(false); + const IntList zoomValues = ZoomMenu::zoomValues(); + const IntList::const_iterator cend = zoomValues.constEnd(); + //: Zoom percentage + for (IntList::const_iterator it = zoomValues.constBegin(); it != cend; ++it) + m_zoomCombo->addItem(QCoreApplication::translate("FormEditorOptionsPage", "%1 %").arg(*it), QVariant(*it)); + + // Layout + setCheckable(true); + setTitle(QCoreApplication::translate("FormEditorOptionsPage", "Preview Zoom")); + QFormLayout *lt = new QFormLayout; + lt->addRow(QCoreApplication::translate("FormEditorOptionsPage", "Default Zoom"), m_zoomCombo); + setLayout(lt); +} + +void ZoomSettingsWidget::fromSettings(const QDesignerSharedSettings &s) +{ + setChecked(s.zoomEnabled()); + const int idx = m_zoomCombo->findData(QVariant(s.zoom())); + m_zoomCombo->setCurrentIndex(qMax(0, idx)); +} + +void ZoomSettingsWidget::toSettings(QDesignerSharedSettings &s) const +{ + s.setZoomEnabled(isChecked()); + const int zoom = m_zoomCombo->itemData(m_zoomCombo->currentIndex()).toInt(); + s.setZoom(zoom); +} + + + +// FormEditorOptionsPage: +FormEditorOptionsPage::FormEditorOptionsPage(QDesignerFormEditorInterface *core) + : m_core(core) +{ +} + +QString FormEditorOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("FormEditorOptionsPage", "Forms"); +} + +QWidget *FormEditorOptionsPage::createPage(QWidget *parent) +{ + QWidget *optionsWidget = new QWidget(parent); + + const QDesignerSharedSettings settings(m_core); + m_previewConf = new PreviewConfigurationWidget(m_core); + m_zoomSettingsWidget = new ZoomSettingsWidget; + m_zoomSettingsWidget->fromSettings(settings); + + m_defaultGridConf = new GridPanel(); + m_defaultGridConf->setTitle(QCoreApplication::translate("FormEditorOptionsPage", "Default Grid")); + m_defaultGridConf->setGrid(settings.defaultGrid()); + + QVBoxLayout *optionsVLayout = new QVBoxLayout(); + optionsVLayout->addWidget(m_defaultGridConf); + optionsVLayout->addWidget(m_previewConf); + optionsVLayout->addWidget(m_zoomSettingsWidget); + optionsVLayout->addStretch(1); + + // Outer layout to give it horizontal stretch + QHBoxLayout *optionsHLayout = new QHBoxLayout(); + optionsHLayout->addLayout(optionsVLayout); + optionsHLayout->addStretch(1); + optionsWidget->setLayout(optionsHLayout); + + return optionsWidget; +} + +void FormEditorOptionsPage::apply() +{ + QDesignerSharedSettings settings(m_core); + if (m_defaultGridConf) { + const Grid defaultGrid = m_defaultGridConf->grid(); + settings.setDefaultGrid(defaultGrid); + + FormWindowBase::setDefaultDesignerGrid(defaultGrid); + // Update grid settings in all existing form windows + QDesignerFormWindowManagerInterface *fwm = m_core->formWindowManager(); + if (const int numWindows = fwm->formWindowCount()) { + for (int i = 0; i < numWindows; i++) + if (qdesigner_internal::FormWindowBase *fwb + = qobject_cast<qdesigner_internal::FormWindowBase *>( fwm->formWindow(i))) + if (!fwb->hasFormGrid()) + fwb->setDesignerGrid(defaultGrid); + } + } + if (m_previewConf) { + m_previewConf->saveState(); + } + + if (m_zoomSettingsWidget) + m_zoomSettingsWidget->toSettings(settings); +} + +void FormEditorOptionsPage::finish() +{ +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formeditor_optionspage.h b/tools/designer/src/components/formeditor/formeditor_optionspage.h new file mode 100644 index 0000000..4aeda6a --- /dev/null +++ b/tools/designer/src/components/formeditor/formeditor_optionspage.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_OPTIONSPAGE_H +#define FORMEDITOR_OPTIONSPAGE_H + +#include <QtDesigner/private/abstractoptionspage_p.h> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class PreviewConfigurationWidget; +class GridPanel; +class ZoomSettingsWidget; + +class FormEditorOptionsPage : public QDesignerOptionsPageInterface +{ +public: + explicit FormEditorOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer<PreviewConfigurationWidget> m_previewConf; + QPointer<GridPanel> m_defaultGridConf; + QPointer<ZoomSettingsWidget> m_zoomSettingsWidget; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMEDITOR_OPTIONSPAGE_H diff --git a/tools/designer/src/components/formeditor/formwindow.cpp b/tools/designer/src/components/formeditor/formwindow.cpp new file mode 100644 index 0000000..48efcde --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow.cpp @@ -0,0 +1,2921 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::FormWindow +*/ + +#include "formwindow.h" +#include "formeditor.h" +#include "formwindow_dnditem.h" +#include "formwindow_widgetstack.h" +#include "formwindowcursor.h" +#include "formwindowmanager.h" +#include "tool_widgeteditor.h" +#include "widgetselection.h" +#include "qtresourcemodel_p.h" +#include "widgetfactory_p.h" + +// shared +#include <metadatabase_p.h> +#include <qdesigner_tabwidget_p.h> +#include <qdesigner_toolbox_p.h> +#include <qdesigner_stackedbox_p.h> +#include <qdesigner_resource.h> +#include <qdesigner_command_p.h> +#include <qdesigner_command2_p.h> +#include <qdesigner_propertycommand_p.h> +#include <qdesigner_taskmenu_p.h> +#include <qdesigner_widget_p.h> +#include <qdesigner_utils_p.h> +#include <qlayout_widget_p.h> +#include <spacer_widget_p.h> +#include <invisible_widget_p.h> +#include <layoutinfo_p.h> +#include <qdesigner_objectinspector_p.h> +#include <connectionedit_p.h> +#include <actionprovider_p.h> +#include <ui4_p.h> +#include <deviceprofile_p.h> +#include <shared_settings_p.h> +#include <grid_p.h> + +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> +#include <QtDesigner/QDesignerPropertySheetExtension> +#include <QtDesigner/QDesignerWidgetFactoryInterface> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerTaskMenuExtension> +#include <QtDesigner/QDesignerWidgetBoxInterface> +#include <abstractdialoggui_p.h> + +#include <QtCore/QtDebug> +#include <QtCore/QBuffer> +#include <QtCore/QTimer> +#include <QtCore/QXmlStreamReader> +#include <QtGui/QMenu> +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QClipboard> +#include <QtGui/QUndoGroup> +#include <QtGui/QScrollArea> +#include <QtGui/QRubberBand> +#include <QtGui/QApplication> +#include <QtGui/QSplitter> +#include <QtGui/QPainter> +#include <QtGui/QGroupBox> +#include <QtGui/QDockWidget> +#include <QtGui/QToolBox> +#include <QtGui/QStackedWidget> +#include <QtGui/QTabWidget> +#include <QtGui/QButtonGroup> + +Q_DECLARE_METATYPE(QWidget*) + +QT_BEGIN_NAMESPACE + +namespace { +class BlockSelection +{ +public: + BlockSelection(qdesigner_internal::FormWindow *fw) + : m_formWindow(fw), + m_blocked(m_formWindow->blockSelectionChanged(true)) + { + } + + ~BlockSelection() + { + if (m_formWindow) + m_formWindow->blockSelectionChanged(m_blocked); + } + +private: + QPointer<qdesigner_internal::FormWindow> m_formWindow; + const bool m_blocked; +}; + +enum { debugFormWindow = 0 }; +} + +namespace qdesigner_internal { + +// ------------------------ FormWindow::Selection +// Maintains a pool of WidgetSelections to be used for selected widgets. + +class FormWindow::Selection +{ +public: + Selection(); + ~Selection(); + + // Clear + void clear(); + + // Also clear out the pool. Call if reparenting of the main container occurs. + void clearSelectionPool(); + + void repaintSelection(QWidget *w); + void repaintSelection(); + + bool isWidgetSelected(QWidget *w) const; + QWidgetList selectedWidgets() const; + + WidgetSelection *addWidget(FormWindow* fw, QWidget *w); + // remove widget, return new current widget or 0 + QWidget* removeWidget(QWidget *w); + + void raiseList(const QWidgetList& l); + void raiseWidget(QWidget *w); + + void updateGeometry(QWidget *w); + + void hide(QWidget *w); + void show(QWidget *w); + +private: + + typedef QList<WidgetSelection *> SelectionPool; + SelectionPool m_selectionPool; + + typedef QHash<QWidget *, WidgetSelection *> SelectionHash; + SelectionHash m_usedSelections; +}; + +FormWindow::Selection::Selection() +{ +} + +FormWindow::Selection::~Selection() +{ + clearSelectionPool(); +} + +void FormWindow::Selection::clear() +{ + if (!m_usedSelections.empty()) { + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + it.value()->setWidget(0); + } + m_usedSelections.clear(); + } +} + +void FormWindow::Selection::clearSelectionPool() +{ + clear(); + qDeleteAll(m_selectionPool); + m_selectionPool.clear(); +} + +WidgetSelection *FormWindow::Selection::addWidget(FormWindow* fw, QWidget *w) +{ + WidgetSelection *rc = m_usedSelections.value(w); + if (rc != 0) { + rc->show(); + rc->updateActive(); + return rc; + } + // find a free one in the pool + const SelectionPool::iterator pend = m_selectionPool.end(); + for (SelectionPool::iterator it = m_selectionPool.begin(); it != pend; ++it) { + if (! (*it)->isUsed()) { + rc = *it; + break; + } + } + + if (rc == 0) { + rc = new WidgetSelection(fw); + m_selectionPool.push_back(rc); + } + + m_usedSelections.insert(w, rc); + rc->setWidget(w); + return rc; +} + +QWidget* FormWindow::Selection::removeWidget(QWidget *w) +{ + WidgetSelection *s = m_usedSelections.value(w); + if (!s) + return w; + + s->setWidget(0); + m_usedSelections.remove(w); + + if (m_usedSelections.isEmpty()) + return 0; + + return (*m_usedSelections.begin())->widget(); +} + +void FormWindow::Selection::repaintSelection(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->update(); +} + +void FormWindow::Selection::repaintSelection() +{ + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + it.value()->update(); + } +} + +bool FormWindow::Selection::isWidgetSelected(QWidget *w) const{ + return m_usedSelections.contains(w); +} + +QWidgetList FormWindow::Selection::selectedWidgets() const +{ + return m_usedSelections.keys(); +} + +void FormWindow::Selection::raiseList(const QWidgetList& l) +{ + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + WidgetSelection *w = it.value(); + if (l.contains(w->widget())) + w->show(); + } +} + +void FormWindow::Selection::raiseWidget(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->show(); +} + +void FormWindow::Selection::updateGeometry(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) { + s->updateGeometry(); + } +} + +void FormWindow::Selection::hide(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->hide(); +} + +void FormWindow::Selection::show(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->show(); +} + +// ------------------------ FormWindow +FormWindow::FormWindow(FormEditor *core, QWidget *parent, Qt::WindowFlags flags) : + FormWindowBase(core, parent, flags), + m_mouseState(NoMouseState), + m_core(core), + m_selection(new Selection), + m_widgetStack(new FormWindowWidgetStack(this)), + m_contextMenuPosition(-1, -1) +{ + // Apply settings to formcontainer + deviceProfile().apply(core, m_widgetStack->formContainer(), qdesigner_internal::DeviceProfile::ApplyFormParent); + + setLayout(m_widgetStack->layout()); + init(); + + m_cursor = new FormWindowCursor(this, this); + + core->formWindowManager()->addFormWindow(this); + + setDirty(false); + setAcceptDrops(true); +} + +FormWindow::~FormWindow() +{ + Q_ASSERT(core() != 0); + Q_ASSERT(core()->metaDataBase() != 0); + Q_ASSERT(core()->formWindowManager() != 0); + + core()->formWindowManager()->removeFormWindow(this); + core()->metaDataBase()->remove(this); + + QWidgetList l = widgets(); + foreach (QWidget *w, l) + core()->metaDataBase()->remove(w); + + m_widgetStack = 0; + m_rubberBand = 0; + if (resourceSet()) + core()->resourceModel()->removeResourceSet(resourceSet()); + delete m_selection; +} + +QDesignerFormEditorInterface *FormWindow::core() const +{ + return m_core; +} + +QDesignerFormWindowCursorInterface *FormWindow::cursor() const +{ + return m_cursor; +} + +void FormWindow::updateWidgets() +{ + if (!m_mainContainer) + return; +} + +int FormWindow::widgetDepth(const QWidget *w) +{ + int d = -1; + while (w && !w->isWindow()) { + d++; + w = w->parentWidget(); + } + + return d; +} + +bool FormWindow::isChildOf(const QWidget *c, const QWidget *p) +{ + while (c) { + if (c == p) + return true; + c = c->parentWidget(); + } + return false; +} + +void FormWindow::setCursorToAll(const QCursor &c, QWidget *start) +{ +#ifndef QT_NO_CURSOR + start->setCursor(c); + const QWidgetList widgets = qFindChildren<QWidget*>(start); + foreach (QWidget *widget, widgets) { + if (!qobject_cast<WidgetHandle*>(widget)) { + widget->setCursor(c); + } + } +#endif +} + +void FormWindow::init() +{ + if (FormWindowManager *manager = qobject_cast<FormWindowManager*> (core()->formWindowManager())) { + m_commandHistory = new QUndoStack(this); + manager->undoGroup()->addStack(m_commandHistory); + } + + m_blockSelectionChanged = false; + + m_defaultMargin = INT_MIN; + m_defaultSpacing = INT_MIN; + + connect(m_widgetStack, SIGNAL(currentToolChanged(int)), this, SIGNAL(toolChanged(int))); + + m_selectionChangedTimer = new QTimer(this); + m_selectionChangedTimer->setSingleShot(true); + connect(m_selectionChangedTimer, SIGNAL(timeout()), this, SLOT(selectionChangedTimerDone())); + + m_checkSelectionTimer = new QTimer(this); + m_checkSelectionTimer->setSingleShot(true); + connect(m_checkSelectionTimer, SIGNAL(timeout()), this, SLOT(checkSelectionNow())); + + m_geometryChangedTimer = new QTimer(this); + m_geometryChangedTimer->setSingleShot(true); + connect(m_geometryChangedTimer, SIGNAL(timeout()), this, SIGNAL(geometryChanged())); + + m_rubberBand = 0; + + setFocusPolicy(Qt::StrongFocus); + + m_mainContainer = 0; + m_currentWidget = 0; + + connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SLOT(updateDirty())); + connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SIGNAL(changed())); + connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SLOT(checkSelection())); + + core()->metaDataBase()->add(this); + + initializeCoreTools(); + + QAction *a = new QAction(this); + a->setText(tr("Edit contents")); + a->setShortcut(tr("F2")); + connect(a, SIGNAL(triggered()), this, SLOT(editContents())); + addAction(a); +} + +QWidget *FormWindow::mainContainer() const +{ + return m_mainContainer; +} + + +void FormWindow::clearMainContainer() +{ + if (m_mainContainer) { + setCurrentTool(0); + m_widgetStack->setMainContainer(0); + core()->metaDataBase()->remove(m_mainContainer); + unmanageWidget(m_mainContainer); + delete m_mainContainer; + m_mainContainer = 0; + } +} + +void FormWindow::setMainContainer(QWidget *w) +{ + if (w == m_mainContainer) { + // nothing to do + return; + } + + clearMainContainer(); + + m_mainContainer = w; + const QSize sz = m_mainContainer->size(); + + m_widgetStack->setMainContainer(m_mainContainer); + m_widgetStack->setCurrentTool(m_widgetEditor); + + setCurrentWidget(m_mainContainer); + manageWidget(m_mainContainer); + + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), m_mainContainer)) { + sheet->setVisible(sheet->indexOf(QLatin1String("windowTitle")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowIcon")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowModality")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowFilePath")), true); + // ### generalize + } + + m_mainContainer->setFocusPolicy(Qt::StrongFocus); + m_mainContainer->resize(sz); + + emit mainContainerChanged(m_mainContainer); +} + +QWidget *FormWindow::findTargetContainer(QWidget *widget) const +{ + Q_ASSERT(widget); + + while (QWidget *parentWidget = widget->parentWidget()) { + if (LayoutInfo::layoutType(m_core, parentWidget) == LayoutInfo::NoLayout && isManaged(widget)) + return widget; + + widget = parentWidget; + } + + return mainContainer(); +} + +static inline void clearObjectInspectorSelection(const QDesignerFormEditorInterface *core) +{ + if (QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(core->objectInspector())) + oi->clearSelection(); +} + +// Find a parent of a desired selection state +static QWidget *findSelectedParent(QDesignerFormWindowInterface *fw, const QWidget *w, bool selected) +{ + const QDesignerFormWindowCursorInterface *cursor = fw->cursor(); + QWidget *mainContainer = fw->mainContainer(); + for (QWidget *p = w->parentWidget(); p && p != mainContainer; p = p->parentWidget()) + if (fw->isManaged(p)) + if (cursor->isWidgetSelected(p) == selected) + return p; + return 0; +} + +// Mouse modifiers. + +enum MouseFlags { ToggleSelectionModifier = 0x1, CycleParentModifier=0x2, CopyDragModifier=0x4 }; + +static inline unsigned mouseFlags(Qt::KeyboardModifiers mod) +{ + switch (mod) { + case Qt::ShiftModifier: + return CycleParentModifier; + break; +#ifdef Q_WS_MAC + case Qt::AltModifier: // "Alt" or "option" key on Mac means copy + return CopyDragModifier; +#endif + case Qt::ControlModifier: + return CopyDragModifier|ToggleSelectionModifier; + break; + default: + break; + } + return 0; +} + +// Handle the click selection: Do toggling/cycling +// of parents according to the modifiers. +void FormWindow::handleClickSelection(QWidget *managedWidget, unsigned mouseMode) +{ + const bool sameWidget = managedWidget == m_lastClickedWidget; + m_lastClickedWidget = managedWidget; + + const bool selected = isWidgetSelected(managedWidget); + if (debugFormWindow) + qDebug() << "handleClickSelection" << managedWidget << " same=" << sameWidget << " mouse= " << mouseMode << " selected=" << selected; + + // // toggle selection state of widget + if (mouseMode & ToggleSelectionModifier) { + selectWidget(managedWidget, !selected); + return; + } + + QWidget *selectionCandidate = 0; + // Hierarchy cycling: If the same widget clicked again: Attempt to cycle + // trough the hierarchy. Find the next currently selected parent + if (sameWidget && (mouseMode & CycleParentModifier)) + if (QWidget *currentlySelectedParent = selected ? managedWidget : findSelectedParent(this, managedWidget, true)) + selectionCandidate = findSelectedParent(this, currentlySelectedParent, false); + // Not the same widget, list wrapped over or there was no unselected parent + if (!selectionCandidate && !selected) + selectionCandidate = managedWidget; + + if (selectionCandidate) + selectSingleWidget(selectionCandidate); +} + +void FormWindow::selectSingleWidget(QWidget *w) +{ + clearSelection(false); + selectWidget(w, true); + raiseChildSelections(w); +} + +bool FormWindow::handleMousePressEvent(QWidget * widget, QWidget *managedWidget, QMouseEvent *e) +{ + m_mouseState = NoMouseState; + m_startPos = QPoint(); + e->accept(); + + BlockSelection blocker(this); + + if (core()->formWindowManager()->activeFormWindow() != this) + core()->formWindowManager()->setActiveFormWindow(this); + + const Qt::MouseButtons buttons = e->buttons(); + if (buttons != Qt::LeftButton && buttons != Qt::MidButton) + return true; + + m_startPos = mapFromGlobal(e->globalPos()); + + if (debugFormWindow) + qDebug() << "handleMousePressEvent:" << widget << ',' << managedWidget; + + if (buttons == Qt::MidButton || isMainContainer(managedWidget) == true) { // press was on the formwindow + clearObjectInspectorSelection(m_core); // We might have a toolbar or non-widget selected in the object inspector. + clearSelection(false); + + m_mouseState = MouseDrawRubber; + m_currRect = QRect(); + startRectDraw(mapFromGlobal(e->globalPos()), this, Rubber); + return true; + } + if (buttons != Qt::LeftButton) + return true; + + const unsigned mouseMode = mouseFlags(e->modifiers()); + + /* Normally, we want to be able to click /select-on-press to drag away + * the widget in the next step. However, in the case of a widget which + * itself or whose parent is selected, we defer the selection to the + * release event. + * This is to prevent children from being dragged away from layouts + * when their layouts are selected and one wants to move the layout. + * Note that toggle selection is only deferred if the widget is already + * selected, so, it is still possible to just Ctrl+Click and CopyDrag. */ + const bool deferSelection = isWidgetSelected(managedWidget) || findSelectedParent(this, managedWidget, true); + if (deferSelection) { + m_mouseState = MouseDeferredSelection; + } else { + // Cycle the parent unless we explicitly want toggle + const unsigned effectiveMouseMode = (mouseMode & ToggleSelectionModifier) ? mouseMode : static_cast<unsigned>(CycleParentModifier); + handleClickSelection(managedWidget, effectiveMouseMode); + } + return true; +} + +// We can drag widget in managed layouts except splitter. +static bool canDragWidgetInLayout(const QDesignerFormEditorInterface *core, QWidget *w) +{ + bool managed; + const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core ,w, &managed); + if (!managed) + return false; + switch (type) { + case LayoutInfo::NoLayout: + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: + return false; + default: + break; + } + return true; +} + +bool FormWindow::handleMouseMoveEvent(QWidget *, QWidget *, QMouseEvent *e) +{ + e->accept(); + if (m_startPos.isNull()) + return true; + + const QPoint pos = mapFromGlobal(e->globalPos()); + + switch (m_mouseState) { + case MouseDrawRubber: // Rubber band with left/middle mouse + continueRectDraw(pos, this, Rubber); + return true; + case MouseMoveDrag: // Spurious move event after drag started? + return true; + default: + break; + } + + if (e->buttons() != Qt::LeftButton) + return true; + + const bool canStartDrag = (m_startPos - pos).manhattanLength() > QApplication::startDragDistance(); + + if (canStartDrag == false) { + // nothing to do + return true; + } + + m_mouseState = MouseMoveDrag; + const bool blocked = blockSelectionChanged(true); + + QWidgetList sel = selectedWidgets(); + simplifySelection(&sel); + + QSet<QWidget*> widget_set; + + foreach (QWidget *child, sel) { // Move parent layout or container? + QWidget *current = child; + + bool done = false; + while (!isMainContainer(current) && !done) { + if (!isManaged(current)) { + current = current->parentWidget(); + continue; + } else if (LayoutInfo::isWidgetLaidout(core(), current)) { + // Go up to parent of layout if shift pressed, else do that only for splitters + if (!canDragWidgetInLayout(core(), current)) { + current = current->parentWidget(); + continue; + } + } + done = true; + } + + if (current == mainContainer()) + continue; + + widget_set.insert(current); + } + + sel = widget_set.toList(); + QDesignerFormWindowCursorInterface *c = cursor(); + QWidget *current = c->current(); + if (sel.contains(current)) { + sel.removeAll(current); + sel.prepend(current); + } + + QList<QDesignerDnDItemInterface*> item_list; + const QPoint globalPos = mapToGlobal(m_startPos); + const QDesignerDnDItemInterface::DropType dropType = (mouseFlags(e->modifiers()) & CopyDragModifier) ? + QDesignerDnDItemInterface::CopyDrop : QDesignerDnDItemInterface::MoveDrop; + foreach (QWidget *widget, sel) { + item_list.append(new FormWindowDnDItem(dropType, this, widget, globalPos)); + if (dropType == QDesignerDnDItemInterface::MoveDrop) { + m_selection->hide(widget); + widget->hide(); + } + } + + blockSelectionChanged(blocked); + + if (!sel.empty()) // reshow selection? + if (QDesignerMimeData::execDrag(item_list, core()->topLevel()) == Qt::IgnoreAction && dropType == QDesignerDnDItemInterface::MoveDrop) + foreach (QWidget *widget, sel) + m_selection->show(widget); + + m_startPos = QPoint(); + + return true; +} + +bool FormWindow::handleMouseReleaseEvent(QWidget *w, QWidget *mw, QMouseEvent *e) +{ + const MouseState oldState = m_mouseState; + m_mouseState = NoMouseState; + + if (debugFormWindow) + qDebug() << "handleMouseeleaseEvent:" << w << ',' << mw << "state=" << oldState; + + if (oldState == MouseDoubleClicked) + return true; + + e->accept(); + + switch (oldState) { + case MouseDrawRubber: { // we were drawing a rubber selection + endRectDraw(); // get rid of the rectangle + const bool blocked = blockSelectionChanged(true); + selectWidgets(); // select widgets which intersect the rect + blockSelectionChanged(blocked); + } + break; + // Deferred select: Select the child here unless the parent was moved. + case MouseDeferredSelection: + handleClickSelection(mw, mouseFlags(e->modifiers())); + break; + default: + break; + } + + m_startPos = QPoint(); + + /* Inform about selection changes (left/mid or context menu). Also triggers + * in the case of an empty rubber drag that cleared the selection in + * MousePressEvent. */ + switch (e->button()) { + case Qt::LeftButton: + case Qt::MidButton: + case Qt::RightButton: + emitSelectionChanged(); + break; + default: + break; + } + + return true; +} + +void FormWindow::checkPreviewGeometry(QRect &r) +{ + if (!rect().contains(r)) { + if (r.left() < rect().left()) + r.moveTopLeft(QPoint(0, r.top())); + if (r.right() > rect().right()) + r.moveBottomRight(QPoint(rect().right(), r.bottom())); + if (r.top() < rect().top()) + r.moveTopLeft(QPoint(r.left(), rect().top())); + if (r.bottom() > rect().bottom()) + r.moveBottomRight(QPoint(r.right(), rect().bottom())); + } +} + +void FormWindow::startRectDraw(const QPoint &pos, QWidget *, RectType t) +{ + m_rectAnchor = (t == Insert) ? designerGrid().snapPoint(pos) : pos; + + m_currRect = QRect(m_rectAnchor, QSize(0, 0)); + if (!m_rubberBand) + m_rubberBand = new QRubberBand(QRubberBand::Rectangle, this); + m_rubberBand->setGeometry(m_currRect); + m_rubberBand->show(); +} + +void FormWindow::continueRectDraw(const QPoint &pos, QWidget *, RectType t) +{ + const QPoint p2 = (t == Insert) ? designerGrid().snapPoint(pos) : pos; + + QRect r(m_rectAnchor, p2); + r = r.normalized(); + + if (m_currRect == r) + return; + + if (r.width() > 1 || r.height() > 1) { + m_currRect = r; + if (m_rubberBand) + m_rubberBand->setGeometry(m_currRect); + } +} + +void FormWindow::endRectDraw() +{ + if (m_rubberBand) { + delete m_rubberBand; + m_rubberBand = 0; + } +} + +QWidget *FormWindow::currentWidget() const +{ + return m_currentWidget; +} + +bool FormWindow::setCurrentWidget(QWidget *currentWidget) +{ + if (debugFormWindow) + qDebug() << "setCurrentWidget:" << m_currentWidget << " --> " << currentWidget; + if (currentWidget == m_currentWidget) + return false; + // repaint the old widget unless it is the main window + if (m_currentWidget && m_currentWidget != mainContainer()) { + m_selection->repaintSelection(m_currentWidget); + } + // set new and repaint + m_currentWidget = currentWidget; + if (m_currentWidget && m_currentWidget != mainContainer()) { + m_selection->repaintSelection(m_currentWidget); + } + return true; +} + +void FormWindow::selectWidget(QWidget* w, bool select) +{ + if (trySelectWidget(w, select)) + emitSelectionChanged(); +} + +// Selects a widget and determines the new current one. Returns true if a change occurs. +bool FormWindow::trySelectWidget(QWidget *w, bool select) +{ + if (debugFormWindow) + qDebug() << "trySelectWidget:" << w << select; + if (!isManaged(w) && !isCentralWidget(w)) + return false; + + if (!select && !isWidgetSelected(w)) + return false; + + if (!mainContainer()) + return false; + + if (isMainContainer(w) || isCentralWidget(w)) { + setCurrentWidget(mainContainer()); + return true; + } + + if (select) { + setCurrentWidget(w); + m_selection->addWidget(this, w); + } else { + QWidget *newCurrent = m_selection->removeWidget(w); + if (!newCurrent) + newCurrent = mainContainer(); + setCurrentWidget(newCurrent); + } + return true; +} + +void FormWindow::clearSelection(bool changePropertyDisplay) +{ + if (debugFormWindow) + qDebug() << "clearSelection(" << changePropertyDisplay << ')'; + // At all events, we need a current widget. + m_selection->clear(); + setCurrentWidget(mainContainer()); + + if (changePropertyDisplay) + emitSelectionChanged(); +} + +void FormWindow::emitSelectionChanged() +{ + if (m_blockSelectionChanged == true) { + // nothing to do + return; + } + + m_selectionChangedTimer->start(0); +} + +void FormWindow::selectionChangedTimerDone() +{ + emit selectionChanged(); +} + +bool FormWindow::isWidgetSelected(QWidget *w) const +{ + return m_selection->isWidgetSelected(w); +} + +bool FormWindow::isMainContainer(const QWidget *w) const +{ + return w && (w == this || w == mainContainer()); +} + +void FormWindow::updateChildSelections(QWidget *w) +{ + const QWidgetList l = qFindChildren<QWidget*>(w); + if (!l.empty()) { + const QWidgetList::const_iterator lcend = l.constEnd(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) { + QWidget *w = *it; + if (isManaged(w)) + updateSelection(w); + } + } +} + +void FormWindow::repaintSelection() +{ + m_selection->repaintSelection(); +} + +void FormWindow::raiseSelection(QWidget *w) +{ + m_selection->raiseWidget(w); +} + +void FormWindow::updateSelection(QWidget *w) +{ + if (!w->isVisibleTo(this)) { + selectWidget(w, false); + } else { + m_selection->updateGeometry(w); + } +} + +QWidget *FormWindow::designerWidget(QWidget *w) const +{ + while ((w && !isMainContainer(w) && !isManaged(w)) || isCentralWidget(w)) + w = w->parentWidget(); + + return w; +} + +bool FormWindow::isCentralWidget(QWidget *w) const +{ + if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(mainContainer())) + return w == mainWindow->centralWidget(); + + return false; +} + +void FormWindow::ensureUniqueObjectName(QObject *object) +{ + QString name = object->objectName(); + if (name.isEmpty()) { + QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(object))) + name = qdesigner_internal::qtify(item->name()); + } + unify(object, name, true); + object->setObjectName(name); +} + +template <class Iterator> +static inline void insertNames(const QDesignerMetaDataBaseInterface *metaDataBase, + Iterator it, const Iterator &end, + QObject *excludedObject, QSet<QString> &nameSet) +{ + for ( ; it != end; ++it) + if (excludedObject != *it && metaDataBase->item(*it)) + nameSet.insert((*it)->objectName()); +} + +static QSet<QString> languageKeywords() +{ + static QSet<QString> keywords; + if (keywords.isEmpty()) { + // C++ keywords + keywords.insert(QLatin1String("asm")); + keywords.insert(QLatin1String("auto")); + keywords.insert(QLatin1String("bool")); + keywords.insert(QLatin1String("break")); + keywords.insert(QLatin1String("case")); + keywords.insert(QLatin1String("catch")); + keywords.insert(QLatin1String("char")); + keywords.insert(QLatin1String("class")); + keywords.insert(QLatin1String("const")); + keywords.insert(QLatin1String("const_cast")); + keywords.insert(QLatin1String("continue")); + keywords.insert(QLatin1String("default")); + keywords.insert(QLatin1String("delete")); + keywords.insert(QLatin1String("do")); + keywords.insert(QLatin1String("double")); + keywords.insert(QLatin1String("dynamic_cast")); + keywords.insert(QLatin1String("else")); + keywords.insert(QLatin1String("enum")); + keywords.insert(QLatin1String("explicit")); + keywords.insert(QLatin1String("export")); + keywords.insert(QLatin1String("extern")); + keywords.insert(QLatin1String("false")); + keywords.insert(QLatin1String("float")); + keywords.insert(QLatin1String("for")); + keywords.insert(QLatin1String("friend")); + keywords.insert(QLatin1String("goto")); + keywords.insert(QLatin1String("if")); + keywords.insert(QLatin1String("inline")); + keywords.insert(QLatin1String("int")); + keywords.insert(QLatin1String("long")); + keywords.insert(QLatin1String("mutable")); + keywords.insert(QLatin1String("namespace")); + keywords.insert(QLatin1String("new")); + keywords.insert(QLatin1String("NULL")); + keywords.insert(QLatin1String("operator")); + keywords.insert(QLatin1String("private")); + keywords.insert(QLatin1String("protected")); + keywords.insert(QLatin1String("public")); + keywords.insert(QLatin1String("register")); + keywords.insert(QLatin1String("reinterpret_cast")); + keywords.insert(QLatin1String("return")); + keywords.insert(QLatin1String("short")); + keywords.insert(QLatin1String("signed")); + keywords.insert(QLatin1String("sizeof")); + keywords.insert(QLatin1String("static")); + keywords.insert(QLatin1String("static_cast")); + keywords.insert(QLatin1String("struct")); + keywords.insert(QLatin1String("switch")); + keywords.insert(QLatin1String("template")); + keywords.insert(QLatin1String("this")); + keywords.insert(QLatin1String("throw")); + keywords.insert(QLatin1String("true")); + keywords.insert(QLatin1String("try")); + keywords.insert(QLatin1String("typedef")); + keywords.insert(QLatin1String("typeid")); + keywords.insert(QLatin1String("typename")); + keywords.insert(QLatin1String("union")); + keywords.insert(QLatin1String("unsigned")); + keywords.insert(QLatin1String("using")); + keywords.insert(QLatin1String("virtual")); + keywords.insert(QLatin1String("void")); + keywords.insert(QLatin1String("volatile")); + keywords.insert(QLatin1String("wchar_t")); + keywords.insert(QLatin1String("while")); + + // java keywords + keywords.insert(QLatin1String("abstract")); + keywords.insert(QLatin1String("assert")); + keywords.insert(QLatin1String("boolean")); + keywords.insert(QLatin1String("break")); + keywords.insert(QLatin1String("byte")); + keywords.insert(QLatin1String("case")); + keywords.insert(QLatin1String("catch")); + keywords.insert(QLatin1String("char")); + keywords.insert(QLatin1String("class")); + keywords.insert(QLatin1String("const")); + keywords.insert(QLatin1String("continue")); + keywords.insert(QLatin1String("default")); + keywords.insert(QLatin1String("do")); + keywords.insert(QLatin1String("double")); + keywords.insert(QLatin1String("else")); + keywords.insert(QLatin1String("enum")); + keywords.insert(QLatin1String("extends")); + keywords.insert(QLatin1String("false")); + keywords.insert(QLatin1String("final")); + keywords.insert(QLatin1String("finality")); + keywords.insert(QLatin1String("float")); + keywords.insert(QLatin1String("for")); + keywords.insert(QLatin1String("goto")); + keywords.insert(QLatin1String("if")); + keywords.insert(QLatin1String("implements")); + keywords.insert(QLatin1String("import")); + keywords.insert(QLatin1String("instanceof")); + keywords.insert(QLatin1String("int")); + keywords.insert(QLatin1String("interface")); + keywords.insert(QLatin1String("long")); + keywords.insert(QLatin1String("native")); + keywords.insert(QLatin1String("new")); + keywords.insert(QLatin1String("null")); + keywords.insert(QLatin1String("package")); + keywords.insert(QLatin1String("private")); + keywords.insert(QLatin1String("protected")); + keywords.insert(QLatin1String("public")); + keywords.insert(QLatin1String("return")); + keywords.insert(QLatin1String("short")); + keywords.insert(QLatin1String("static")); + keywords.insert(QLatin1String("strictfp")); + keywords.insert(QLatin1String("super")); + keywords.insert(QLatin1String("switch")); + keywords.insert(QLatin1String("synchronized")); + keywords.insert(QLatin1String("this")); + keywords.insert(QLatin1String("throw")); + keywords.insert(QLatin1String("throws")); + keywords.insert(QLatin1String("transient")); + keywords.insert(QLatin1String("true")); + keywords.insert(QLatin1String("try")); + keywords.insert(QLatin1String("void")); + keywords.insert(QLatin1String("volatile")); + keywords.insert(QLatin1String("while")); + } + return keywords; +} + +bool FormWindow::unify(QObject *w, QString &s, bool changeIt) +{ + typedef QSet<QString> StringSet; + + QWidget *main = mainContainer(); + if (!main) + return true; + + StringSet existingNames = languageKeywords(); + // build a set of existing names of other widget excluding self + if (!(w->isWidgetType() && isMainContainer(qobject_cast<QWidget*>(w)))) + existingNames.insert(main->objectName()); + + const QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); + const QWidgetList widgetChildren = qFindChildren<QWidget*>(main); + if (!widgetChildren.empty()) + insertNames(metaDataBase, widgetChildren.constBegin(), widgetChildren.constEnd(), w, existingNames); + + const QList<QLayout *> layoutChildren = qFindChildren<QLayout*>(main); + if (!layoutChildren.empty()) + insertNames(metaDataBase, layoutChildren.constBegin(), layoutChildren.constEnd(), w, existingNames); + + const QList<QAction *> actionChildren = qFindChildren<QAction*>(main); + if (!actionChildren.empty()) + insertNames(metaDataBase, actionChildren.constBegin(), actionChildren.constEnd(), w, existingNames); + + const QList<QButtonGroup *> buttonGroupChildren = qFindChildren<QButtonGroup*>(main); + if (!buttonGroupChildren.empty()) + insertNames(metaDataBase, buttonGroupChildren.constBegin(), buttonGroupChildren.constEnd(), w, existingNames); + + const StringSet::const_iterator enEnd = existingNames.constEnd(); + if (existingNames.constFind(s) == enEnd) + return true; + else + if (!changeIt) + return false; + + // split 'name_number' + qlonglong num = 0; + qlonglong factor = 1; + int idx = s.length()-1; + const ushort zeroUnicode = QLatin1Char('0').unicode(); + for ( ; idx > 0 && s.at(idx).isDigit(); --idx) { + num += (s.at(idx).unicode() - zeroUnicode) * factor; + factor *= 10; + } + // Position index past '_'. + const QChar underscore = QLatin1Char('_'); + if (idx >= 0 && s.at(idx) == underscore) { + idx++; + } else { + num = 1; + s += underscore; + idx = s.length(); + } + // try 'name_n', 'name_n+1' + for (num++ ; ;num++) { + s.truncate(idx); + s += QString::number(num); + if (existingNames.constFind(s) == enEnd) + break; + } + return false; +} +/* already_in_form is true when we are moving a widget from one parent to another inside the same + * form. All this means is that InsertWidgetCommand::undo() must not unmanage it. */ + +void FormWindow::insertWidget(QWidget *w, const QRect &rect, QWidget *container, bool already_in_form) +{ + clearSelection(false); + + beginCommand(tr("Insert widget '%1'").arg(WidgetFactory::classNameOf(m_core, w))); // ### use the WidgetDatabaseItem + + /* Reparenting into a QSplitter automatically adjusts child's geometry. We create the geometry + * command before we push the reparent command, so that the geometry command has the original + * geometry of the widget. */ + QRect r = rect; + Q_ASSERT(r.isValid()); + SetPropertyCommand *geom_cmd = new SetPropertyCommand(this); + geom_cmd->init(w, QLatin1String("geometry"), r); // ### use rc.size() + + if (w->parentWidget() != container) { + ReparentWidgetCommand *cmd = new ReparentWidgetCommand(this); + cmd->init(w, container); + m_commandHistory->push(cmd); + } + + m_commandHistory->push(geom_cmd); + + InsertWidgetCommand *cmd = new InsertWidgetCommand(this); + cmd->init(w, already_in_form); + m_commandHistory->push(cmd); + + endCommand(); + + w->show(); +} + +QWidget *FormWindow::createWidget(DomUI *ui, const QRect &rc, QWidget *target) +{ + QWidget *container = findContainer(target, false); + if (!container) + return 0; + if (isMainContainer(container)) { + if (QMainWindow *mw = qobject_cast<QMainWindow*>(container)) { + Q_ASSERT(mw->centralWidget() != 0); + container = mw->centralWidget(); + } + } + QDesignerResource resource(this); + const FormBuilderClipboard clipboard = resource.paste(ui, container); + if (clipboard.m_widgets.size() != 1) // multiple-paste from DomUI not supported yet + return 0; + QWidget *widget = clipboard.m_widgets.first(); + insertWidget(widget, rc, container); + return widget; +} + +#ifndef QT_NO_DEBUG +static bool isDescendant(const QWidget *parent, const QWidget *child) +{ + for (; child != 0; child = child->parentWidget()) { + if (child == parent) + return true; + } + return false; +} +#endif + +void FormWindow::resizeWidget(QWidget *widget, const QRect &geometry) +{ + Q_ASSERT(isDescendant(this, widget)); + + QRect r = geometry; + if (m_lastIndex > m_commandHistory->index()) + m_lastIndex = -1; + SetPropertyCommand *cmd = new SetPropertyCommand(this); + cmd->init(widget, QLatin1String("geometry"), r); + cmd->setText(tr("Resize")); + m_commandHistory->push(cmd); +} + +void FormWindow::raiseChildSelections(QWidget *w) +{ + const QWidgetList l = qFindChildren<QWidget*>(w); + if (l.isEmpty()) + return; + m_selection->raiseList(l); +} + +QWidget *FormWindow::containerAt(const QPoint &pos, QWidget *notParentOf) +{ + QWidget *container = 0; + int depth = -1; + const QWidgetList selected = selectedWidgets(); + if (rect().contains(mapFromGlobal(pos))) { + container = mainContainer(); + depth = widgetDepth(container); + } + + QListIterator<QWidget*> it(m_widgets); + while (it.hasNext()) { + QWidget *wit = it.next(); + if (qobject_cast<QLayoutWidget*>(wit) || qobject_cast<QSplitter*>(wit)) + continue; + if (!wit->isVisibleTo(this)) + continue; + if (selected.indexOf(wit) != -1) + continue; + if (!core()->widgetDataBase()->isContainer(wit) && + wit != mainContainer()) + continue; + + // the rectangles of all ancestors of the container must contain the insert position + QWidget *w = wit; + while (w && !w->isWindow()) { + if (!w->rect().contains((w->mapFromGlobal(pos)))) + break; + w = w->parentWidget(); + } + if (!(w == 0 || w->isWindow())) + continue; // we did not get through the full while loop + + int wd = widgetDepth(wit); + if (wd == depth && container) { + if (wit->parentWidget()->children().indexOf(wit) > + container->parentWidget()->children().indexOf(container)) + wd++; + } + if (wd > depth && !isChildOf(wit, notParentOf)) { + depth = wd; + container = wit; + } + } + return container; +} + +QWidgetList FormWindow::selectedWidgets() const +{ + return m_selection->selectedWidgets(); +} + +void FormWindow::selectWidgets() +{ + bool selectionChanged = false; + const QWidgetList l = qFindChildren<QWidget*>(mainContainer()); + QListIterator <QWidget*> it(l); + const QRect selRect(mapToGlobal(m_currRect.topLeft()), m_currRect.size()); + while (it.hasNext()) { + QWidget *w = it.next(); + if (w->isVisibleTo(this) && isManaged(w)) { + const QPoint p = w->mapToGlobal(QPoint(0,0)); + const QRect r(p, w->size()); + if (r.intersects(selRect) && !r.contains(selRect) && trySelectWidget(w, true)) + selectionChanged = true; + } + } + + if (selectionChanged) + emitSelectionChanged(); +} + +bool FormWindow::handleKeyPressEvent(QWidget *widget, QWidget *, QKeyEvent *e) +{ + if (qobject_cast<const FormWindow*>(widget) || qobject_cast<const QMenu*>(widget)) + return false; + + e->accept(); // we always accept! + + switch (e->key()) { + default: break; // we don't care about the other keys + + case Qt::Key_Delete: + case Qt::Key_Backspace: + if (e->modifiers() == Qt::NoModifier) + deleteWidgets(); + break; + + case Qt::Key_Tab: + if (e->modifiers() == Qt::NoModifier) + cursor()->movePosition(QDesignerFormWindowCursorInterface::Next); + break; + + case Qt::Key_Backtab: + if (e->modifiers() == Qt::NoModifier) + cursor()->movePosition(QDesignerFormWindowCursorInterface::Prev); + break; + + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + handleArrowKeyEvent(e->key(), e->modifiers()); + break; + } + + return true; +} + +int FormWindow::getValue(const QRect &rect, int key, bool size) const +{ + if (size) { + if (key == Qt::Key_Left || key == Qt::Key_Right) + return rect.width(); + return rect.height(); + } + if (key == Qt::Key_Left || key == Qt::Key_Right) + return rect.x(); + return rect.y(); +} + +int FormWindow::calcValue(int val, bool forward, bool snap, int snapOffset) const +{ + if (snap) { + const int rest = val % snapOffset; + if (rest) { + const int offset = forward ? snapOffset : 0; + const int newOffset = rest < 0 ? offset - snapOffset : offset; + return val + newOffset - rest; + } + return (forward ? val + snapOffset : val - snapOffset); + } + return (forward ? val + 1 : val - 1); +} + +QRect FormWindow::applyValue(const QRect &rect, int val, int key, bool size) const +{ + QRect r = rect; + if (size) { + if (key == Qt::Key_Left || key == Qt::Key_Right) + r.setWidth(val); + else + r.setHeight(val); + } else { + if (key == Qt::Key_Left || key == Qt::Key_Right) + r.moveLeft(val); + else + r.moveTop(val); + } + return r; +} + +void FormWindow::handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers) +{ + bool startMacro = false; + const QDesignerFormWindowCursorInterface *c = cursor(); + if (!c->hasSelection()) + return; + + QWidgetList selection; + + // check if a laid out widget is selected + const int count = c->selectedWidgetCount(); + for (int index = 0; index < count; ++index) { + QWidget *w = c->selectedWidget(index); + if (!LayoutInfo::isWidgetLaidout(m_core, w)) + selection.append(w); + } + + if (selection.isEmpty()) + return; + + QWidget *current = c->current(); + if (!current || LayoutInfo::isWidgetLaidout(m_core, current)) { + current = selection.first(); + } + + const bool size = modifiers & Qt::ShiftModifier; + + const bool snap = !(modifiers & Qt::ControlModifier); + const bool forward = (key == Qt::Key_Right || key == Qt::Key_Down); + const int snapPoint = (key == Qt::Key_Left || key == Qt::Key_Right) ? grid().x() : grid().y(); + + const int oldValue = getValue(current->geometry(), key, size); + + const int newValue = calcValue(oldValue, forward, snap, snapPoint); + + const int offset = newValue - oldValue; + + const int selCount = selection.count(); + // check if selection is the same as last time + if (selCount != m_moveSelection.count() || + m_lastUndoIndex != m_commandHistory->index()) { + m_moveSelection.clear(); + startMacro = true; + } else { + for (int index = 0; index < selCount; ++index) { + if (m_moveSelection[index]->object() != selection.at(index)) { + m_moveSelection.clear(); + startMacro = true; + break; + } + } + } + + if (startMacro) + beginCommand(tr("Key Move")); + + for (int index = 0; index < selCount; ++index) { + QWidget *w = selection.at(index); + const QRect oldGeom = w->geometry(); + const QRect geom = applyValue(oldGeom, getValue(oldGeom, key, size) + offset, key, size); + + SetPropertyCommand *cmd = 0; + + if (m_moveSelection.count() > index) + cmd = m_moveSelection[index]; + + if (!cmd) { + cmd = new SetPropertyCommand(this); + cmd->init(w, QLatin1String("geometry"), geom); + cmd->setText(tr("Key Move")); + m_commandHistory->push(cmd); + + if (m_moveSelection.count() > index) + m_moveSelection.replace(index, cmd); + else + m_moveSelection.append(cmd); + } else { + cmd->setNewValue(geom); + cmd->redo(); + } + } + + if (startMacro) { + endCommand(); + m_lastUndoIndex = m_commandHistory->index(); + } +} + +bool FormWindow::handleKeyReleaseEvent(QWidget *, QWidget *, QKeyEvent *e) +{ + e->accept(); + return true; +} + +void FormWindow::selectAll() +{ + bool selectionChanged = false; + foreach (QWidget *widget, m_widgets) { + if (widget->isVisibleTo(this) && trySelectWidget(widget, true)) + selectionChanged = true; + } + if (selectionChanged) + emitSelectionChanged(); +} + +void FormWindow::createLayout(int type, QWidget *container) +{ + if (container) { + layoutContainer(container, type); + } else { + LayoutCommand *cmd = new LayoutCommand(this); + cmd->init(mainContainer(), selectedWidgets(), static_cast<LayoutInfo::Type>(type)); + commandHistory()->push(cmd); + } +} + +void FormWindow::morphLayout(QWidget *container, int newType) +{ + MorphLayoutCommand *cmd = new MorphLayoutCommand(this); + if (cmd->init(container, newType)) { + commandHistory()->push(cmd); + } else { + qDebug() << "** WARNING Unable to morph layout."; + delete cmd; + } +} + +void FormWindow::deleteWidgets() +{ + QWidgetList selection = selectedWidgets(); + simplifySelection(&selection); + + deleteWidgetList(selection); +} + +QString FormWindow::fileName() const +{ + return m_fileName; +} + +void FormWindow::setFileName(const QString &fileName) +{ + if (m_fileName == fileName) + return; + + m_fileName = fileName; + emit fileNameChanged(fileName); +} + +QString FormWindow::contents() const +{ + QBuffer b; + if (!mainContainer() || !b.open(QIODevice::WriteOnly)) + return QString(); + + QDesignerResource resource(const_cast<FormWindow*>(this)); + resource.save(&b, mainContainer()); + + return QString::fromUtf8(b.buffer()); +} + +void FormWindow::copy() +{ + QBuffer b; + if (!b.open(QIODevice::WriteOnly)) + return; + + FormBuilderClipboard clipboard; + QDesignerResource resource(this); + resource.setSaveRelative(false); + clipboard.m_widgets = selectedWidgets(); + simplifySelection(&clipboard.m_widgets); + resource.copy(&b, clipboard); + + qApp->clipboard()->setText(QString::fromUtf8(b.buffer()), QClipboard::Clipboard); +} + +void FormWindow::cut() +{ + copy(); + deleteWidgets(); +} + +// for cases like QMainWindow (central widget is an inner container) or QStackedWidget (page is an inner container) +QWidget *FormWindow::innerContainer(QWidget *outerContainer) const +{ + bool isContainer = m_core->widgetDataBase()->isContainer(outerContainer); + if (isContainer) + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), outerContainer)) + return container->widget(container->currentIndex()); + return outerContainer; +} + +QWidget *FormWindow::containerForPaste() const +{ + QWidget *w = mainContainer(); + if (!w) + return 0; + do { + // Try to find a close parent, for example a non-laid-out + // QFrame/QGroupBox when a widget within it is selected. + QWidgetList selection = selectedWidgets(); + if (selection.empty()) + break; + simplifySelection(&selection); + + QWidget *containerOfW = findContainer(selection.first(), /* exclude layouts */ true); + if (!containerOfW || containerOfW == mainContainer()) + break; + // No layouts, must be container + containerOfW = innerContainer(containerOfW); + if (LayoutInfo::layoutType(m_core, containerOfW) != LayoutInfo::NoLayout || !m_core->widgetDataBase()->isContainer(containerOfW)) + break; + w = containerOfW; + } while (false); + // First check for layout (note that it does not cover QMainWindow + // and the like as the central widget has the layout). + + w = innerContainer(w); + if (LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout) + return 0; + // Go up via container extension (also includes step from QMainWindow to its central widget) + w = m_core->widgetFactory()->containerOfWidget(w); + if (w == 0 || LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout) + return 0; + + if (debugFormWindow) + qDebug() <<"containerForPaste() " << w; + return w; +} + +void FormWindow::paste() +{ + paste(PasteAll); +} + +// Construct DomUI from clipboard (paste) and determine number of widgets/actions. +static inline DomUI *domUIFromClipboard(int *widgetCount, int *actionCount) +{ + *widgetCount = *actionCount = 0; + const QString clipboardText = qApp->clipboard()->text(); + if (clipboardText.isEmpty() || clipboardText.indexOf(QLatin1Char('<')) == -1) + return 0; + + QXmlStreamReader reader(clipboardText); + DomUI *ui = 0; + const QString uiElement = QLatin1String("ui"); + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0 && !ui) { + ui = new DomUI(); + ui->read(reader); + break; + } else { + reader.raiseError(QCoreApplication::translate("FormWindow", "Unexpected element <%1>").arg(reader.name().toString())); + } + } + } + if (reader.hasError()) { + delete ui; + ui = 0; + designerWarning(QCoreApplication::translate("FormWindow", "Error while pasting clipboard contents at line %1, column %2: %3"). + arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString())); + return 0; + } + + if (const DomWidget *topLevel = ui->elementWidget()) { + *widgetCount = topLevel->elementWidget().size(); + *actionCount = topLevel->elementAction().size(); + } + if (*widgetCount == 0 && *actionCount == 0) { + delete ui; + return 0; + } + return ui; +} + +static inline QString pasteCommandDescription(int widgetCount, int actionCount) +{ + if (widgetCount == 0) + return FormWindow::tr("Paste %n action(s)", 0, actionCount); + if (actionCount == 0) + return FormWindow::tr("Paste %n widget(s)", 0, widgetCount); + return FormWindow::tr("Paste (%1 widgets, %2 actions)").arg(widgetCount).arg(actionCount); +} + +static void positionPastedWidgetsAtMousePosition(FormWindow *fw, const QPoint &contextMenuPosition, QWidget *parent, const QWidgetList &l) +{ + // Try to position pasted widgets at mouse position (current mouse position for Ctrl-V or position of context menu) + // if it fits. If it is completely outside, force it to 0,0 + // If it fails, the old coordinates relative to the previous parent will be used. + QPoint currentPos = contextMenuPosition.x() >=0 ? parent->mapFrom(fw, contextMenuPosition) : parent->mapFromGlobal(QCursor::pos()); + const Grid &grid = fw->designerGrid(); + QPoint cursorPos = grid.snapPoint(currentPos); + const QRect parentGeometry = QRect(QPoint(0, 0), parent->size()); + const bool outside = !parentGeometry.contains(cursorPos); + if (outside) + cursorPos = grid.snapPoint(QPoint(0, 0)); + // Determine area of pasted widgets + QRect pasteArea; + const QWidgetList::const_iterator lcend = l.constEnd(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) + pasteArea =pasteArea.isNull() ? (*it)->geometry() : pasteArea.united((*it)->geometry()); + + // Mouse on some child? (try to position bottomRight on a free spot to + // get the stacked-offset effect of Designer 4.3, that is, offset by grid if Ctrl-V is pressed continuously + do { + const QPoint bottomRight = cursorPos + QPoint(pasteArea.width(), pasteArea.height()) - QPoint(1, 1); + if (bottomRight.y() > parentGeometry.bottom() || parent->childAt(bottomRight) == 0) + break; + cursorPos += QPoint(grid.deltaX(), grid.deltaY()); + } while (true); + // Move. + const QPoint offset = cursorPos - pasteArea.topLeft(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) + (*it)->move((*it)->pos() + offset); +} + +void FormWindow::paste(PasteMode pasteMode) +{ + // Avoid QDesignerResource constructing widgets that are not used as + // QDesignerResource manages the widgets it creates (creating havoc if one remains unused) + DomUI *ui = 0; + do { + int widgetCount; + int actionCount; + ui = domUIFromClipboard(&widgetCount, &actionCount); + if (!ui) + break; + + // Check for actions + if (pasteMode == PasteActionsOnly) + if (widgetCount != 0 || actionCount == 0) + break; + + // Check for widgets: need a container + QWidget *pasteContainer = widgetCount ? containerForPaste() : 0; + if (widgetCount && pasteContainer == 0) { + + const QString message = tr("Cannot paste widgets. Designer could not find a container " + "without a layout to paste into."); + const QString infoMessage = tr("Break the layout of the " + "container you want to paste into, select this container " + "and then paste again."); + core()->dialogGui()->message(this, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Information, + tr("Paste error"), message, infoMessage, QMessageBox::Ok); + break; + } + + QDesignerResource resource(this); + // Note that the widget factory must be able to locate the + // form window (us) via parent, otherwise, it will not able to construct QLayoutWidgets + // (It will then default to widgets) among other issues. + const FormBuilderClipboard clipboard = resource.paste(ui, pasteContainer, this); + + clearSelection(false); + // Create command sequence + beginCommand(pasteCommandDescription(widgetCount, actionCount)); + + if (widgetCount) { + positionPastedWidgetsAtMousePosition(this, m_contextMenuPosition, pasteContainer, clipboard.m_widgets); + foreach (QWidget *w, clipboard.m_widgets) { + InsertWidgetCommand *cmd = new InsertWidgetCommand(this); + cmd->init(w); + m_commandHistory->push(cmd); + selectWidget(w); + } + } + + if (actionCount) + foreach (QAction *a, clipboard.m_actions) { + ensureUniqueObjectName(a); + AddActionCommand *cmd = new AddActionCommand(this); + cmd->init(a); + m_commandHistory->push(cmd); + } + endCommand(); + } while (false); + delete ui; +} + +// Draw a dotted frame around containers +bool FormWindow::frameNeeded(QWidget *w) const +{ + if (!core()->widgetDataBase()->isContainer(w)) + return false; + if (qobject_cast<QGroupBox *>(w)) + return false; + if (qobject_cast<QToolBox *>(w)) + return false; + if (qobject_cast<QTabWidget *>(w)) + return false; + if (qobject_cast<QStackedWidget *>(w)) + return false; + if (qobject_cast<QDockWidget *>(w)) + return false; + if (qobject_cast<QDesignerWidget *>(w)) + return false; + if (qobject_cast<QMainWindow *>(w)) + return false; + if (qobject_cast<QDialog *>(w)) + return false; + if (qobject_cast<QLayoutWidget *>(w)) + return false; + return true; +} + +bool FormWindow::eventFilter(QObject *watched, QEvent *event) +{ + const bool ret = FormWindowBase::eventFilter(watched, event); + if (event->type() != QEvent::Paint) + return ret; + + Q_ASSERT(watched->isWidgetType()); + QWidget *w = static_cast<QWidget *>(watched); + QPaintEvent *pe = static_cast<QPaintEvent*>(event); + const QRect widgetRect = w->rect(); + const QRect paintRect = pe->rect(); + // Does the paint rectangle touch the borders of the widget rectangle + if (paintRect.x() > widgetRect.x() && paintRect.y() > widgetRect.y() && + paintRect.right() < widgetRect.right() && paintRect.bottom() < widgetRect.bottom()) + return ret; + QPainter p(w); + const QPen pen(QColor(0, 0, 0, 32), 0, Qt::DotLine); + p.setPen(pen); + p.setBrush(QBrush(Qt::NoBrush)); + p.drawRect(widgetRect.adjusted(0, 0, -1, -1)); + return ret; +} + +void FormWindow::manageWidget(QWidget *w) +{ + if (isManaged(w)) + return; + + Q_ASSERT(qobject_cast<QMenu*>(w) == 0); + + if (w->hasFocus()) + setFocus(); + + core()->metaDataBase()->add(w); + + m_insertedWidgets.insert(w); + m_widgets.append(w); + +#ifndef QT_NO_CURSOR + setCursorToAll(Qt::ArrowCursor, w); +#endif + + emit changed(); + emit widgetManaged(w); + + if (frameNeeded(w)) + w->installEventFilter(this); +} + +void FormWindow::unmanageWidget(QWidget *w) +{ + if (!isManaged(w)) + return; + + m_selection->removeWidget(w); + + emit aboutToUnmanageWidget(w); + + if (w == m_currentWidget) + setCurrentWidget(mainContainer()); + + core()->metaDataBase()->remove(w); + + m_insertedWidgets.remove(w); + m_widgets.removeAt(m_widgets.indexOf(w)); + + emit changed(); + emit widgetUnmanaged(w); + + if (frameNeeded(w)) + w->removeEventFilter(this); +} + +bool FormWindow::isManaged(QWidget *w) const +{ + return m_insertedWidgets.contains(w); +} + +void FormWindow::breakLayout(QWidget *w) +{ + if (w == this) + w = mainContainer(); + // Find the first-order managed child widgets + QWidgetList widgets; + + const QObjectList children = w->children(); + const QObjectList::const_iterator cend = children.constEnd(); + const QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) + if ( (*it)->isWidgetType()) { + QWidget *w = static_cast<QWidget*>(*it); + if (mdb->item(w)) + widgets.push_back(w); + } + + BreakLayoutCommand *cmd = new BreakLayoutCommand(this); + cmd->init(widgets, w); + commandHistory()->push(cmd); + clearSelection(false); +} + +void FormWindow::beginCommand(const QString &description) +{ + if (m_lastIndex > m_commandHistory->index()) + m_lastIndex = -1; + m_commandHistory->beginMacro(description); +} + +void FormWindow::endCommand() +{ + m_commandHistory->endMacro(); +} + +void FormWindow::raiseWidgets() +{ + QWidgetList widgets = selectedWidgets(); + simplifySelection(&widgets); + + if (widgets.isEmpty()) + return; + + beginCommand(tr("Raise widgets")); + foreach (QWidget *widget, widgets) { + RaiseWidgetCommand *cmd = new RaiseWidgetCommand(this); + cmd->init(widget); + m_commandHistory->push(cmd); + } + endCommand(); +} + +void FormWindow::lowerWidgets() +{ + QWidgetList widgets = selectedWidgets(); + simplifySelection(&widgets); + + if (widgets.isEmpty()) + return; + + beginCommand(tr("Lower widgets")); + foreach (QWidget *widget, widgets) { + LowerWidgetCommand *cmd = new LowerWidgetCommand(this); + cmd->init(widget); + m_commandHistory->push(cmd); + } + endCommand(); +} + +bool FormWindow::handleMouseButtonDblClickEvent(QWidget *w, QWidget *managedWidget, QMouseEvent *e) +{ + if (debugFormWindow) + qDebug() << "handleMouseButtonDblClickEvent:" << w << ',' << managedWidget << "state=" << m_mouseState; + + e->accept(); + + // Might be out of sync due cycling of the parent selection + // In that case, do nothing + if (isWidgetSelected(managedWidget)) + emit activated(managedWidget); + + m_mouseState = MouseDoubleClicked; + return true; +} + + +QMenu *FormWindow::initializePopupMenu(QWidget *managedWidget) +{ + if (!isManaged(managedWidget) || currentTool()) + return 0; + + // Make sure the managedWidget is selected and current since + // the SetPropertyCommands must use the right reference + // object obtained from the property editor for the property group + // of a multiselection to be correct. + const bool selected = isWidgetSelected(managedWidget); + bool update = false; + if (selected == false) { + clearObjectInspectorSelection(m_core); // We might have a toolbar or non-widget selected in the object inspector. + clearSelection(false); + update = trySelectWidget(managedWidget, true); + raiseChildSelections(managedWidget); // raise selections and select widget + } else { + update = setCurrentWidget(managedWidget); + } + + if (update) { + emitSelectionChanged(); + QMetaObject::invokeMethod(core()->formWindowManager(), "slotUpdateActions"); + } + + QWidget *contextMenuWidget = 0; + + if (isMainContainer(managedWidget)) { // press on a child widget + contextMenuWidget = mainContainer(); + } else { // press on a child widget + // if widget is laid out, find the first non-laid out super-widget + QWidget *realWidget = managedWidget; // but store the original one + QMainWindow *mw = qobject_cast<QMainWindow*>(mainContainer()); + + if (mw && mw->centralWidget() == realWidget) { + contextMenuWidget = managedWidget; + } else { + contextMenuWidget = realWidget; + } + } + + if (!contextMenuWidget) + return 0; + + QMenu *contextMenu = createPopupMenu(contextMenuWidget); + if (!contextMenu) + return 0; + + emit contextMenuRequested(contextMenu, contextMenuWidget); + return contextMenu; +} + +bool FormWindow::handleContextMenu(QWidget *, QWidget *managedWidget, QContextMenuEvent *e) +{ + QMenu *contextMenu = initializePopupMenu(managedWidget); + if (!contextMenu) + return false; + const QPoint globalPos = e->globalPos(); + m_contextMenuPosition = mapFromGlobal (globalPos); + contextMenu->exec(globalPos); + delete contextMenu; + e->accept(); + m_contextMenuPosition = QPoint(-1, -1); + return true; +} + +void FormWindow::setContents(QIODevice *dev) +{ + UpdateBlocker ub(this); + clearSelection(); + m_selection->clearSelectionPool(); + m_insertedWidgets.clear(); + m_widgets.clear(); + // The main container is cleared as otherwise + // the names of the newly loaded objects will be unified. + clearMainContainer(); + emit changed(); + + QDesignerResource r(this); + QWidget *w = r.load(dev, formContainer()); + setMainContainer(w); + emit changed(); +} + +void FormWindow::setContents(const QString &contents) +{ + QByteArray data = contents.toUtf8(); + QBuffer b(&data); + if (b.open(QIODevice::ReadOnly)) + setContents(&b); +} + +void FormWindow::layoutContainer(QWidget *w, int type) +{ + if (w == this) + w = mainContainer(); + + w = core()->widgetFactory()->containerOfWidget(w); + + const QObjectList l = w->children(); + if (l.isEmpty()) + return; + // find managed widget children + QWidgetList widgets; + const QObjectList::const_iterator ocend = l.constEnd(); + for (QObjectList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) + if ( (*it)->isWidgetType() ) { + QWidget *widget = static_cast<QWidget*>(*it); + if (widget->isVisibleTo(this) && isManaged(widget)) + widgets.append(widget); + } + + LayoutCommand *cmd = new LayoutCommand(this); + cmd->init(mainContainer(), widgets, static_cast<LayoutInfo::Type>(type), w); + clearSelection(false); + commandHistory()->push(cmd); +} + +bool FormWindow::hasInsertedChildren(QWidget *widget) const // ### move +{ + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) { + widget = container->widget(container->currentIndex()); + } + + const QWidgetList l = widgets(widget); + + foreach (QWidget *child, l) { + if (isManaged(child) && !LayoutInfo::isWidgetLaidout(core(), child) && child->isVisibleTo(const_cast<FormWindow*>(this))) + return true; + } + + return false; +} + +// "Select Ancestor" sub menu code +void FormWindow::slotSelectWidget(QAction *a) +{ + if (QWidget *w = qvariant_cast<QWidget*>(a->data())) + selectSingleWidget(w); +} + +static inline QString objectNameOf(const QWidget *w) +{ + if (const QLayoutWidget *lw = qobject_cast<const QLayoutWidget *>(w)) { + const QLayout *layout = lw->layout(); + const QString rc = layout->objectName(); + if (!rc.isEmpty()) + return rc; + // Fall thru for 4.3 forms which have a name on the widget: Display the class name + return QString::fromUtf8(layout->metaObject()->className()); + } + return w->objectName(); +} + +QAction *FormWindow::createSelectAncestorSubMenu(QWidget *w) +{ + // Find the managed, unselected parents + QWidgetList parents; + QWidget *mc = mainContainer(); + for (QWidget *p = w->parentWidget(); p && p != mc; p = p->parentWidget()) + if (isManaged(p) && !isWidgetSelected(p)) + parents.push_back(p); + if (parents.empty()) + return 0; + // Create a submenu listing the managed, unselected parents + QMenu *menu = new QMenu; + QActionGroup *ag = new QActionGroup(menu); + QObject::connect(ag, SIGNAL(triggered(QAction*)), this, SLOT(slotSelectWidget(QAction*))); + const int size = parents.size(); + for (int i = 0; i < size; i++) { + QWidget *w = parents.at(i); + QAction *a = ag->addAction(objectNameOf(w)); + a->setData(qVariantFromValue(w)); + menu->addAction(a); + } + QAction *ma = new QAction(tr("Select Ancestor"), 0); + ma->setMenu(menu); + return ma; +} + +QMenu *FormWindow::createPopupMenu(QWidget *w) +{ + QMenu *popup = createExtensionTaskMenu(this, w, true); + if (!popup) + popup = new QMenu; + // if w doesn't have a QDesignerTaskMenu as a child create one and make it a child. + // insert actions from QDesignerTaskMenu + + QDesignerFormWindowManagerInterface *manager = core()->formWindowManager(); + const bool isFormWindow = qobject_cast<const FormWindow*>(w); + + // Check for special containers and obtain the page menu from them to add layout actions. + if (!isFormWindow) { + if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(w)) { + QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(stackedWidget, popup); + } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(w)) { + QTabWidgetEventFilter::addTabWidgetContextMenuActions(tabWidget, popup); + } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(w)) { + QToolBoxHelper::addToolBoxContextMenuActions(toolBox, popup); + } + + popup->addAction(manager->actionCut()); + popup->addAction(manager->actionCopy()); + } + + popup->addAction(manager->actionPaste()); + + if (QAction *selectAncestorAction = createSelectAncestorSubMenu(w)) + popup->addAction(selectAncestorAction); + popup->addAction(manager->actionSelectAll()); + + if (!isFormWindow) { + popup->addAction(manager->actionDelete()); + } + + popup->addSeparator(); + QMenu *layoutMenu = popup->addMenu(tr("Lay out")); + layoutMenu->addAction(manager->actionAdjustSize()); + layoutMenu->addAction(manager->actionHorizontalLayout()); + layoutMenu->addAction(manager->actionVerticalLayout()); + layoutMenu->addAction(manager->actionGridLayout()); + layoutMenu->addAction(manager->actionFormLayout()); + if (!isFormWindow) { + layoutMenu->addAction(manager->actionSplitHorizontal()); + layoutMenu->addAction(manager->actionSplitVertical()); + } + layoutMenu->addAction(manager->actionBreakLayout()); + layoutMenu->addAction(manager->actionSimplifyLayout()); + + return popup; +} + +void FormWindow::resizeEvent(QResizeEvent *e) +{ + m_geometryChangedTimer->start(10); + + QWidget::resizeEvent(e); +} + +/*! + Maps \a pos in \a w's coordinates to the form's coordinate system. + + This is the equivalent to mapFromGlobal(w->mapToGlobal(pos)) but + avoids the two roundtrips to the X-Server on Unix/X11. + */ +QPoint FormWindow::mapToForm(const QWidget *w, const QPoint &pos) const +{ + QPoint p = pos; + const QWidget* i = w; + while (i && !i->isWindow() && !isMainContainer(i)) { + p = i->mapToParent(p); + i = i->parentWidget(); + } + + return mapFromGlobal(w->mapToGlobal(pos)); +} + +bool FormWindow::canBeBuddy(QWidget *w) const // ### rename me. +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + const Qt::FocusPolicy q = static_cast<Qt::FocusPolicy>(Utils::valueOf(sheet->property(index), &ok)); + return ok && q != Qt::NoFocus; + } + } + + return false; +} + +QWidget *FormWindow::findContainer(QWidget *w, bool excludeLayout) const +{ + if (!isChildOf(w, this) + || const_cast<const QWidget *>(w) == this) + return 0; + + QDesignerWidgetFactoryInterface *widgetFactory = core()->widgetFactory(); + QDesignerWidgetDataBaseInterface *widgetDataBase = core()->widgetDataBase(); + QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); + + QWidget *container = widgetFactory->containerOfWidget(mainContainer()); // default parent for new widget is the formwindow + if (!isMainContainer(w)) { // press was not on formwindow, check if we can find another parent + while (w) { + if (qobject_cast<InvisibleWidget*>(w) || !metaDataBase->item(w)) { + w = w->parentWidget(); + continue; + } + + const bool isContainer = widgetDataBase->isContainer(w, true) || w == mainContainer(); + + if (!isContainer || (excludeLayout && qobject_cast<QLayoutWidget*>(w))) { // ### skip QSplitter + w = w->parentWidget(); + } else { + container = w; + break; + } + } + } + + return container; +} + +void FormWindow::simplifySelection(QWidgetList *sel) const +{ + if (sel->size() < 2) + return; + // Figure out which widgets should be removed from selection. + // We want to remove those whose parent widget is also in the + // selection (because the child widgets are contained by + // their parent, they shouldn't be in the selection -- + // they are "implicitly" selected). + QWidget *mainC = mainContainer(); // Quick check for main container first + if (sel->contains(mainC)) { + sel->clear(); + sel->push_back(mainC); + return; + } + typedef QVector<QWidget *> WidgetVector; + WidgetVector toBeRemoved; + toBeRemoved.reserve(sel->size()); + const QWidgetList::const_iterator scend = sel->constEnd(); + for (QWidgetList::const_iterator it = sel->constBegin(); it != scend; ++it) { + QWidget *child = *it; + for (QWidget *w = child; true ; ) { // Is any of the parents also selected? + QWidget *parent = w->parentWidget(); + if (!parent || parent == mainC) + break; + if (sel->contains(parent)) { + toBeRemoved.append(child); + break; + } + w = parent; + } + } + // Now we can actually remove the widgets that were marked + // for removal in the previous pass. + if (!toBeRemoved.isEmpty()) { + const WidgetVector::const_iterator rcend = toBeRemoved.constEnd(); + for (WidgetVector::const_iterator it = toBeRemoved.constBegin(); it != rcend; ++it) + sel->removeAll(*it); + } +} + +FormWindow *FormWindow::findFormWindow(QWidget *w) +{ + return qobject_cast<FormWindow*>(QDesignerFormWindowInterface::findFormWindow(w)); +} + +bool FormWindow::isDirty() const +{ + return m_dirty; +} + +void FormWindow::setDirty(bool dirty) +{ + m_dirty = dirty; + + if (!m_dirty) + m_lastIndex = m_commandHistory->index(); +} + +void FormWindow::updateDirty() +{ + m_dirty = m_commandHistory->index() != m_lastIndex; +} + +QWidget *FormWindow::containerAt(const QPoint &pos) +{ + QWidget *widget = widgetAt(pos); + return findContainer(widget, true); +} + +static QWidget *childAt_SkipDropLine(QWidget *w, QPoint pos) +{ + const QObjectList child_list = w->children(); + for (int i = child_list.size() - 1; i >= 0; --i) { + QObject *child_obj = child_list[i]; + if (qobject_cast<WidgetHandle*>(child_obj) != 0) + continue; + QWidget *child = qobject_cast<QWidget*>(child_obj); + if (!child || child->isWindow() || !child->isVisible() || + !child->geometry().contains(pos) || child->testAttribute(Qt::WA_TransparentForMouseEvents)) + continue; + const QPoint childPos = child->mapFromParent(pos); + if (QWidget *res = childAt_SkipDropLine(child, childPos)) + return res; + if (child->testAttribute(Qt::WA_MouseNoMask) || child->mask().contains(pos) + || child->mask().isEmpty()) + return child; + } + + return 0; +} + +QWidget *FormWindow::widgetAt(const QPoint &pos) +{ + QWidget *w = childAt(pos); + if (qobject_cast<const WidgetHandle*>(w) != 0) + w = childAt_SkipDropLine(this, pos); + return (w == 0 || w == formContainer()) ? this : w; +} + +void FormWindow::highlightWidget(QWidget *widget, const QPoint &pos, HighlightMode mode) +{ + Q_ASSERT(widget); + + if (QMainWindow *mainWindow = qobject_cast<QMainWindow*> (widget)) { + widget = mainWindow->centralWidget(); + } + + QWidget *container = findContainer(widget, false); + + if (container == 0 || core()->metaDataBase()->item(container) == 0) + return; + + if (QDesignerActionProviderExtension *g = qt_extension<QDesignerActionProviderExtension*>(core()->extensionManager(), container)) { + if (mode == Restore) { + g->adjustIndicator(QPoint()); + } else { + const QPoint pt = widget->mapTo(container, pos); + g->adjustIndicator(pt); + } + } else if (QDesignerLayoutDecorationExtension *g = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), container)) { + if (mode == Restore) { + g->adjustIndicator(QPoint(), -1); + } else { + const QPoint pt = widget->mapTo(container, pos); + const int index = g->findItemAt(pt); + g->adjustIndicator(pt, index); + } + } + + QMainWindow *mw = qobject_cast<QMainWindow*> (container); + if (container == mainContainer() || (mw && mw->centralWidget() && mw->centralWidget() == container)) + return; + + if (mode == Restore) { + const WidgetPaletteMap::iterator pit = m_palettesBeforeHighlight.find(container); + if (pit != m_palettesBeforeHighlight.end()) { + container->setPalette(pit.value().first); + container->setAutoFillBackground(pit.value().second); + m_palettesBeforeHighlight.erase(pit); + } + } else { + QPalette p = container->palette(); + if (!m_palettesBeforeHighlight.contains(container)) { + PaletteAndFill paletteAndFill; + if (container->testAttribute(Qt::WA_SetPalette)) + paletteAndFill.first = p; + paletteAndFill.second = container->autoFillBackground(); + m_palettesBeforeHighlight.insert(container, paletteAndFill); + } + + p.setColor(backgroundRole(), p.midlight().color()); + container->setPalette(p); + container->setAutoFillBackground(true); + } +} + +QWidgetList FormWindow::widgets(QWidget *widget) const +{ + const QObjectList children = widget->children(); + if (children.empty()) + return QWidgetList(); + QWidgetList rc; + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) + if ((*it)->isWidgetType()) { + QWidget *w = qobject_cast<QWidget*>(*it); + if (isManaged(w)) + rc.push_back(w); + } + return rc; +} + +int FormWindow::toolCount() const +{ + return m_widgetStack->count(); +} + +QDesignerFormWindowToolInterface *FormWindow::tool(int index) const +{ + return m_widgetStack->tool(index); +} + +void FormWindow::registerTool(QDesignerFormWindowToolInterface *tool) +{ + Q_ASSERT(tool != 0); + + m_widgetStack->addTool(tool); + + if (m_mainContainer) + m_mainContainer->update(); +} + +void FormWindow::setCurrentTool(int index) +{ + m_widgetStack->setCurrentTool(index); +} + +int FormWindow::currentTool() const +{ + return m_widgetStack->currentIndex(); +} + +bool FormWindow::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + if (m_widgetStack == 0) + return false; + + QDesignerFormWindowToolInterface *tool = m_widgetStack->currentTool(); + if (tool == 0) + return false; + + return tool->handleEvent(widget, managedWidget, event); +} + +void FormWindow::initializeCoreTools() +{ + m_widgetEditor = new WidgetEditorTool(this); + registerTool(m_widgetEditor); +} + +void FormWindow::checkSelection() +{ + m_checkSelectionTimer->start(0); +} + +void FormWindow::checkSelectionNow() +{ + m_checkSelectionTimer->stop(); + + foreach (QWidget *widget, selectedWidgets()) { + updateSelection(widget); + + if (LayoutInfo::layoutType(core(), widget) != LayoutInfo::NoLayout) + updateChildSelections(widget); + } +} + +QString FormWindow::author() const +{ + return m_author; +} + +QString FormWindow::comment() const +{ + return m_comment; +} + +void FormWindow::setAuthor(const QString &author) +{ + m_author = author; +} + +void FormWindow::setComment(const QString &comment) +{ + m_comment = comment; +} + +void FormWindow::editWidgets() +{ + m_widgetEditor->action()->trigger(); +} + +QStringList FormWindow::resourceFiles() const +{ + return m_resourceFiles; +} + +void FormWindow::addResourceFile(const QString &path) +{ + if (!m_resourceFiles.contains(path)) { + m_resourceFiles.append(path); + setDirty(true); + emit resourceFilesChanged(); + } +} + +void FormWindow::removeResourceFile(const QString &path) +{ + if (m_resourceFiles.removeAll(path) > 0) { + setDirty(true); + emit resourceFilesChanged(); + } +} + +bool FormWindow::blockSelectionChanged(bool b) +{ + const bool blocked = m_blockSelectionChanged; + m_blockSelectionChanged = b; + return blocked; +} + +void FormWindow::editContents() +{ + const QWidgetList sel = selectedWidgets(); + if (sel.count() == 1) { + QWidget *widget = sel.first(); + + if (QAction *a = preferredEditAction(core(), widget)) + a->trigger(); + } +} + +void FormWindow::dragWidgetWithinForm(QWidget *widget, const QRect &targetGeometry, QWidget *targetContainer) +{ + const bool fromLayout = canDragWidgetInLayout(core(), widget); + const QDesignerLayoutDecorationExtension *targetDeco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), targetContainer); + const bool toLayout = targetDeco != 0; + + if (fromLayout) { + // Drag from Layout: We need to delete the widget properly to store the layout state + // Do not simplify the layout when dragging onto a layout + // as this might invalidate the insertion position if it is the same layout + DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this); + unsigned deleteFlags = DeleteWidgetCommand::DoNotUnmanage; + if (toLayout) + deleteFlags |= DeleteWidgetCommand::DoNotSimplifyLayout; + cmd->init(widget, deleteFlags); + commandHistory()->push(cmd); + } + + if (toLayout) { + // Drag from form to layout: just insert. Do not manage + insertWidget(widget, targetGeometry, targetContainer, true); + } else { + // into container without layout + if (targetContainer != widget->parent()) { // different parent + ReparentWidgetCommand *cmd = new ReparentWidgetCommand(this); + cmd->init(widget, targetContainer ); + commandHistory()->push(cmd); + } + resizeWidget(widget, targetGeometry); + selectWidget(widget, true); + widget->show(); + } +} + +static Qt::DockWidgetArea detectDropArea(QMainWindow *mainWindow, const QRect &area, const QPoint &drop) +{ + QPoint offset = area.topLeft(); + QRect rect = area; + rect.moveTopLeft(QPoint(0, 0)); + QPoint point = drop - offset; + const int x = point.x(); + const int y = point.y(); + const int w = rect.width(); + const int h = rect.height(); + + if (rect.contains(point)) { + bool topRight = false; + bool topLeft = false; + if (w * y < h * x) // top and right, oterwise bottom and left + topRight = true; + if (w * y < h * (w - x)) // top and left, otherwise bottom and right + topLeft = true; + + if (topRight && topLeft) + return Qt::TopDockWidgetArea; + else if (topRight && !topLeft) + return Qt::RightDockWidgetArea; + else if (!topRight && topLeft) + return Qt::LeftDockWidgetArea; + return Qt::BottomDockWidgetArea; + } + + if (x < 0) { + if (y < 0) + return mainWindow->corner(Qt::TopLeftCorner); + else if (y > h) + return mainWindow->corner(Qt::BottomLeftCorner); + else + return Qt::LeftDockWidgetArea; + } else if (x > w) { + if (y < 0) + return mainWindow->corner(Qt::TopRightCorner); + else if (y > h) + return mainWindow->corner(Qt::BottomRightCorner); + else + return Qt::RightDockWidgetArea; + } else { + if (y < 0) + return Qt::TopDockWidgetArea; + else + return Qt::BottomDockWidgetArea; + } + return Qt::LeftDockWidgetArea; +} + +bool FormWindow::dropDockWidget(QDesignerDnDItemInterface *item, const QPoint &global_mouse_pos) +{ + DomUI *dom_ui = item->domUi(); + + QMainWindow *mw = qobject_cast<QMainWindow *>(mainContainer()); + if (!mw) + return false; + + QDesignerResource resource(this); + const FormBuilderClipboard clipboard = resource.paste(dom_ui, mw); + if (clipboard.m_widgets.size() != 1) // multiple-paste from DomUI not supported yet + return false; + + QWidget *centralWidget = mw->centralWidget(); + QPoint localPos = centralWidget->mapFromGlobal(global_mouse_pos); + const QRect centralWidgetAreaRect = centralWidget->rect(); + Qt::DockWidgetArea area = detectDropArea(mw, centralWidgetAreaRect, localPos); + + beginCommand(tr("Drop widget")); + + clearSelection(false); + highlightWidget(mw, QPoint(0, 0), FormWindow::Restore); + + QWidget *widget = clipboard.m_widgets.first(); + + insertWidget(widget, QRect(0, 0, 1, 1), mw); + + selectWidget(widget, true); + mw->setFocus(Qt::MouseFocusReason); // in case focus was in e.g. object inspector + + core()->formWindowManager()->setActiveFormWindow(this); + mainContainer()->activateWindow(); + + QDesignerPropertySheetExtension *propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m_core->extensionManager()->extension(widget, Q_TYPEID(QDesignerPropertySheetExtension))); + if (propertySheet) { + const QString dockWidgetAreaName = QLatin1String("dockWidgetArea"); + PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(propertySheet->property(propertySheet->indexOf(dockWidgetAreaName))); + e.value = area; + QVariant v; + qVariantSetValue(v, e); + SetPropertyCommand *cmd = new SetPropertyCommand(this); + cmd->init(widget, dockWidgetAreaName, v); + m_commandHistory->push(cmd); + } + + endCommand(); + return true; +} + +bool FormWindow::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, QWidget *target, + const QPoint &global_mouse_pos) +{ + + QWidget *parent = target; + if (parent == 0) + parent = mainContainer(); + // You can only drop stuff onto the central widget of a QMainWindow + // ### generalize to use container extension + if (QMainWindow *main_win = qobject_cast<QMainWindow*>(target)) { + if (!main_win->centralWidget()) { + designerWarning(tr("A QMainWindow-based form does not contain a central widget.")); + return false; + } + const QPoint main_win_pos = main_win->mapFromGlobal(global_mouse_pos); + const QRect central_wgt_geo = main_win->centralWidget()->geometry(); + if (!central_wgt_geo.contains(main_win_pos)) + return false; + } + + QWidget *container = findContainer(parent, false); + if (container == 0) + return false; + + beginCommand(tr("Drop widget")); + + clearSelection(false); + highlightWidget(target, target->mapFromGlobal(global_mouse_pos), FormWindow::Restore); + + QPoint offset; + QDesignerDnDItemInterface *current = 0; + QDesignerFormWindowCursorInterface *c = cursor(); + foreach (QDesignerDnDItemInterface *item, item_list) { + QWidget *w = item->widget(); + if (!current) + current = item; + if (c->current() == w) { + current = item; + break; + } + } + if (current) { + QRect geom = current->decoration()->geometry(); + QPoint topLeft = container->mapFromGlobal(geom.topLeft()); + offset = designerGrid().snapPoint(topLeft) - topLeft; + } + + foreach (QDesignerDnDItemInterface *item, item_list) { + DomUI *dom_ui = item->domUi(); + QRect geometry = item->decoration()->geometry(); + Q_ASSERT(dom_ui != 0); + + geometry.moveTopLeft(container->mapFromGlobal(geometry.topLeft()) + offset); + if (item->type() == QDesignerDnDItemInterface::CopyDrop) { // from widget box or CTRL + mouse move + QWidget *widget = createWidget(dom_ui, geometry, parent); + if (!widget) { + endCommand(); + return false; + } + selectWidget(widget, true); + mainContainer()->setFocus(Qt::MouseFocusReason); // in case focus was in e.g. object inspector + } else { // same form move + QWidget *widget = item->widget(); + Q_ASSERT(widget != 0); + QDesignerFormWindowInterface *dest = findFormWindow(widget); + if (dest == this) { + dragWidgetWithinForm(widget, geometry, container); + } else { // from other form + FormWindow *source = qobject_cast<FormWindow*>(item->source()); + Q_ASSERT(source != 0); + + source->deleteWidgetList(QWidgetList() << widget); + QWidget *new_widget = createWidget(dom_ui, geometry, parent); + + selectWidget(new_widget, true); + } + } + } + + core()->formWindowManager()->setActiveFormWindow(this); + mainContainer()->activateWindow(); + endCommand(); + return true; +} + +QDir FormWindow::absoluteDir() const +{ + if (fileName().isEmpty()) + return QDir::current(); + + return QFileInfo(fileName()).absoluteDir(); +} + +void FormWindow::layoutDefault(int *margin, int *spacing) +{ + *margin = m_defaultMargin; + *spacing = m_defaultSpacing; +} + +void FormWindow::setLayoutDefault(int margin, int spacing) +{ + m_defaultMargin = margin; + m_defaultSpacing = spacing; +} + +void FormWindow::layoutFunction(QString *margin, QString *spacing) +{ + *margin = m_marginFunction; + *spacing = m_spacingFunction; +} + +void FormWindow::setLayoutFunction(const QString &margin, const QString &spacing) +{ + m_marginFunction = margin; + m_spacingFunction = spacing; +} + +QString FormWindow::pixmapFunction() const +{ + return m_pixmapFunction; +} + +void FormWindow::setPixmapFunction(const QString &pixmapFunction) +{ + m_pixmapFunction = pixmapFunction; +} + +QStringList FormWindow::includeHints() const +{ + return m_includeHints; +} + +void FormWindow::setIncludeHints(const QStringList &includeHints) +{ + m_includeHints = includeHints; +} + +QString FormWindow::exportMacro() const +{ + return m_exportMacro; +} + +void FormWindow::setExportMacro(const QString &exportMacro) +{ + m_exportMacro = exportMacro; +} + +QEditorFormBuilder *FormWindow::createFormBuilder() +{ + return new QDesignerResource(this); +} + +QWidget *FormWindow::formContainer() const +{ + return m_widgetStack->formContainer(); +} + +} // namespace + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindow.h b/tools/designer/src/components/formeditor/formwindow.h new file mode 100644 index 0000000..7e50ca2 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow.h @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_H +#define FORMWINDOW_H + +#include "formeditor_global.h" +#include <formwindowbase_p.h> + +// Qt +#include <QtCore/QHash> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QSet> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QDesignerDnDItemInterface; +class QDesignerTaskMenuExtension; +class DomConnections; + +class QWidget; +class QAction; +class QLabel; +class QTimer; +class QAction; +class QMenu; +class QUndoStack; +class QRubberBand; + +namespace qdesigner_internal { + +class FormEditor; +class FormWindowCursor; +class WidgetEditorTool; +class FormWindowWidgetStack; +class FormWindowManager; +class FormWindowDnDItem; +class SetPropertyCommand; + +class QT_FORMEDITOR_EXPORT FormWindow: public FormWindowBase +{ + Q_OBJECT + +public: + explicit FormWindow(FormEditor *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~FormWindow(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual QDesignerFormWindowCursorInterface *cursor() const; + + // Overwritten: FormWindowBase + virtual QWidget *formContainer() const; + + virtual int toolCount() const; + virtual int currentTool() const; + virtual void setCurrentTool(int index); + virtual QDesignerFormWindowToolInterface *tool(int index) const; + virtual void registerTool(QDesignerFormWindowToolInterface *tool); + + virtual QString author() const; + virtual void setAuthor(const QString &author); + + virtual QString comment() const; + virtual void setComment(const QString &comment); + + virtual void layoutDefault(int *margin, int *spacing); + virtual void setLayoutDefault(int margin, int spacing); + + virtual void layoutFunction(QString *margin, QString *spacing); + virtual void setLayoutFunction(const QString &margin, const QString &spacing); + + virtual QString pixmapFunction() const; + virtual void setPixmapFunction(const QString &pixmapFunction); + + virtual QString exportMacro() const; + virtual void setExportMacro(const QString &exportMacro); + + virtual QStringList includeHints() const; + virtual void setIncludeHints(const QStringList &includeHints); + + virtual QString fileName() const; + virtual void setFileName(const QString &fileName); + + virtual QString contents() const; + virtual void setContents(const QString &contents); + virtual void setContents(QIODevice *dev); + + virtual QDir absoluteDir() const; + + virtual void simplifySelection(QWidgetList *sel) const; + + virtual void ensureUniqueObjectName(QObject *object); + + virtual QWidget *mainContainer() const; + void setMainContainer(QWidget *mainContainer); + bool isMainContainer(const QWidget *w) const; + + QWidget *currentWidget() const; + + bool hasInsertedChildren(QWidget *w) const; + + QList<QWidget *> selectedWidgets() const; + void clearSelection(bool changePropertyDisplay=true); + bool isWidgetSelected(QWidget *w) const; + void selectWidget(QWidget *w, bool select=true); + + void selectWidgets(); + void repaintSelection(); + void updateSelection(QWidget *w); + void updateChildSelections(QWidget *w); + void raiseChildSelections(QWidget *w); + void raiseSelection(QWidget *w); + + inline const QList<QWidget *>& widgets() const { return m_widgets; } + inline int widgetCount() const { return m_widgets.count(); } + inline QWidget *widgetAt(int index) const { return m_widgets.at(index); } + + QList<QWidget *> widgets(QWidget *widget) const; + + QWidget *createWidget(DomUI *ui, const QRect &rect, QWidget *target); + + bool isManaged(QWidget *w) const; + + void manageWidget(QWidget *w); + void unmanageWidget(QWidget *w); + + inline QUndoStack *commandHistory() const + { return m_commandHistory; } + + void beginCommand(const QString &description); + void endCommand(); + + virtual bool blockSelectionChanged(bool blocked); + virtual void emitSelectionChanged(); + + bool unify(QObject *w, QString &s, bool changeIt); + + bool isDirty() const; + void setDirty(bool dirty); + + static FormWindow *findFormWindow(QWidget *w); + + virtual QWidget *containerAt(const QPoint &pos); + virtual QWidget *widgetAt(const QPoint &pos); + virtual void highlightWidget(QWidget *w, const QPoint &pos, + HighlightMode mode = Highlight); + + void updateOrderIndicators(); + + bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + QStringList resourceFiles() const; + void addResourceFile(const QString &path); + void removeResourceFile(const QString &path); + + void resizeWidget(QWidget *widget, const QRect &geometry); + + bool dropDockWidget(QDesignerDnDItemInterface *item, const QPoint &global_mouse_pos); + bool dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, QWidget *target, + const QPoint &global_mouse_pos); + + virtual QWidget *findContainer(QWidget *w, bool excludeLayout) const; + // for WidgetSelection only. + QWidget *designerWidget(QWidget *w) const; + + // Initialize and return a popup menu for a managed widget + QMenu *initializePopupMenu(QWidget *managedWidget); + + virtual void paste(PasteMode pasteMode); + virtual QEditorFormBuilder *createFormBuilder(); + + bool eventFilter(QObject *watched, QEvent *event); + +signals: + void contextMenuRequested(QMenu *menu, QWidget *widget); + +public slots: + void deleteWidgets(); + void raiseWidgets(); + void lowerWidgets(); + void copy(); + void cut(); + void paste(); + void selectAll(); + + void createLayout(int type, QWidget *container = 0); + void morphLayout(QWidget *container, int newType); + void breakLayout(QWidget *w); + + void editContents(); + +protected: + virtual QMenu *createPopupMenu(QWidget *w); + virtual void resizeEvent(QResizeEvent *e); + + void insertWidget(QWidget *w, const QRect &rect, QWidget *target, bool already_in_form = false); + +private slots: + void selectionChangedTimerDone(); + void updateDirty(); + void checkSelection(); + void checkSelectionNow(); + void slotSelectWidget(QAction *); + +private: + enum MouseState { + NoMouseState, + // Double click received + MouseDoubleClicked, + // Drawing selection rubber band rectangle + MouseDrawRubber, + // Started a move operation + MouseMoveDrag, + // Click on a widget whose parent is selected. Defer selection to release + MouseDeferredSelection + }; + MouseState m_mouseState; + QPointer<QWidget> m_lastClickedWidget; + + void init(); + void initializeCoreTools(); + + int getValue(const QRect &rect, int key, bool size) const; + int calcValue(int val, bool forward, bool snap, int snapOffset) const; + QRect applyValue(const QRect &rect, int val, int key, bool size) const; + void handleClickSelection(QWidget *managedWidget, unsigned mouseFlags); + + bool frameNeeded(QWidget *w) const; + + enum RectType { Insert, Rubber }; + + void startRectDraw(const QPoint &global, QWidget *, RectType t); + void continueRectDraw(const QPoint &global, QWidget *, RectType t); + void endRectDraw(); + + QWidget *containerAt(const QPoint &pos, QWidget *notParentOf); + + void checkPreviewGeometry(QRect &r); + + void finishContextMenu(QWidget *w, QWidget *menuParent, QContextMenuEvent *e); + + bool handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e); + bool handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + + bool isCentralWidget(QWidget *w) const; + + bool setCurrentWidget(QWidget *currentWidget); + bool trySelectWidget(QWidget *w, bool select); + + void dragWidgetWithinForm(QWidget *widget, const QRect &targetGeometry, QWidget *targetContainer); + + void setCursorToAll(const QCursor &c, QWidget *start); + + QPoint mapToForm(const QWidget *w, const QPoint &pos) const; + bool canBeBuddy(QWidget *w) const; + + QWidget *findTargetContainer(QWidget *widget) const; + + void clearMainContainer(); + + static int widgetDepth(const QWidget *w); + static bool isChildOf(const QWidget *c, const QWidget *p); + + void editWidgets(); + + void updateWidgets(); + + void handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers); + + void layoutSelection(int type); + void layoutContainer(QWidget *w, int type); + +private: + QWidget *innerContainer(QWidget *outerContainer) const; + QWidget *containerForPaste() const; + QAction *createSelectAncestorSubMenu(QWidget *w); + void selectSingleWidget(QWidget *w); + + FormEditor *m_core; + FormWindowCursor *m_cursor; + QWidget *m_mainContainer; + QWidget *m_currentWidget; + + bool m_blockSelectionChanged; + + QPoint m_rectAnchor; + QRect m_currRect; + + QWidgetList m_widgets; + QSet<QWidget*> m_insertedWidgets; + + class Selection; + Selection *m_selection; + + QPoint m_startPos; + + QUndoStack *m_commandHistory; + + QString m_fileName; + + typedef QPair<QPalette ,bool> PaletteAndFill; + typedef QMap<QWidget*, PaletteAndFill> WidgetPaletteMap; + WidgetPaletteMap m_palettesBeforeHighlight; + + QRubberBand *m_rubberBand; + + QTimer *m_selectionChangedTimer; + QTimer *m_checkSelectionTimer; + QTimer *m_geometryChangedTimer; + + int m_dirty; + int m_lastIndex; + + FormWindowWidgetStack *m_widgetStack; + WidgetEditorTool *m_widgetEditor; + + QStringList m_resourceFiles; + + QString m_comment; + QString m_author; + QString m_pixmapFunction; + int m_defaultMargin, m_defaultSpacing; + QString m_marginFunction, m_spacingFunction; + QString m_exportMacro; + QStringList m_includeHints; + + QList<SetPropertyCommand*> m_moveSelection; + int m_lastUndoIndex; + QPoint m_contextMenuPosition; + +private: + friend class WidgetEditorTool; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_H diff --git a/tools/designer/src/components/formeditor/formwindow_dnditem.cpp b/tools/designer/src/components/formeditor/formwindow_dnditem.cpp new file mode 100644 index 0000000..3af5343 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow_dnditem.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindow_dnditem.h" +#include "formwindow.h" + +#include <ui4_p.h> +#include <qdesigner_resource.h> +#include <qtresourcemodel_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtGui/QLabel> +#include <QtGui/QPixmap> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +static QWidget *decorationFromWidget(QWidget *w) +{ + QLabel *label = new QLabel(0, Qt::ToolTip); + QPixmap pm = QPixmap::grabWidget(w); + label->setPixmap(pm); + label->resize(pm.size()); + + return label; +} + +static DomUI *widgetToDom(QWidget *widget, FormWindow *form) +{ + QDesignerResource builder(form); + builder.setSaveRelative(false); + return builder.copy(FormBuilderClipboard(widget)); +} + +FormWindowDnDItem::FormWindowDnDItem(QDesignerDnDItemInterface::DropType type, FormWindow *form, + QWidget *widget, const QPoint &global_mouse_pos) + : QDesignerDnDItem(type, form) +{ + QWidget *decoration = decorationFromWidget(widget); + QPoint pos = widget->mapToGlobal(QPoint(0, 0)); + decoration->move(pos); + + init(0, widget, decoration, global_mouse_pos); +} + +DomUI *FormWindowDnDItem::domUi() const +{ + DomUI *result = QDesignerDnDItem::domUi(); + if (result != 0) + return result; + FormWindow *form = qobject_cast<FormWindow*>(source()); + if (widget() == 0 || form == 0) + return 0; + + QtResourceModel *resourceModel = form->core()->resourceModel(); + QtResourceSet *currentResourceSet = resourceModel->currentResourceSet(); + /* Short: + * We need to activate the original resourceSet associated with a form + * to properly generate the dom resource includes. + * Long: + * widgetToDom() calls copy() on QDesignerResource. It generates the + * Dom structure. In order to create DomResources properly we need to + * have the associated ResourceSet active (QDesignerResource::saveResources() + * queries the resource model for a qrc path for the given resource file: + * qrcFile = m_core->resourceModel()->qrcPath(ri->text()); + * This works only when the resource file comes from the active + * resourceSet */ + resourceModel->setCurrentResourceSet(form->resourceSet()); + + result = widgetToDom(widget(), form); + const_cast<FormWindowDnDItem*>(this)->setDomUi(result); + resourceModel->setCurrentResourceSet(currentResourceSet); + return result; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindow_dnditem.h b/tools/designer/src/components/formeditor/formwindow_dnditem.h new file mode 100644 index 0000000..c6e7479 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow_dnditem.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_DNDITEM_H +#define FORMWINDOW_DNDITEM_H + +#include <qdesigner_dnditem_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class FormWindow; + +class FormWindowDnDItem : public QDesignerDnDItem +{ +public: + FormWindowDnDItem(QDesignerDnDItemInterface::DropType type, FormWindow *form, + QWidget *widget, const QPoint &global_mouse_pos); + virtual DomUI *domUi() const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_DNDITEM_H diff --git a/tools/designer/src/components/formeditor/formwindow_widgetstack.cpp b/tools/designer/src/components/formeditor/formwindow_widgetstack.cpp new file mode 100644 index 0000000..7270628 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow_widgetstack.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindow_widgetstack.h" +#include <QtDesigner/QDesignerFormWindowToolInterface> + +#include <QtGui/QWidget> +#include <QtGui/qevent.h> +#include <QtGui/QAction> +#include <QtGui/QStackedLayout> +#include <QtGui/QVBoxLayout> + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +FormWindowWidgetStack::FormWindowWidgetStack(QObject *parent) : + QObject(parent), + m_formContainer(new QWidget), + m_formContainerLayout(new QVBoxLayout), + m_layout(new QStackedLayout) +{ + m_layout->setMargin(0); + m_layout->setSpacing(0); + m_layout->setStackingMode(QStackedLayout::StackAll); + + m_formContainerLayout->setMargin(0); + m_formContainer->setObjectName(QLatin1String("formContainer")); + m_formContainer->setLayout(m_formContainerLayout); + // System settings might have different background colors, autofill them + // (affects for example mainwindow status bars) + m_formContainer->setAutoFillBackground(true); +} + +FormWindowWidgetStack::~FormWindowWidgetStack() +{ +} + +int FormWindowWidgetStack::count() const +{ + return m_tools.count(); +} + +QDesignerFormWindowToolInterface *FormWindowWidgetStack::currentTool() const +{ + return tool(currentIndex()); +} + +void FormWindowWidgetStack::setCurrentTool(int index) +{ + const int cnt = count(); + if (index < 0 || index >= cnt) { + qDebug("FormWindowWidgetStack::setCurrentTool(): invalid index: %d", index); + return; + } + + const int cur = currentIndex(); + if (index == cur) + return; + + if (cur != -1) + m_tools.at(cur)->deactivated(); + + + m_layout->setCurrentIndex(index); + // Show the widget editor and the current tool + for (int i = 0; i < cnt; i++) + m_tools.at(i)->editor()->setVisible(i == 0 || i == index); + + QDesignerFormWindowToolInterface *tool = m_tools.at(index); + tool->activated(); + + emit currentToolChanged(index); +} + +void FormWindowWidgetStack::setSenderAsCurrentTool() +{ + QDesignerFormWindowToolInterface *tool = 0; + QAction *action = qobject_cast<QAction*>(sender()); + if (action == 0) { + qDebug("FormWindowWidgetStack::setSenderAsCurrentTool(): sender is not a QAction"); + return; + } + + foreach (QDesignerFormWindowToolInterface *t, m_tools) { + if (action == t->action()) { + tool = t; + break; + } + } + + if (tool == 0) { + qDebug("FormWindowWidgetStack::setSenderAsCurrentTool(): unknown tool"); + return; + } + + setCurrentTool(tool); +} + +int FormWindowWidgetStack::indexOf(QDesignerFormWindowToolInterface *tool) const +{ + return m_tools.indexOf(tool); +} + +void FormWindowWidgetStack::setCurrentTool(QDesignerFormWindowToolInterface *tool) +{ + int index = indexOf(tool); + if (index == -1) { + qDebug("FormWindowWidgetStack::setCurrentTool(): unknown tool"); + return; + } + + setCurrentTool(index); +} + +void FormWindowWidgetStack::setMainContainer(QWidget *w) +{ + // This code is triggered once by the formwindow and + // by integrations doing "revert to saved". Anything changing? + const int previousCount = m_formContainerLayout->count(); + QWidget *previousMainContainer = previousCount ? m_formContainerLayout->itemAt(0)->widget() : static_cast<QWidget*>(0); + if (previousMainContainer == w) + return; + // Swap + if (previousCount) + delete m_formContainerLayout->takeAt(0); + if (w) + m_formContainerLayout->addWidget(w); +} + +void FormWindowWidgetStack::addTool(QDesignerFormWindowToolInterface *tool) +{ + if (QWidget *w = tool->editor()) { + w->setVisible(m_layout->count() == 0); // Initially only form editor is visible + m_layout->addWidget(w); + } else { + // The form editor might not have a tool initially, use dummy. Assert on anything else + Q_ASSERT(m_tools.empty()); + m_layout->addWidget(m_formContainer); + } + + m_tools.append(tool); + + connect(tool->action(), SIGNAL(triggered()), this, SLOT(setSenderAsCurrentTool())); +} + +QDesignerFormWindowToolInterface *FormWindowWidgetStack::tool(int index) const +{ + if (index < 0 || index >= count()) + return 0; + + return m_tools.at(index); +} + +int FormWindowWidgetStack::currentIndex() const +{ + return m_layout->currentIndex(); +} + +QWidget *FormWindowWidgetStack::defaultEditor() const +{ + if (m_tools.isEmpty()) + return 0; + + return m_tools.at(0)->editor(); +} + +QLayout *FormWindowWidgetStack::layout() const +{ + return m_layout; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindow_widgetstack.h b/tools/designer/src/components/formeditor/formwindow_widgetstack.h new file mode 100644 index 0000000..92323c5 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindow_widgetstack.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_WIDGETSTACK_H +#define FORMWINDOW_WIDGETSTACK_H + +#include "formeditor_global.h" + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowToolInterface; + +class QStackedLayout; +class QVBoxLayout; +class QWidget; + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormWindowWidgetStack: public QObject +{ + Q_OBJECT +public: + FormWindowWidgetStack(QObject *parent = 0); + virtual ~FormWindowWidgetStack(); + + QLayout *layout() const; + + int count() const; + QDesignerFormWindowToolInterface *tool(int index) const; + QDesignerFormWindowToolInterface *currentTool() const; + int currentIndex() const; + int indexOf(QDesignerFormWindowToolInterface *tool) const; + + void setMainContainer(QWidget *w = 0); + + // Return the widget containing the form which can be used to apply embedded design settings to. + // These settings should not affect the other editing tools. + QWidget *formContainer() const { return m_formContainer; } + +signals: + void currentToolChanged(int index); + +public slots: + void addTool(QDesignerFormWindowToolInterface *tool); + void setCurrentTool(QDesignerFormWindowToolInterface *tool); + void setCurrentTool(int index); + void setSenderAsCurrentTool(); + +protected: + QWidget *defaultEditor() const; + +private: + QList<QDesignerFormWindowToolInterface*> m_tools; + QWidget *m_formContainer; + QVBoxLayout *m_formContainerLayout; + QStackedLayout *m_layout; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_WIDGETSTACK_H diff --git a/tools/designer/src/components/formeditor/formwindowcursor.cpp b/tools/designer/src/components/formeditor/formwindowcursor.cpp new file mode 100644 index 0000000..5b4aee1 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowcursor.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::FormWindowCursor +*/ + +#include "formwindowcursor.h" +#include "formwindow.h" + +// sdk +#include <QtDesigner/propertysheet.h> +#include <QtDesigner/QExtensionManager> +#include <qdesigner_propertycommand_p.h> + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +FormWindowCursor::FormWindowCursor(FormWindow *fw, QObject *parent) + : QObject(parent), + m_formWindow(fw) +{ + update(); + connect(fw, SIGNAL(changed()), this, SLOT(update())); +} + +FormWindowCursor::~FormWindowCursor() +{ +} + +QDesignerFormWindowInterface *FormWindowCursor::formWindow() const +{ + return m_formWindow; +} + +bool FormWindowCursor::movePosition(MoveOperation op, MoveMode mode) +{ + if (widgetCount() == 0) + return false; + + int iterator = position(); + + if (mode == MoveAnchor) + m_formWindow->clearSelection(false); + + switch (op) { + case Next: + ++iterator; + if (iterator >= widgetCount()) + iterator = 0; + + m_formWindow->selectWidget(m_formWindow->widgetAt(iterator), true); + return true; + + case Prev: + --iterator; + if (iterator < 0) + iterator = widgetCount() - 1; + + if (iterator < 0) + return false; + + m_formWindow->selectWidget(m_formWindow->widgetAt(iterator), true); + return true; + + default: + return false; + } +} + +int FormWindowCursor::position() const +{ + const int index = m_formWindow->widgets().indexOf(current()); + return index == -1 ? 0 : index; +} + +void FormWindowCursor::setPosition(int pos, MoveMode mode) +{ + if (!widgetCount()) + return; + + if (mode == MoveAnchor) + m_formWindow->clearSelection(false); + + if (pos >= widgetCount()) + pos = 0; + + m_formWindow->selectWidget(m_formWindow->widgetAt(pos), true); +} + +QWidget *FormWindowCursor::current() const +{ + return m_formWindow->currentWidget(); +} + +bool FormWindowCursor::hasSelection() const +{ + return !m_formWindow->selectedWidgets().isEmpty(); +} + +int FormWindowCursor::selectedWidgetCount() const +{ + int N = m_formWindow->selectedWidgets().count(); + return N ? N : 1; +} + +QWidget *FormWindowCursor::selectedWidget(int index) const +{ + return hasSelection() + ? m_formWindow->selectedWidgets().at(index) + : m_formWindow->mainContainer(); +} + +void FormWindowCursor::update() +{ + // ### todo +} + +int FormWindowCursor::widgetCount() const +{ + return m_formWindow->widgetCount(); +} + +QWidget *FormWindowCursor::widget(int index) const +{ + return m_formWindow->widgetAt(index); +} + +void FormWindowCursor::setProperty(const QString &name, const QVariant &value) +{ + + // build selection + const int N = selectedWidgetCount(); + Q_ASSERT(N); + + SetPropertyCommand::ObjectList selection; + for (int i=0; i<N; ++i) + selection.push_back(selectedWidget(i)); + + + SetPropertyCommand* setPropertyCommand = new SetPropertyCommand(m_formWindow); + if (setPropertyCommand->init(selection, name, value, current())) { + m_formWindow->commandHistory()->push(setPropertyCommand); + } else { + delete setPropertyCommand; + qDebug() << "Unable to set property " << name << '.'; + } +} + +void FormWindowCursor::setWidgetProperty(QWidget *widget, const QString &name, const QVariant &value) +{ + SetPropertyCommand *cmd = new SetPropertyCommand(m_formWindow); + if (cmd->init(widget, name, value)) { + m_formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "Unable to set property " << name << '.'; + } +} + +void FormWindowCursor::resetWidgetProperty(QWidget *widget, const QString &name) +{ + ResetPropertyCommand *cmd = new ResetPropertyCommand(m_formWindow); + if (cmd->init(widget, name)) { + m_formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "Unable to reset property " << name << '.'; + } +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindowcursor.h b/tools/designer/src/components/formeditor/formwindowcursor.h new file mode 100644 index 0000000..7167432 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowcursor.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWCURSOR_H +#define FORMWINDOWCURSOR_H + +#include "formeditor_global.h" +#include "formwindow.h" +#include <QtDesigner/QDesignerFormWindowCursorInterface> + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormWindowCursor: public QObject, public QDesignerFormWindowCursorInterface +{ + Q_OBJECT +public: + explicit FormWindowCursor(FormWindow *fw, QObject *parent = 0); + virtual ~FormWindowCursor(); + + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual bool movePosition(MoveOperation op, MoveMode mode); + + virtual int position() const; + virtual void setPosition(int pos, MoveMode mode); + + virtual QWidget *current() const; + + virtual int widgetCount() const; + virtual QWidget *widget(int index) const; + + virtual bool hasSelection() const; + virtual int selectedWidgetCount() const; + virtual QWidget *selectedWidget(int index) const; + + virtual void setProperty(const QString &name, const QVariant &value); + virtual void setWidgetProperty(QWidget *widget, const QString &name, const QVariant &value); + virtual void resetWidgetProperty(QWidget *widget, const QString &name); + +public slots: + void update(); + +private: + FormWindow *m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOWCURSOR_H diff --git a/tools/designer/src/components/formeditor/formwindowmanager.cpp b/tools/designer/src/components/formeditor/formwindowmanager.cpp new file mode 100644 index 0000000..69fb4a3 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowmanager.cpp @@ -0,0 +1,1020 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::FormWindowManager +*/ + +// components/formeditor +#include "formwindowmanager.h" +#include "formwindow_dnditem.h" +#include "formwindow.h" +#include "formeditor.h" +#include "widgetselection.h" +#include "previewactiongroup.h" +#include "formwindowsettings.h" + +// shared +#include <widgetdatabase_p.h> +#include <iconloader_p.h> +#include <connectionedit_p.h> +#include <qtresourcemodel_p.h> +#include <qdesigner_dnditem_p.h> +#include <qdesigner_command_p.h> +#include <qdesigner_command2_p.h> +#include <layoutinfo_p.h> +#include <qlayout_widget_p.h> +#include <qdesigner_objectinspector_p.h> +#include <actioneditor_p.h> +#include <shared_settings_p.h> +#include <previewmanager_p.h> +#include <abstractdialoggui_p.h> +#include <widgetfactory_p.h> +#include <spacer_widget_p.h> + +// SDK +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerLanguageExtension> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerWidgetBoxInterface> +#include <QtDesigner/QDesignerIntegrationInterface> + +#include <QtGui/QUndoGroup> +#include <QtGui/QAction> +#include <QtGui/QSplitter> +#include <QtGui/QMouseEvent> +#include <QtGui/QApplication> +#include <QtGui/QSizeGrip> +#include <QtGui/QClipboard> +#include <QtGui/QMdiArea> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QDesktopWidget> +#include <QtGui/QMessageBox> + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace { + enum { debugFWM = 0 }; +} + +static inline QString whatsThisFrom(const QString &str) { /// ### implement me! + return str; +} + +// find the first child of w in a sequence +template <class Iterator> +static inline Iterator findFirstChildOf(Iterator it,Iterator end, const QWidget *w) +{ + for (;it != end; ++it) { + if (w->isAncestorOf(*it)) + return it; + } + return it; +} + +namespace qdesigner_internal { + +FormWindowManager::FormWindowManager(QDesignerFormEditorInterface *core, QObject *parent) : + QDesignerFormWindowManager(parent), + m_core(core), + m_activeFormWindow(0), + m_previewManager(new PreviewManager(PreviewManager::SingleFormNonModalPreview, this)), + m_createLayoutContext(LayoutContainer), + m_morphLayoutContainer(0), + m_actionGroupPreviewInStyle(0), + m_actionShowFormWindowSettingsDialog(0) +{ + setupActions(); + qApp->installEventFilter(this); +} + +FormWindowManager::~FormWindowManager() +{ + qDeleteAll(m_formWindows); +} + +QDesignerFormEditorInterface *FormWindowManager::core() const +{ + return m_core; +} + +QDesignerFormWindowInterface *FormWindowManager::activeFormWindow() const +{ + return m_activeFormWindow; +} + +int FormWindowManager::formWindowCount() const +{ + return m_formWindows.size(); +} + +QDesignerFormWindowInterface *FormWindowManager::formWindow(int index) const +{ + return m_formWindows.at(index); +} + +bool FormWindowManager::eventFilter(QObject *o, QEvent *e) +{ + if (!o->isWidgetType()) + return false; + + // If we don't have an active form, we only listen for WindowActivate to speed up integrations + const QEvent::Type eventType = e->type(); + if (m_activeFormWindow == 0 && eventType != QEvent::WindowActivate) + return false; + + switch (eventType) { // Uninteresting events + case QEvent::Create: + case QEvent::Destroy: + case QEvent::AccessibilityDescription: + case QEvent::AccessibilityHelp: + case QEvent::AccessibilityPrepare: + case QEvent::ActionAdded: + case QEvent::ActionChanged: + case QEvent::ActionRemoved: + case QEvent::ChildAdded: + case QEvent::ChildPolished: + case QEvent::ChildRemoved: + case QEvent::Clipboard: + case QEvent::ContentsRectChange: + case QEvent::DeferredDelete: + case QEvent::FileOpen: + case QEvent::LanguageChange: + case QEvent::MetaCall: + case QEvent::ModifiedChange: + case QEvent::Paint: + case QEvent::PaletteChange: + case QEvent::ParentAboutToChange: + case QEvent::ParentChange: + case QEvent::Polish: + case QEvent::PolishRequest: + case QEvent::QueryWhatsThis: + case QEvent::StatusTip: + case QEvent::StyleChange: + case QEvent::Timer: + case QEvent::ToolBarChange: + case QEvent::ToolTip: + case QEvent::WhatsThis: + case QEvent::WhatsThisClicked: + case QEvent::DynamicPropertyChange: + case QEvent::HoverEnter: + case QEvent::HoverLeave: + case QEvent::HoverMove: + return false; + default: + break; + } + + QWidget *widget = static_cast<QWidget*>(o); + + if (qobject_cast<WidgetHandle*>(widget)) { // ### remove me + return false; + } + + FormWindow *fw = FormWindow::findFormWindow(widget); + if (fw == 0) { + return false; + } + + if (QWidget *managedWidget = findManagedWidget(fw, widget)) { + // Prevent MDI and QWorkspace subwindows from being closed by clicking at the title bar + if (managedWidget != widget && eventType == QEvent::Close) { + e->ignore(); + return true; + } + switch (eventType) { + + case QEvent::WindowActivate: { + if (fw->parentWidget()->isWindow() && fw->isMainContainer(managedWidget) && activeFormWindow() != fw) { + setActiveFormWindow(fw); + } + } break; + + case QEvent::WindowDeactivate: { + if (o == fw && o == activeFormWindow()) + fw->repaintSelection(); + } break; + + case QEvent::KeyPress: { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->key() == Qt::Key_Escape) { + ke->accept(); + return true; + } + } + // don't break... + // Embedded Design: Drop on different form: Make sure the right form + // window/device is active before having the widget created by the factory + case QEvent::Drop: + if (activeFormWindow() != fw) + setActiveFormWindow(fw); + // don't break... + default: { + if (fw->handleEvent(widget, managedWidget, e)) { + return true; + } + } break; + + } // end switch + } + + return false; +} + +void FormWindowManager::addFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast<FormWindow*>(w); + if (!formWindow || m_formWindows.contains(formWindow)) + return; + + connect(formWindow, SIGNAL(selectionChanged()), this, SLOT(slotUpdateActions())); + connect(formWindow->commandHistory(), SIGNAL(indexChanged(int)), this, SLOT(slotUpdateActions())); + connect(formWindow, SIGNAL(toolChanged(int)), this, SLOT(slotUpdateActions())); + + if (ActionEditor *ae = qobject_cast<ActionEditor *>(m_core->actionEditor())) + connect(w, SIGNAL(mainContainerChanged(QWidget*)), ae, SLOT(mainContainerChanged())); + if (QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(m_core->objectInspector())) + connect(w, SIGNAL(mainContainerChanged(QWidget*)), oi, SLOT(mainContainerChanged())); + + m_formWindows.append(formWindow); + emit formWindowAdded(formWindow); +} + +void FormWindowManager::removeFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast<FormWindow*>(w); + + int idx = m_formWindows.indexOf(formWindow); + if (!formWindow || idx == -1) + return; + + formWindow->disconnect(this); + m_formWindows.removeAt(idx); + emit formWindowRemoved(formWindow); + + if (formWindow == m_activeFormWindow) + setActiveFormWindow(0); + + if (m_formWindows.size() == 0 + && m_core->widgetBox()) { + // Make sure that widget box is enabled by default + m_core->widgetBox()->setEnabled(true); + } + +} + +void FormWindowManager::setActiveFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast<FormWindow*>(w); + + if (formWindow == m_activeFormWindow) + return; + + FormWindow *old = m_activeFormWindow; + + m_activeFormWindow = formWindow; + + QtResourceSet *resourceSet = 0; + if (formWindow) + resourceSet = formWindow->resourceSet(); + m_core->resourceModel()->setCurrentResourceSet(resourceSet); + + slotUpdateActions(); + + if (m_activeFormWindow) { + m_activeFormWindow->repaintSelection(); + if (old) + old->repaintSelection(); + } + + emit activeFormWindowChanged(m_activeFormWindow); + + if (m_activeFormWindow) { + m_activeFormWindow->emitSelectionChanged(); + m_activeFormWindow->commandHistory()->setActive(); + // Trigger setActiveSubWindow on mdi area unless we are in toplevel mode + QMdiSubWindow *mdiSubWindow = 0; + if (QWidget *formwindow = m_activeFormWindow->parentWidget()) { + mdiSubWindow = qobject_cast<QMdiSubWindow *>(formwindow->parentWidget()); + } + if (mdiSubWindow) { + for (QWidget *parent = mdiSubWindow->parentWidget(); parent; parent = parent->parentWidget()) { + if (QMdiArea *mdiArea = qobject_cast<QMdiArea*>(parent)) { + mdiArea->setActiveSubWindow(mdiSubWindow); + break; + } + } + } + } +} + +void FormWindowManager::closeAllPreviews() +{ + m_previewManager->closeAllPreviews(); +} + +QWidget *FormWindowManager::findManagedWidget(FormWindow *fw, QWidget *w) +{ + while (w && w != fw) { + if (fw->isManaged(w)) + break; + w = w->parentWidget(); + } + return w; +} + +void FormWindowManager::setupActions() +{ + m_actionCut = new QAction(createIconSet(QLatin1String("editcut.png")), tr("Cu&t"), this); + m_actionCut->setObjectName(QLatin1String("__qt_cut_action")); + m_actionCut->setShortcut(QKeySequence::Cut); + m_actionCut->setStatusTip(tr("Cuts the selected widgets and puts them on the clipboard")); + m_actionCut->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Cut"))); + connect(m_actionCut, SIGNAL(triggered()), this, SLOT(slotActionCutActivated())); + m_actionCut->setEnabled(false); + + m_actionCopy = new QAction(createIconSet(QLatin1String("editcopy.png")), tr("&Copy"), this); + m_actionCopy->setObjectName(QLatin1String("__qt_copy_action")); + m_actionCopy->setShortcut(QKeySequence::Copy); + m_actionCopy->setStatusTip(tr("Copies the selected widgets to the clipboard")); + m_actionCopy->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Copy"))); + connect(m_actionCopy, SIGNAL(triggered()), this, SLOT(slotActionCopyActivated())); + m_actionCopy->setEnabled(false); + + m_actionPaste = new QAction(createIconSet(QLatin1String("editpaste.png")), tr("&Paste"), this); + m_actionPaste->setObjectName(QLatin1String("__qt_paste_action")); + m_actionPaste->setShortcut(QKeySequence::Paste); + m_actionPaste->setStatusTip(tr("Pastes the clipboard's contents")); + m_actionPaste->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Paste"))); + connect(m_actionPaste, SIGNAL(triggered()), this, SLOT(slotActionPasteActivated())); + m_actionPaste->setEnabled(false); + + m_actionDelete = new QAction(tr("&Delete"), this); + m_actionDelete->setObjectName(QLatin1String("__qt_delete_action")); + m_actionDelete->setStatusTip(tr("Deletes the selected widgets")); + m_actionDelete->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Delete"))); + connect(m_actionDelete, SIGNAL(triggered()), this, SLOT(slotActionDeleteActivated())); + m_actionDelete->setEnabled(false); + + m_actionSelectAll = new QAction(tr("Select &All"), this); + m_actionSelectAll->setObjectName(QLatin1String("__qt_select_all_action")); + m_actionSelectAll->setShortcut(QKeySequence::SelectAll); + m_actionSelectAll->setStatusTip(tr("Selects all widgets")); + m_actionSelectAll->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Select All"))); + connect(m_actionSelectAll, SIGNAL(triggered()), this, SLOT(slotActionSelectAllActivated())); + m_actionSelectAll->setEnabled(false); + + m_actionRaise = new QAction(createIconSet(QLatin1String("editraise.png")), tr("Bring to &Front"), this); + m_actionRaise->setObjectName(QLatin1String("__qt_raise_action")); + m_actionRaise->setShortcut(Qt::CTRL + Qt::Key_L); + m_actionRaise->setStatusTip(tr("Raises the selected widgets")); + m_actionRaise->setWhatsThis(tr("Raises the selected widgets")); + connect(m_actionRaise, SIGNAL(triggered()), this, SLOT(slotActionRaiseActivated())); + m_actionRaise->setEnabled(false); + + m_actionLower = new QAction(createIconSet(QLatin1String("editlower.png")), tr("Send to &Back"), this); + m_actionLower->setObjectName(QLatin1String("__qt_lower_action")); + m_actionLower->setShortcut(Qt::CTRL + Qt::Key_K); + m_actionLower->setStatusTip(tr("Lowers the selected widgets")); + m_actionLower->setWhatsThis(tr("Lowers the selected widgets")); + connect(m_actionLower, SIGNAL(triggered()), this, SLOT(slotActionLowerActivated())); + m_actionLower->setEnabled(false); + + m_actionAdjustSize = new QAction(createIconSet(QLatin1String("adjustsize.png")), tr("Adjust &Size"), this); + m_actionAdjustSize->setObjectName(QLatin1String("__qt_adjust_size_action")); + m_actionAdjustSize->setShortcut(Qt::CTRL + Qt::Key_J); + m_actionAdjustSize->setStatusTip(tr("Adjusts the size of the selected widget")); + m_actionAdjustSize->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Adjust Size"))); + connect(m_actionAdjustSize, SIGNAL(triggered()), this, SLOT(slotActionAdjustSizeActivated())); + m_actionAdjustSize->setEnabled(false); + + + m_actionHorizontalLayout = new QAction(createIconSet(QLatin1String("edithlayout.png")), tr("Lay Out &Horizontally"), this); + m_actionHorizontalLayout->setObjectName(QLatin1String("__qt_horizontal_layout_action")); + m_actionHorizontalLayout->setShortcut(Qt::CTRL + Qt::Key_1); + m_actionHorizontalLayout->setStatusTip(tr("Lays out the selected widgets horizontally")); + m_actionHorizontalLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Horizontally"))); + m_actionHorizontalLayout->setData(LayoutInfo::HBox); + m_actionHorizontalLayout->setEnabled(false); + connect(m_actionHorizontalLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionVerticalLayout = new QAction(createIconSet(QLatin1String("editvlayout.png")), tr("Lay Out &Vertically"), this); + m_actionVerticalLayout->setObjectName(QLatin1String("__qt_vertical_layout_action")); + m_actionVerticalLayout->setShortcut(Qt::CTRL + Qt::Key_2); + m_actionVerticalLayout->setStatusTip(tr("Lays out the selected widgets vertically")); + m_actionVerticalLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Vertically"))); + m_actionVerticalLayout->setData(LayoutInfo::VBox); + m_actionVerticalLayout->setEnabled(false); + connect(m_actionVerticalLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + QAction *actionFormLayout = new QAction(createIconSet(QLatin1String("editform.png")), tr("Lay Out in a &Form Layout"), this); + actionFormLayout->setObjectName(QLatin1String("__qt_form_layout_action")); + actionFormLayout->setShortcut(Qt::CTRL + Qt::Key_6); + actionFormLayout->setStatusTip(tr("Lays out the selected widgets in a form layout")); + actionFormLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out in a Form"))); + actionFormLayout->setData(LayoutInfo::Form); + actionFormLayout->setEnabled(false); + setActionFormLayout(actionFormLayout); + connect(actionFormLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionGridLayout = new QAction(createIconSet(QLatin1String("editgrid.png")), tr("Lay Out in a &Grid"), this); + m_actionGridLayout->setObjectName(QLatin1String("__qt_grid_layout_action")); + m_actionGridLayout->setShortcut(Qt::CTRL + Qt::Key_5); + m_actionGridLayout->setStatusTip(tr("Lays out the selected widgets in a grid")); + m_actionGridLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out in a Grid"))); + m_actionGridLayout->setData(LayoutInfo::Grid); + m_actionGridLayout->setEnabled(false); + connect(m_actionGridLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionSplitHorizontal = new QAction(createIconSet(QLatin1String("edithlayoutsplit.png")), + tr("Lay Out Horizontally in S&plitter"), this); + m_actionSplitHorizontal->setObjectName(QLatin1String("__qt_split_horizontal_action")); + m_actionSplitHorizontal->setShortcut(Qt::CTRL + Qt::Key_3); + m_actionSplitHorizontal->setStatusTip(tr("Lays out the selected widgets horizontally in a splitter")); + m_actionSplitHorizontal->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Horizontally in Splitter"))); + m_actionSplitHorizontal->setData(LayoutInfo::HSplitter); + m_actionSplitHorizontal->setEnabled(false); + connect(m_actionSplitHorizontal, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionSplitVertical = new QAction(createIconSet(QLatin1String("editvlayoutsplit.png")), + tr("Lay Out Vertically in Sp&litter"), this); + m_actionSplitVertical->setObjectName(QLatin1String("__qt_split_vertical_action")); + m_actionSplitVertical->setShortcut(Qt::CTRL + Qt::Key_4); + m_actionSplitVertical->setStatusTip(tr("Lays out the selected widgets vertically in a splitter")); + m_actionSplitVertical->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Vertically in Splitter"))); + connect(m_actionSplitVertical, SIGNAL(triggered()), this, SLOT(createLayout())); + m_actionSplitVertical->setData(LayoutInfo::VSplitter); + + m_actionSplitVertical->setEnabled(false); + + m_actionBreakLayout = new QAction(createIconSet(QLatin1String("editbreaklayout.png")), tr("&Break Layout"), this); + m_actionBreakLayout->setObjectName(QLatin1String("__qt_break_layout_action")); + m_actionBreakLayout->setShortcut(Qt::CTRL + Qt::Key_0); + m_actionBreakLayout->setStatusTip(tr("Breaks the selected layout")); + m_actionBreakLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Break Layout"))); + connect(m_actionBreakLayout, SIGNAL(triggered()), this, SLOT(slotActionBreakLayoutActivated())); + m_actionBreakLayout->setEnabled(false); + + QAction *simplifyLayoutAction = new QAction(tr("Si&mplify Grid Layout"), this); + simplifyLayoutAction->setObjectName(QLatin1String("__qt_simplify_layout_action")); + simplifyLayoutAction->setStatusTip(tr("Removes empty columns and rows")); + simplifyLayoutAction->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Simplify Layout"))); + connect(simplifyLayoutAction, SIGNAL(triggered()), this, SLOT(slotActionSimplifyLayoutActivated())); + simplifyLayoutAction->setEnabled(false); + setActionSimplifyLayout(simplifyLayoutAction); + + m_actionDefaultPreview = new QAction(tr("&Preview..."), this); + m_actionDefaultPreview->setObjectName(QLatin1String("__qt_default_preview_action")); + m_actionDefaultPreview->setStatusTip(tr("Preview current form")); + m_actionDefaultPreview->setWhatsThis(whatsThisFrom(QLatin1String("Form|Preview"))); + connect(m_actionDefaultPreview, SIGNAL(triggered()), + this, SLOT(slotActionDefaultPreviewActivated())); + + m_undoGroup = new QUndoGroup(this); + + m_actionUndo = m_undoGroup->createUndoAction(this); + m_actionUndo->setEnabled(false); + m_actionUndo->setIcon(createIconSet(QLatin1String("undo.png"))); + m_actionRedo = m_undoGroup->createRedoAction(this); + m_actionRedo->setEnabled(false); + m_actionRedo->setIcon(createIconSet(QLatin1String("redo.png"))); + + m_actionShowFormWindowSettingsDialog = new QAction(tr("Form &Settings..."), this); + m_actionShowFormWindowSettingsDialog->setObjectName(QLatin1String("__qt_form_settings_action")); + connect(m_actionShowFormWindowSettingsDialog, SIGNAL(triggered()), this, SLOT(slotActionShowFormWindowSettingsDialog())); + m_actionShowFormWindowSettingsDialog->setEnabled(false); +} + +void FormWindowManager::slotActionCutActivated() +{ + m_activeFormWindow->cut(); +} + +void FormWindowManager::slotActionCopyActivated() +{ + m_activeFormWindow->copy(); + slotUpdateActions(); +} + +void FormWindowManager::slotActionPasteActivated() +{ + m_activeFormWindow->paste(); +} + +void FormWindowManager::slotActionDeleteActivated() +{ + m_activeFormWindow->deleteWidgets(); +} + +void FormWindowManager::slotActionLowerActivated() +{ + m_activeFormWindow->lowerWidgets(); +} + +void FormWindowManager::slotActionRaiseActivated() +{ + m_activeFormWindow->raiseWidgets(); +} + +static inline QWidget *findLayoutContainer(const FormWindow *fw) +{ + QList<QWidget*> l(fw->selectedWidgets()); + fw->simplifySelection(&l); + return l.empty() ? fw->mainContainer() : l.front(); +} + +void FormWindowManager::createLayout() +{ + QAction *a = qobject_cast<QAction *>(sender()); + if (!a) + return; + const int type = a->data().toInt(); + switch (m_createLayoutContext) { + case LayoutContainer: + // Cannot create a splitter on a container + if (type != LayoutInfo::HSplitter && type != LayoutInfo::VSplitter) + m_activeFormWindow->createLayout(type, findLayoutContainer(m_activeFormWindow)); + break; + case LayoutSelection: + m_activeFormWindow->createLayout(type); + break; + case MorphLayout: + m_activeFormWindow->morphLayout(m_morphLayoutContainer, type); + break; + } +} + +void FormWindowManager::slotActionBreakLayoutActivated() +{ + const QList<QWidget *> layouts = layoutsToBeBroken(); + if (layouts.isEmpty()) + return; + + if (debugFWM) { + qDebug() << "slotActionBreakLayoutActivated: " << layouts.size(); + foreach (QWidget *w, layouts) { + qDebug() << w; + } + } + + m_activeFormWindow->beginCommand(tr("Break Layout")); + foreach (QWidget *layout, layouts) { + m_activeFormWindow->breakLayout(layout); + } + m_activeFormWindow->endCommand(); +} + +void FormWindowManager::slotActionSimplifyLayoutActivated() +{ + Q_ASSERT(m_activeFormWindow != 0); + QWidgetList selectedWidgets = m_activeFormWindow->selectedWidgets(); + m_activeFormWindow->simplifySelection(&selectedWidgets); + if (selectedWidgets.size() != 1) + return; + SimplifyLayoutCommand *cmd = new SimplifyLayoutCommand(m_activeFormWindow); + if (cmd->init(selectedWidgets.front())) { + m_activeFormWindow->commandHistory()->push(cmd); + } else { + delete cmd; + } +} + +void FormWindowManager::slotActionAdjustSizeActivated() +{ + Q_ASSERT(m_activeFormWindow != 0); + + m_activeFormWindow->beginCommand(tr("Adjust Size")); + + QList<QWidget*> selectedWidgets = m_activeFormWindow->selectedWidgets(); + m_activeFormWindow->simplifySelection(&selectedWidgets); + + if (selectedWidgets.isEmpty()) { + Q_ASSERT(m_activeFormWindow->mainContainer() != 0); + selectedWidgets.append(m_activeFormWindow->mainContainer()); + } + + // Always count the main container as unlaid-out + foreach (QWidget *widget, selectedWidgets) { + bool unlaidout = LayoutInfo::layoutType(core(), widget->parentWidget()) == LayoutInfo::NoLayout; + bool isMainContainer = m_activeFormWindow->isMainContainer(widget); + + if (unlaidout || isMainContainer) { + AdjustWidgetSizeCommand *cmd = new AdjustWidgetSizeCommand(m_activeFormWindow); + cmd->init(widget); + m_activeFormWindow->commandHistory()->push(cmd); + } + } + + m_activeFormWindow->endCommand(); +} + +void FormWindowManager::slotActionSelectAllActivated() +{ + m_activeFormWindow->selectAll(); +} + +void FormWindowManager::slotActionDefaultPreviewActivated() +{ + slotActionGroupPreviewInStyle(QString(), -1); +} + +void FormWindowManager::slotActionGroupPreviewInStyle(const QString &style, int deviceProfileIndex) +{ + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return; + + QString errorMessage; + if (!m_previewManager->showPreview(fw, style, deviceProfileIndex, &errorMessage)) { + const QString title = tr("Could not create form preview", "Title of warning message box"); + core()->dialogGui()->message(fw, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Warning, + title, errorMessage); + } +} + +// The user might click on a layout child or the actual layout container. +QWidgetList FormWindowManager::layoutsToBeBroken(QWidget *w) const +{ + if (!w) + return QList<QWidget *>(); + + if (debugFWM) + qDebug() << "layoutsToBeBroken: " << w; + + QWidget *parent = w->parentWidget(); + if (m_activeFormWindow->isMainContainer(w)) + parent = 0; + + QWidget *widget = core()->widgetFactory()->containerOfWidget(w); + + // maybe we want to remove following block + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(widget)); + if (!item) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Don't have an item, recursing for parent"; + return layoutsToBeBroken(parent); + } + + const bool layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(widget)); + + if (!layoutContainer) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Not a container, recursing for parent"; + return layoutsToBeBroken(parent); + } + + QLayout *widgetLayout = widget->layout(); + QLayout *managedLayout = LayoutInfo::managedLayout(m_core, widgetLayout); + if (!managedLayout) { + if (qobject_cast<const QSplitter *>(widget)) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Splitter special"; + QList<QWidget *> list = layoutsToBeBroken(parent); + list.append(widget); + return list; + } + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container but doesn't have a managed layout (has an internal layout), returning 0"; + return QList<QWidget *>(); + } + + if (managedLayout) { + QList<QWidget *> list; + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container and has a layout"; + if (qobject_cast<const QLayoutWidget *>(widget)) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: red layout special case"; + list = layoutsToBeBroken(parent); + } + list.append(widget); + return list; + } + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container but doesn't have a layout at all, returning 0"; + return QList<QWidget *>(); + +} + +QMap<QWidget *, bool> FormWindowManager::getUnsortedLayoutsToBeBroken(bool firstOnly) const +{ + // Return a set of layouts to be broken. + QMap<QWidget *, bool> layouts; + + QList<QWidget *> selection = m_activeFormWindow->selectedWidgets(); + if (selection.isEmpty() && m_activeFormWindow->mainContainer()) + selection.append(m_activeFormWindow->mainContainer()); + + const QList<QWidget *>::const_iterator scend = selection.constEnd(); + for (QList<QWidget *>::const_iterator sit = selection.constBegin(); sit != scend; ++sit) { + // find all layouts + const QList<QWidget *> list = layoutsToBeBroken(*sit); + if (!list.empty()) { + const QList<QWidget *>::const_iterator lbcend = list.constEnd(); + for (QList<QWidget *>::const_iterator lbit = list.constBegin(); lbit != lbcend; ++lbit) { + layouts.insert(*lbit, true); + } + if (firstOnly) + return layouts; + } + } + return layouts; +} + +bool FormWindowManager::hasLayoutsToBeBroken() const +{ + // Quick check for layouts to be broken + return !getUnsortedLayoutsToBeBroken(true).isEmpty(); +} + +QWidgetList FormWindowManager::layoutsToBeBroken() const +{ + // Get all layouts. This is a list of all 'red' layouts (QLayoutWidgets) + // up to the first 'real' widget with a layout in hierarchy order. + QMap<QWidget *, bool> unsortedLayouts = getUnsortedLayoutsToBeBroken(false); + // Sort in order of hierarchy + QList<QWidget *> orderedLayoutList; + const QMap<QWidget *, bool>::const_iterator lscend = unsortedLayouts.constEnd(); + for (QMap<QWidget *, bool>::const_iterator itLay = unsortedLayouts.constBegin(); itLay != lscend; ++itLay) { + QWidget *wToBeInserted = itLay.key(); + if (!orderedLayoutList.contains(wToBeInserted)) { + // try to find first child, use as insertion position, else append + const QList<QWidget *>::iterator firstChildPos = findFirstChildOf(orderedLayoutList.begin(), orderedLayoutList.end(), wToBeInserted); + if (firstChildPos == orderedLayoutList.end()) { + orderedLayoutList.push_back(wToBeInserted); + } else { + orderedLayoutList.insert(firstChildPos, wToBeInserted); + } + } + } + return orderedLayoutList; +} + +static inline bool hasManagedLayoutItems(const QDesignerFormEditorInterface *core, QWidget *w) +{ + if (const QLayout *ml = LayoutInfo::managedLayout(core, w)) { + // Try to find managed items, ignore dummy grid spacers + const int count = ml->count(); + for (int i = 0; i < count; i++) + if (!LayoutInfo::isEmptyItem(ml->itemAt(i))) + return true; + } + return false; +} + +void FormWindowManager::slotUpdateActions() +{ + m_createLayoutContext = LayoutSelection; + m_morphLayoutContainer = 0; + bool canMorphIntoVBoxLayout = false; + bool canMorphIntoHBoxLayout = false; + bool canMorphIntoGridLayout = false; + bool canMorphIntoFormLayout = false; + int selectedWidgetCount = 0; + int laidoutWidgetCount = 0; + int unlaidoutWidgetCount = 0; + bool pasteAvailable = false; + bool layoutAvailable = false; + bool breakAvailable = false; + bool simplifyAvailable = false; + bool layoutContainer = false; + bool canChangeZOrder = true; + + do { + if (m_activeFormWindow == 0 || m_activeFormWindow->currentTool() != 0) + break; + + breakAvailable = hasLayoutsToBeBroken(); + + QWidgetList simplifiedSelection = m_activeFormWindow->selectedWidgets(); + + selectedWidgetCount = simplifiedSelection.count(); + pasteAvailable = qApp->clipboard()->mimeData() && qApp->clipboard()->mimeData()->hasText(); + + m_activeFormWindow->simplifySelection(&simplifiedSelection); + QWidget *mainContainer = m_activeFormWindow->mainContainer(); + if (simplifiedSelection.isEmpty() && mainContainer) + simplifiedSelection.append(mainContainer); + + // Always count the main container as unlaid-out + const QWidgetList::const_iterator cend = simplifiedSelection.constEnd(); + for (QWidgetList::const_iterator it = simplifiedSelection.constBegin(); it != cend; ++it) { + if (*it != mainContainer && LayoutInfo::isWidgetLaidout(m_core, *it)) { + ++laidoutWidgetCount; + } else { + ++unlaidoutWidgetCount; + } + if (qobject_cast<const QLayoutWidget *>(*it) || qobject_cast<const Spacer *>(*it)) + canChangeZOrder = false; + } + + // Figure out layouts: Looking at a group of dangling widgets + if (simplifiedSelection.count() != 1) { + layoutAvailable = unlaidoutWidgetCount > 1; + //breakAvailable = false; + break; + } + // Manipulate layout of a single widget + m_createLayoutContext = LayoutSelection; + QWidget *widget = core()->widgetFactory()->containerOfWidget(simplifiedSelection.first()); + if (widget == 0) // We are looking at a page-based container with 0 pages + break; + + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(widget)); + if (!item) + break; + + QLayout *widgetLayout = LayoutInfo::internalLayout(widget); + QLayout *managedLayout = LayoutInfo::managedLayout(m_core, widgetLayout); + // We don't touch a layout createds by a custom widget + if (widgetLayout && !managedLayout) + break; + + layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(widget)); + + layoutAvailable = layoutContainer && m_activeFormWindow->hasInsertedChildren(widget) && managedLayout == 0; + simplifyAvailable = SimplifyLayoutCommand::canSimplify(m_core, widget); + if (layoutAvailable) { + m_createLayoutContext = LayoutContainer; + } else { + /* Cannot create a layout, have some layouts to be broken and + * exactly one, non-empty layout with selected: check the morph layout options + * (Note that there might be > 1 layouts to broken if the selection + * is a red layout, however, we want the inner-most layout here). */ + if (breakAvailable && simplifiedSelection.size() == 1 + && hasManagedLayoutItems(m_core, widget)) { + int type; + m_morphLayoutContainer = widget; // Was: page of first selected + m_createLayoutContext = MorphLayout; + if (MorphLayoutCommand::canMorph(m_activeFormWindow, m_morphLayoutContainer, &type)) { + canMorphIntoVBoxLayout = type != LayoutInfo::VBox; + canMorphIntoHBoxLayout = type != LayoutInfo::HBox; + canMorphIntoGridLayout = type != LayoutInfo::Grid; + canMorphIntoFormLayout = type != LayoutInfo::Form; + } + } + } + } while(false); + + m_actionCut->setEnabled(selectedWidgetCount > 0); + m_actionCopy->setEnabled(selectedWidgetCount > 0); + m_actionDelete->setEnabled(selectedWidgetCount > 0); + m_actionLower->setEnabled(canChangeZOrder && selectedWidgetCount > 0); + m_actionRaise->setEnabled(canChangeZOrder && selectedWidgetCount > 0); + + m_actionPaste->setEnabled(pasteAvailable); + + m_actionSelectAll->setEnabled(m_activeFormWindow != 0); + + m_actionAdjustSize->setEnabled(unlaidoutWidgetCount > 0); + + m_actionHorizontalLayout->setEnabled(layoutAvailable || canMorphIntoHBoxLayout); + m_actionVerticalLayout->setEnabled(layoutAvailable || canMorphIntoVBoxLayout); + m_actionSplitHorizontal->setEnabled(layoutAvailable && !layoutContainer); + m_actionSplitVertical->setEnabled(layoutAvailable && !layoutContainer); + actionFormLayout()->setEnabled(layoutAvailable || canMorphIntoFormLayout); + m_actionGridLayout->setEnabled(layoutAvailable || canMorphIntoGridLayout); + + m_actionBreakLayout->setEnabled(breakAvailable); + actionSimplifyLayout()->setEnabled(simplifyAvailable); + m_actionShowFormWindowSettingsDialog->setEnabled(m_activeFormWindow != 0); +} + +QDesignerFormWindowInterface *FormWindowManager::createFormWindow(QWidget *parentWidget, Qt::WindowFlags flags) +{ + FormWindow *formWindow = new FormWindow(qobject_cast<FormEditor*>(core()), parentWidget, flags); + formWindow->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true)); + addFormWindow(formWindow); + return formWindow; +} + +QPixmap FormWindowManager::createPreviewPixmap(QString *errorMessage) +{ + QPixmap pixmap; + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return pixmap; + + pixmap = m_previewManager->createPreviewPixmap(fw, QString(), errorMessage); + return pixmap; +} + +QAction *FormWindowManager::actionUndo() const +{ + return m_actionUndo; +} + +QAction *FormWindowManager::actionRedo() const +{ + return m_actionRedo; +} + +QActionGroup *FormWindowManager::actionGroupPreviewInStyle() const +{ + if (m_actionGroupPreviewInStyle == 0) { + // Wish we could make the 'this' pointer mutable ;-) + QObject *parent = const_cast<FormWindowManager*>(this); + m_actionGroupPreviewInStyle = new PreviewActionGroup(m_core, parent); + connect(m_actionGroupPreviewInStyle, SIGNAL(preview(QString,int)), + this, SLOT(slotActionGroupPreviewInStyle(QString,int))); + } + return m_actionGroupPreviewInStyle; +} + +void FormWindowManager::deviceProfilesChanged() +{ + if (m_actionGroupPreviewInStyle) + m_actionGroupPreviewInStyle->updateDeviceProfiles(); +} + +// DnD stuff + +void FormWindowManager::dragItems(const QList<QDesignerDnDItemInterface*> &item_list) +{ + QDesignerMimeData::execDrag(item_list, m_core->topLevel()); +} + +QUndoGroup *FormWindowManager::undoGroup() const +{ + return m_undoGroup; +} + +QAction *FormWindowManager::actionShowFormWindowSettingsDialog() const +{ + return m_actionShowFormWindowSettingsDialog; +} + +void FormWindowManager::slotActionShowFormWindowSettingsDialog() +{ + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return; + + QDialog *settingsDialog = 0; + const bool wasDirty = fw->isDirty(); + + // Ask the language extension for a dialog. If not, create our own + if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*>(m_core->extensionManager(), m_core)) + settingsDialog = lang->createFormWindowSettingsDialog(fw, /*parent=*/ 0); + + if (!settingsDialog) + settingsDialog = new FormWindowSettings(fw); + + QString title = QFileInfo(fw->fileName()).fileName(); + if (title.isEmpty()) // Grab the title from the outer window if no filename + if (const QWidget *window = m_core->integration()->containerWindow(fw)) + title = window->windowTitle(); + + settingsDialog->setWindowTitle(tr("Form Settings - %1").arg(title)); + if (settingsDialog->exec()) + if (fw->isDirty() != wasDirty) + emit formWindowSettingsChanged(fw); + + delete settingsDialog; +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindowmanager.h b/tools/designer/src/components/formeditor/formwindowmanager.h new file mode 100644 index 0000000..d81ec2d --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowmanager.h @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWMANAGER_H +#define FORMWINDOWMANAGER_H + +#include "formeditor_global.h" + +#include <QtDesigner/private/qdesigner_formwindowmanager_p.h> + +#include <QtCore/QObject> +#include <QtCore/QList> +#include <QtCore/QPointer> +#include <QtCore/QMap> + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionGroup; +class QUndoGroup; +class QDesignerFormEditorInterface; +class QDesignerWidgetBoxInterface; + +namespace qdesigner_internal { + +class FormWindow; +class PreviewManager; +class PreviewActionGroup; + +class QT_FORMEDITOR_EXPORT FormWindowManager + : public QDesignerFormWindowManager +{ + Q_OBJECT +public: + explicit FormWindowManager(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~FormWindowManager(); + + virtual QDesignerFormEditorInterface *core() const; + + inline QAction *actionCut() const { return m_actionCut; } + inline QAction *actionCopy() const { return m_actionCopy; } + inline QAction *actionPaste() const { return m_actionPaste; } + inline QAction *actionDelete() const { return m_actionDelete; } + inline QAction *actionSelectAll() const { return m_actionSelectAll; } + inline QAction *actionLower() const { return m_actionLower; } + inline QAction *actionRaise() const { return m_actionRaise; } + QAction *actionUndo() const; + QAction *actionRedo() const; + + inline QAction *actionHorizontalLayout() const { return m_actionHorizontalLayout; } + inline QAction *actionVerticalLayout() const { return m_actionVerticalLayout; } + inline QAction *actionSplitHorizontal() const { return m_actionSplitHorizontal; } + inline QAction *actionSplitVertical() const { return m_actionSplitVertical; } + inline QAction *actionGridLayout() const { return m_actionGridLayout; } + inline QAction *actionBreakLayout() const { return m_actionBreakLayout; } + inline QAction *actionAdjustSize() const { return m_actionAdjustSize; } + + inline QAction *actionDefaultPreview() const { return m_actionDefaultPreview; } + QActionGroup *actionGroupPreviewInStyle() const; + virtual QAction *actionShowFormWindowSettingsDialog() const; + + QDesignerFormWindowInterface *activeFormWindow() const; + + int formWindowCount() const; + QDesignerFormWindowInterface *formWindow(int index) const; + + QDesignerFormWindowInterface *createFormWindow(QWidget *parentWidget = 0, Qt::WindowFlags flags = 0); + + QPixmap createPreviewPixmap(QString *errorMessage); + + bool eventFilter(QObject *o, QEvent *e); + + void dragItems(const QList<QDesignerDnDItemInterface*> &item_list); + + QUndoGroup *undoGroup() const; + + virtual PreviewManager *previewManager() const { return m_previewManager; } + +public slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + void setActiveFormWindow(QDesignerFormWindowInterface *formWindow); + void closeAllPreviews(); + void deviceProfilesChanged(); + +private slots: + void slotActionCutActivated(); + void slotActionCopyActivated(); + void slotActionPasteActivated(); + void slotActionDeleteActivated(); + void slotActionSelectAllActivated(); + void slotActionLowerActivated(); + void slotActionRaiseActivated(); + void createLayout(); + void slotActionBreakLayoutActivated(); + void slotActionAdjustSizeActivated(); + void slotActionSimplifyLayoutActivated(); + void slotActionDefaultPreviewActivated(); + void slotActionGroupPreviewInStyle(const QString &style, int deviceProfileIndex); + void slotActionShowFormWindowSettingsDialog(); + + void slotUpdateActions(); + +private: + void setupActions(); + FormWindow *findFormWindow(QWidget *w); + QWidget *findManagedWidget(FormWindow *fw, QWidget *w); + + void setCurrentUndoStack(QUndoStack *stack); + +private: + enum CreateLayoutContext { LayoutContainer, LayoutSelection, MorphLayout }; + + QDesignerFormEditorInterface *m_core; + FormWindow *m_activeFormWindow; + QList<FormWindow*> m_formWindows; + + PreviewManager *m_previewManager; + + /* Context of the layout actions and base for morphing layouts. Determined + * in slotUpdateActions() and used later on in the action slots. */ + CreateLayoutContext m_createLayoutContext; + QWidget *m_morphLayoutContainer; + + // edit actions + QAction *m_actionCut; + QAction *m_actionCopy; + QAction *m_actionPaste; + QAction *m_actionSelectAll; + QAction *m_actionDelete; + QAction *m_actionLower; + QAction *m_actionRaise; + // layout actions + QAction *m_actionHorizontalLayout; + QAction *m_actionVerticalLayout; + QAction *m_actionSplitHorizontal; + QAction *m_actionSplitVertical; + QAction *m_actionGridLayout; + QAction *m_actionBreakLayout; + QAction *m_actionAdjustSize; + // preview actions + QAction *m_actionDefaultPreview; + mutable PreviewActionGroup *m_actionGroupPreviewInStyle; + QAction *m_actionShowFormWindowSettingsDialog; + + QAction *m_actionUndo; + QAction *m_actionRedo; + + QMap<QWidget *,bool> getUnsortedLayoutsToBeBroken(bool firstOnly) const; + bool hasLayoutsToBeBroken() const; + QWidgetList layoutsToBeBroken(QWidget *w) const; + QWidgetList layoutsToBeBroken() const; + + QUndoGroup *m_undoGroup; + +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOWMANAGER_H diff --git a/tools/designer/src/components/formeditor/formwindowsettings.cpp b/tools/designer/src/components/formeditor/formwindowsettings.cpp new file mode 100644 index 0000000..1f6d5dd --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowsettings.cpp @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindowsettings.h" +#include "ui_formwindowsettings.h" + +#include <formwindowbase_p.h> +#include <grid_p.h> + +#include <QtGui/QStyle> + +#include <QtCore/QRegExp> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Data structure containing form dialog data providing comparison +struct FormWindowData { + FormWindowData(); + + bool equals(const FormWindowData&) const; + + void fromFormWindow(FormWindowBase* fw); + void applyToFormWindow(FormWindowBase* fw) const; + + bool layoutDefaultEnabled; + int defaultMargin; + int defaultSpacing; + + bool layoutFunctionsEnabled; + QString marginFunction; + QString spacingFunction; + + QString pixFunction; + + QString author; + + QStringList includeHints; + + bool hasFormGrid; + Grid grid; +}; + +inline bool operator==(const FormWindowData &fd1, const FormWindowData &fd2) { return fd1.equals(fd2); } +inline bool operator!=(const FormWindowData &fd1, const FormWindowData &fd2) { return !fd1.equals(fd2); } + +QDebug operator<<(QDebug str, const FormWindowData &d) +{ + str.nospace() << "LayoutDefault=" << d.layoutDefaultEnabled << ',' << d.defaultMargin + << ',' << d.defaultSpacing << " LayoutFunctions=" << d.layoutFunctionsEnabled << ',' + << d.marginFunction << ',' << d.spacingFunction << " PixFunction=" + << d.pixFunction << " Author=" << d.author << " Hints=" << d.includeHints + << " Grid=" << d.hasFormGrid << d.grid.deltaX() << d.grid.deltaY() << '\n'; + return str; +} + +FormWindowData::FormWindowData() : + layoutDefaultEnabled(false), + defaultMargin(0), + defaultSpacing(0), + layoutFunctionsEnabled(false), + hasFormGrid(false) +{ +} + +bool FormWindowData::equals(const FormWindowData &rhs) const +{ + return layoutDefaultEnabled == rhs.layoutDefaultEnabled && + defaultMargin == rhs.defaultMargin && + defaultSpacing == rhs.defaultSpacing && + layoutFunctionsEnabled == rhs.layoutFunctionsEnabled && + marginFunction == rhs.marginFunction && + spacingFunction == rhs.spacingFunction && + pixFunction == rhs.pixFunction && + author == rhs.author && + includeHints == rhs.includeHints && + hasFormGrid == rhs.hasFormGrid && + grid == rhs.grid; +} + +void FormWindowData::fromFormWindow(FormWindowBase* fw) +{ + defaultMargin = defaultSpacing = INT_MIN; + fw->layoutDefault(&defaultMargin, &defaultSpacing); + + QStyle *style = fw->formContainer()->style(); + layoutDefaultEnabled = defaultMargin != INT_MIN || defaultMargin != INT_MIN; + if (defaultMargin == INT_MIN) + defaultMargin = style->pixelMetric(QStyle::PM_DefaultChildMargin, 0); + if (defaultSpacing == INT_MIN) + defaultSpacing = style->pixelMetric(QStyle::PM_DefaultLayoutSpacing, 0); + + + marginFunction.clear(); + spacingFunction.clear(); + fw->layoutFunction(&marginFunction, &spacingFunction); + layoutFunctionsEnabled = !marginFunction.isEmpty() || !spacingFunction.isEmpty(); + + pixFunction = fw->pixmapFunction(); + + author = fw->author(); + + includeHints = fw->includeHints(); + includeHints.removeAll(QString()); + + hasFormGrid = fw->hasFormGrid(); + grid = hasFormGrid ? fw->designerGrid() : FormWindowBase::defaultDesignerGrid(); +} + +void FormWindowData::applyToFormWindow(FormWindowBase* fw) const +{ + fw->setAuthor(author); + fw->setPixmapFunction(pixFunction); + + if (layoutDefaultEnabled) { + fw->setLayoutDefault(defaultMargin, defaultSpacing); + } else { + fw->setLayoutDefault(INT_MIN, INT_MIN); + } + + if (layoutFunctionsEnabled) { + fw->setLayoutFunction(marginFunction, spacingFunction); + } else { + fw->setLayoutFunction(QString(), QString()); + } + + fw->setIncludeHints(includeHints); + + const bool hadFormGrid = fw->hasFormGrid(); + fw->setHasFormGrid(hasFormGrid); + if (hasFormGrid || hadFormGrid != hasFormGrid) + fw->setDesignerGrid(hasFormGrid ? grid : FormWindowBase::defaultDesignerGrid()); +} + +// -------------------------- FormWindowSettings + +FormWindowSettings::FormWindowSettings(QDesignerFormWindowInterface *parent) : + QDialog(parent), + m_ui(new ::Ui::FormWindowSettings), + m_formWindow(qobject_cast<FormWindowBase*>(parent)), + m_oldData(new FormWindowData) +{ + Q_ASSERT(m_formWindow); + + m_ui->setupUi(this); + m_ui->gridPanel->setCheckable(true); + m_ui->gridPanel->setResetButtonVisible(false); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + QString deviceProfileName = m_formWindow->deviceProfileName(); + if (deviceProfileName.isEmpty()) + deviceProfileName = tr("None"); + m_ui->deviceProfileLabel->setText(tr("Device Profile: %1").arg(deviceProfileName)); + + m_oldData->fromFormWindow(m_formWindow); + setData(*m_oldData); +} + +FormWindowSettings::~FormWindowSettings() +{ + delete m_oldData; + delete m_ui; +} + +FormWindowData FormWindowSettings::data() const +{ + FormWindowData rc; + rc.author = m_ui->authorLineEdit->text(); + + if (m_ui->pixmapFunctionGroupBox->isChecked()) { + rc.pixFunction = m_ui->pixmapFunctionLineEdit->text(); + } else { + rc.pixFunction.clear(); + } + + rc.layoutDefaultEnabled = m_ui->layoutDefaultGroupBox->isChecked(); + rc.defaultMargin = m_ui->defaultMarginSpinBox->value(); + rc.defaultSpacing = m_ui->defaultSpacingSpinBox->value(); + + rc.layoutFunctionsEnabled = m_ui->layoutFunctionGroupBox->isChecked(); + rc.marginFunction = m_ui->marginFunctionLineEdit->text(); + rc.spacingFunction = m_ui->spacingFunctionLineEdit->text(); + + const QString hints = m_ui->includeHintsTextEdit->toPlainText(); + if (!hints.isEmpty()) { + rc.includeHints = hints.split(QString(QLatin1Char('\n'))); + // Purge out any lines consisting of blanks only + const QRegExp blankLine = QRegExp(QLatin1String("^\\s*$")); + Q_ASSERT(blankLine.isValid()); + for (QStringList::iterator it = rc.includeHints.begin(); it != rc.includeHints.end(); ) + if (blankLine.exactMatch(*it)) { + it = rc.includeHints.erase(it); + } else { + ++it; + } + rc.includeHints.removeAll(QString()); + } + + rc.hasFormGrid = m_ui->gridPanel->isChecked(); + rc.grid = m_ui->gridPanel->grid(); + return rc; +} + +void FormWindowSettings::setData(const FormWindowData &data) +{ + m_ui->layoutDefaultGroupBox->setChecked(data.layoutDefaultEnabled); + m_ui->defaultMarginSpinBox->setValue(data.defaultMargin); + m_ui->defaultSpacingSpinBox->setValue(data.defaultSpacing); + + m_ui->layoutFunctionGroupBox->setChecked(data.layoutFunctionsEnabled); + m_ui->marginFunctionLineEdit->setText(data.marginFunction); + m_ui->spacingFunctionLineEdit->setText(data.spacingFunction); + + m_ui->pixmapFunctionLineEdit->setText(data.pixFunction); + m_ui->pixmapFunctionGroupBox->setChecked(!data.pixFunction.isEmpty()); + + m_ui->authorLineEdit->setText(data.author); + + if (data.includeHints.empty()) { + m_ui->includeHintsTextEdit->clear(); + } else { + m_ui->includeHintsTextEdit->setText(data.includeHints.join(QLatin1String("\n"))); + } + + m_ui->gridPanel->setChecked(data.hasFormGrid); + m_ui->gridPanel->setGrid(data.grid); +} + +void FormWindowSettings::accept() +{ + // Anything changed? -> Apply and set dirty + const FormWindowData newData = data(); + if (newData != *m_oldData) { + newData.applyToFormWindow(m_formWindow); + m_formWindow->setDirty(true); + } + + QDialog::accept(); +} +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/formwindowsettings.h b/tools/designer/src/components/formeditor/formwindowsettings.h new file mode 100644 index 0000000..4289f42 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowsettings.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWSETTINGS_H +#define FORMWINDOWSETTINGS_H + +#include <QDialog> + +QT_BEGIN_NAMESPACE + +namespace Ui { + class FormWindowSettings; +} + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +struct FormWindowData; +class FormWindowBase; + +/* Dialog to edit the settings of a QDesignerFormWindowInterface. + * It sets the dirty flag on the form window if something was changed. */ + +class FormWindowSettings: public QDialog +{ + Q_DISABLE_COPY(FormWindowSettings) + Q_OBJECT +public: + explicit FormWindowSettings(QDesignerFormWindowInterface *formWindow); + virtual ~FormWindowSettings(); + + virtual void accept(); + +private: + FormWindowData data() const; + void setData(const FormWindowData&); + + Ui::FormWindowSettings *m_ui; + FormWindowBase *m_formWindow; + FormWindowData *m_oldData; +}; +} + +QT_END_NAMESPACE + +#endif // FORMWINDOWSETTINGS_H diff --git a/tools/designer/src/components/formeditor/formwindowsettings.ui b/tools/designer/src/components/formeditor/formwindowsettings.ui new file mode 100644 index 0000000..4e56365 --- /dev/null +++ b/tools/designer/src/components/formeditor/formwindowsettings.ui @@ -0,0 +1,328 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>FormWindowSettings</class> + <widget class="QDialog" name="FormWindowSettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>470</width> + <height>466</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form Settings</string> + </property> + <layout class="QGridLayout"> + <item row="3" column="0" colspan="2"> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="layoutDefaultGroupBox"> + <property name="title"> + <string>Layout &Default</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout"> + <property name="margin"> + <number>8</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>&Spacing:</string> + </property> + <property name="buddy"> + <cstring>defaultSpacingSpinBox</cstring> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>&Margin:</string> + </property> + <property name="buddy"> + <cstring>defaultMarginSpinBox</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="defaultSpacingSpinBox"/> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="defaultMarginSpinBox"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="layoutFunctionGroupBox"> + <property name="title"> + <string>&Layout Function</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout"> + <property name="margin"> + <number>8</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="1" column="1"> + <widget class="QLineEdit" name="spacingFunctionLineEdit"/> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="marginFunctionLineEdit"/> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Ma&rgin:</string> + </property> + <property name="buddy"> + <cstring>marginFunctionLineEdit</cstring> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3_2"> + <property name="text"> + <string>Spa&cing:</string> + </property> + <property name="buddy"> + <cstring>spacingFunctionLineEdit</cstring> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item row="4" column="1"> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="pixmapFunctionGroupBox"> + <property name="title"> + <string>&Pixmap Function</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>8</number> + </property> + <item> + <widget class="QLineEdit" name="pixmapFunctionLineEdit"/> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item row="5" column="1"> + <spacer> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>111</width> + <height>115</height> + </size> + </property> + </spacer> + </item> + <item row="7" column="0" colspan="2"> + <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> + <item row="6" column="0" colspan="2"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="4" column="0" rowspan="2"> + <widget class="QGroupBox" name="includeHintsGroupBox"> + <property name="title"> + <string>&Include Hints</string> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>8</number> + </property> + <item> + <widget class="QTextEdit" name="includeHintsTextEdit"/> + </item> + </layout> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="qdesigner_internal::GridPanel" name="gridPanel"> + <property name="title"> + <string>Grid</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QGroupBox" name="embeddedGroupBox"> + <property name="title"> + <string>Embedded Design</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="deviceProfileLabel"> + <property name="text"> + <string notr="true">TextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QGroupBox" name="pixmapFunctionGroupBox_2"> + <property name="title"> + <string>&Author</string> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>8</number> + </property> + <item> + <widget class="QLineEdit" name="authorLineEdit"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>qdesigner_internal::GridPanel</class> + <extends>QGroupBox</extends> + <header location="global">gridpanel_p.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>authorLineEdit</tabstop> + <tabstop>defaultMarginSpinBox</tabstop> + <tabstop>defaultSpacingSpinBox</tabstop> + <tabstop>marginFunctionLineEdit</tabstop> + <tabstop>spacingFunctionLineEdit</tabstop> + <tabstop>pixmapFunctionLineEdit</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>FormWindowSettings</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>294</x> + <y>442</y> + </hint> + <hint type="destinationlabel"> + <x>150</x> + <y>459</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>FormWindowSettings</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>373</x> + <y>444</y> + </hint> + <hint type="destinationlabel"> + <x>357</x> + <y>461</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/formeditor/iconcache.cpp b/tools/designer/src/components/formeditor/iconcache.cpp new file mode 100644 index 0000000..a256bf8 --- /dev/null +++ b/tools/designer/src/components/formeditor/iconcache.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "iconcache.h" +#include <QtGui/QPixmap> +#include <QtGui/QIcon> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +IconCache::IconCache(QObject *parent) + : QDesignerIconCacheInterface(parent) +{ +} + +QIcon IconCache::nameToIcon(const QString &path, const QString &resourcePath) +{ + Q_UNUSED(path) + Q_UNUSED(resourcePath) + qWarning() << "IconCache::nameToIcon(): IconCache is obsoleted"; + return QIcon(); +} + +QString IconCache::iconToFilePath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::iconToFilePath(): IconCache is obsoleted"; + return QString(); +} + +QString IconCache::iconToQrcPath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::iconToQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QPixmap IconCache::nameToPixmap(const QString &path, const QString &resourcePath) +{ + Q_UNUSED(path) + Q_UNUSED(resourcePath) + qWarning() << "IconCache::nameToPixmap(): IconCache is obsoleted"; + return QPixmap(); +} + +QString IconCache::pixmapToFilePath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::pixmapToFilePath(): IconCache is obsoleted"; + return QString(); +} + +QString IconCache::pixmapToQrcPath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::pixmapToQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QList<QPixmap> IconCache::pixmapList() const +{ + qWarning() << "IconCache::pixmapList(): IconCache is obsoleted"; + return QList<QPixmap>(); +} + +QList<QIcon> IconCache::iconList() const +{ + qWarning() << "IconCache::iconList(): IconCache is obsoleted"; + return QList<QIcon>(); +} + +QString IconCache::resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &wd) const +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + Q_UNUSED(wd) + qWarning() << "IconCache::resolveQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/iconcache.h b/tools/designer/src/components/formeditor/iconcache.h new file mode 100644 index 0000000..24d36e2 --- /dev/null +++ b/tools/designer/src/components/formeditor/iconcache.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ICONCACHE_H +#define ICONCACHE_H + +#include "formeditor_global.h" + +#include <QtDesigner/QDesignerIconCacheInterface> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT IconCache : public QDesignerIconCacheInterface +{ + Q_OBJECT +public: + explicit IconCache(QObject *parent); + + virtual QIcon nameToIcon(const QString &path, const QString &resourcePath = QString()); + virtual QString iconToFilePath(const QIcon &pm) const; + virtual QString iconToQrcPath(const QIcon &pm) const; + virtual QPixmap nameToPixmap(const QString &path, const QString &resourcePath = QString()); + virtual QString pixmapToFilePath(const QPixmap &pm) const; + virtual QString pixmapToQrcPath(const QPixmap &pm) const; + + virtual QList<QPixmap> pixmapList() const; + virtual QList<QIcon> iconList() const; + + virtual QString resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &workingDirectory = QString()) const; + +private: +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ICONCACHE_H diff --git a/tools/designer/src/components/formeditor/images/color.png b/tools/designer/src/components/formeditor/images/color.png Binary files differnew file mode 100644 index 0000000..54b7ebc --- /dev/null +++ b/tools/designer/src/components/formeditor/images/color.png diff --git a/tools/designer/src/components/formeditor/images/configure.png b/tools/designer/src/components/formeditor/images/configure.png Binary files differnew file mode 100644 index 0000000..d9f2fd8 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/configure.png diff --git a/tools/designer/src/components/formeditor/images/cursors/arrow.png b/tools/designer/src/components/formeditor/images/cursors/arrow.png Binary files differnew file mode 100644 index 0000000..a69ef4e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/arrow.png diff --git a/tools/designer/src/components/formeditor/images/cursors/busy.png b/tools/designer/src/components/formeditor/images/cursors/busy.png Binary files differnew file mode 100644 index 0000000..53717e4 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/busy.png diff --git a/tools/designer/src/components/formeditor/images/cursors/closedhand.png b/tools/designer/src/components/formeditor/images/cursors/closedhand.png Binary files differnew file mode 100644 index 0000000..b78dd1d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/closedhand.png diff --git a/tools/designer/src/components/formeditor/images/cursors/cross.png b/tools/designer/src/components/formeditor/images/cursors/cross.png Binary files differnew file mode 100644 index 0000000..fe38e74 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/cross.png diff --git a/tools/designer/src/components/formeditor/images/cursors/hand.png b/tools/designer/src/components/formeditor/images/cursors/hand.png Binary files differnew file mode 100644 index 0000000..d2004ae --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/hand.png diff --git a/tools/designer/src/components/formeditor/images/cursors/hsplit.png b/tools/designer/src/components/formeditor/images/cursors/hsplit.png Binary files differnew file mode 100644 index 0000000..a5667e3 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/hsplit.png diff --git a/tools/designer/src/components/formeditor/images/cursors/ibeam.png b/tools/designer/src/components/formeditor/images/cursors/ibeam.png Binary files differnew file mode 100644 index 0000000..097fc5f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/ibeam.png diff --git a/tools/designer/src/components/formeditor/images/cursors/no.png b/tools/designer/src/components/formeditor/images/cursors/no.png Binary files differnew file mode 100644 index 0000000..2b08c4e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/no.png diff --git a/tools/designer/src/components/formeditor/images/cursors/openhand.png b/tools/designer/src/components/formeditor/images/cursors/openhand.png Binary files differnew file mode 100644 index 0000000..9181c85 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/openhand.png diff --git a/tools/designer/src/components/formeditor/images/cursors/sizeall.png b/tools/designer/src/components/formeditor/images/cursors/sizeall.png Binary files differnew file mode 100644 index 0000000..69f13eb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/sizeall.png diff --git a/tools/designer/src/components/formeditor/images/cursors/sizeb.png b/tools/designer/src/components/formeditor/images/cursors/sizeb.png Binary files differnew file mode 100644 index 0000000..3b127a0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/sizeb.png diff --git a/tools/designer/src/components/formeditor/images/cursors/sizef.png b/tools/designer/src/components/formeditor/images/cursors/sizef.png Binary files differnew file mode 100644 index 0000000..f37d7b9 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/sizef.png diff --git a/tools/designer/src/components/formeditor/images/cursors/sizeh.png b/tools/designer/src/components/formeditor/images/cursors/sizeh.png Binary files differnew file mode 100644 index 0000000..a9f40cb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/sizeh.png diff --git a/tools/designer/src/components/formeditor/images/cursors/sizev.png b/tools/designer/src/components/formeditor/images/cursors/sizev.png Binary files differnew file mode 100644 index 0000000..1edbab2 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/sizev.png diff --git a/tools/designer/src/components/formeditor/images/cursors/uparrow.png b/tools/designer/src/components/formeditor/images/cursors/uparrow.png Binary files differnew file mode 100644 index 0000000..d3e70ef --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/uparrow.png diff --git a/tools/designer/src/components/formeditor/images/cursors/vsplit.png b/tools/designer/src/components/formeditor/images/cursors/vsplit.png Binary files differnew file mode 100644 index 0000000..1beda25 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/vsplit.png diff --git a/tools/designer/src/components/formeditor/images/cursors/wait.png b/tools/designer/src/components/formeditor/images/cursors/wait.png Binary files differnew file mode 100644 index 0000000..69056c4 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/wait.png diff --git a/tools/designer/src/components/formeditor/images/cursors/whatsthis.png b/tools/designer/src/components/formeditor/images/cursors/whatsthis.png Binary files differnew file mode 100644 index 0000000..b47601c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cursors/whatsthis.png diff --git a/tools/designer/src/components/formeditor/images/downplus.png b/tools/designer/src/components/formeditor/images/downplus.png Binary files differnew file mode 100644 index 0000000..1e384a7 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/downplus.png diff --git a/tools/designer/src/components/formeditor/images/dropdownbutton.png b/tools/designer/src/components/formeditor/images/dropdownbutton.png Binary files differnew file mode 100644 index 0000000..5dd9649 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/dropdownbutton.png diff --git a/tools/designer/src/components/formeditor/images/edit.png b/tools/designer/src/components/formeditor/images/edit.png Binary files differnew file mode 100644 index 0000000..a5e49ad --- /dev/null +++ b/tools/designer/src/components/formeditor/images/edit.png diff --git a/tools/designer/src/components/formeditor/images/editdelete-16.png b/tools/designer/src/components/formeditor/images/editdelete-16.png Binary files differnew file mode 100644 index 0000000..ef5c799 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/editdelete-16.png diff --git a/tools/designer/src/components/formeditor/images/emptyicon.png b/tools/designer/src/components/formeditor/images/emptyicon.png Binary files differnew file mode 100644 index 0000000..897220e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/emptyicon.png diff --git a/tools/designer/src/components/formeditor/images/filenew-16.png b/tools/designer/src/components/formeditor/images/filenew-16.png Binary files differnew file mode 100644 index 0000000..eefb3c5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/filenew-16.png diff --git a/tools/designer/src/components/formeditor/images/fileopen-16.png b/tools/designer/src/components/formeditor/images/fileopen-16.png Binary files differnew file mode 100644 index 0000000..d832c62 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/fileopen-16.png diff --git a/tools/designer/src/components/formeditor/images/leveldown.png b/tools/designer/src/components/formeditor/images/leveldown.png Binary files differnew file mode 100644 index 0000000..742b7fb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/leveldown.png diff --git a/tools/designer/src/components/formeditor/images/levelup.png b/tools/designer/src/components/formeditor/images/levelup.png Binary files differnew file mode 100644 index 0000000..48b3e89 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/levelup.png diff --git a/tools/designer/src/components/formeditor/images/mac/adjustsize.png b/tools/designer/src/components/formeditor/images/mac/adjustsize.png Binary files differnew file mode 100644 index 0000000..c4d884c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/adjustsize.png diff --git a/tools/designer/src/components/formeditor/images/mac/back.png b/tools/designer/src/components/formeditor/images/mac/back.png Binary files differnew file mode 100644 index 0000000..e58177f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/back.png diff --git a/tools/designer/src/components/formeditor/images/mac/buddytool.png b/tools/designer/src/components/formeditor/images/mac/buddytool.png Binary files differnew file mode 100644 index 0000000..2a42870 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/buddytool.png diff --git a/tools/designer/src/components/formeditor/images/mac/down.png b/tools/designer/src/components/formeditor/images/mac/down.png Binary files differnew file mode 100644 index 0000000..29d1d44 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/down.png diff --git a/tools/designer/src/components/formeditor/images/mac/editbreaklayout.png b/tools/designer/src/components/formeditor/images/mac/editbreaklayout.png Binary files differnew file mode 100644 index 0000000..dc00559 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editbreaklayout.png diff --git a/tools/designer/src/components/formeditor/images/mac/editcopy.png b/tools/designer/src/components/formeditor/images/mac/editcopy.png Binary files differnew file mode 100644 index 0000000..f551364 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editcopy.png diff --git a/tools/designer/src/components/formeditor/images/mac/editcut.png b/tools/designer/src/components/formeditor/images/mac/editcut.png Binary files differnew file mode 100644 index 0000000..a784fd5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editcut.png diff --git a/tools/designer/src/components/formeditor/images/mac/editdelete.png b/tools/designer/src/components/formeditor/images/mac/editdelete.png Binary files differnew file mode 100644 index 0000000..201b31c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editdelete.png diff --git a/tools/designer/src/components/formeditor/images/mac/editform.png b/tools/designer/src/components/formeditor/images/mac/editform.png Binary files differnew file mode 100644 index 0000000..4fc2e40 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editform.png diff --git a/tools/designer/src/components/formeditor/images/mac/editgrid.png b/tools/designer/src/components/formeditor/images/mac/editgrid.png Binary files differnew file mode 100644 index 0000000..bba4a69 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editgrid.png diff --git a/tools/designer/src/components/formeditor/images/mac/edithlayout.png b/tools/designer/src/components/formeditor/images/mac/edithlayout.png Binary files differnew file mode 100644 index 0000000..ec880bb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/edithlayout.png diff --git a/tools/designer/src/components/formeditor/images/mac/edithlayoutsplit.png b/tools/designer/src/components/formeditor/images/mac/edithlayoutsplit.png Binary files differnew file mode 100644 index 0000000..227d011 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/edithlayoutsplit.png diff --git a/tools/designer/src/components/formeditor/images/mac/editlower.png b/tools/designer/src/components/formeditor/images/mac/editlower.png Binary files differnew file mode 100644 index 0000000..347806f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editlower.png diff --git a/tools/designer/src/components/formeditor/images/mac/editpaste.png b/tools/designer/src/components/formeditor/images/mac/editpaste.png Binary files differnew file mode 100644 index 0000000..64c0b2d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editpaste.png diff --git a/tools/designer/src/components/formeditor/images/mac/editraise.png b/tools/designer/src/components/formeditor/images/mac/editraise.png Binary files differnew file mode 100644 index 0000000..09cbbd7 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editraise.png diff --git a/tools/designer/src/components/formeditor/images/mac/editvlayout.png b/tools/designer/src/components/formeditor/images/mac/editvlayout.png Binary files differnew file mode 100644 index 0000000..63b26cd --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editvlayout.png diff --git a/tools/designer/src/components/formeditor/images/mac/editvlayoutsplit.png b/tools/designer/src/components/formeditor/images/mac/editvlayoutsplit.png Binary files differnew file mode 100644 index 0000000..5a02c94 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/editvlayoutsplit.png diff --git a/tools/designer/src/components/formeditor/images/mac/filenew.png b/tools/designer/src/components/formeditor/images/mac/filenew.png Binary files differnew file mode 100644 index 0000000..9dcba42 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/filenew.png diff --git a/tools/designer/src/components/formeditor/images/mac/fileopen.png b/tools/designer/src/components/formeditor/images/mac/fileopen.png Binary files differnew file mode 100644 index 0000000..c12bcd5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/fileopen.png diff --git a/tools/designer/src/components/formeditor/images/mac/filesave.png b/tools/designer/src/components/formeditor/images/mac/filesave.png Binary files differnew file mode 100644 index 0000000..b41ecf5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/filesave.png diff --git a/tools/designer/src/components/formeditor/images/mac/forward.png b/tools/designer/src/components/formeditor/images/mac/forward.png Binary files differnew file mode 100644 index 0000000..34b91f0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/forward.png diff --git a/tools/designer/src/components/formeditor/images/mac/insertimage.png b/tools/designer/src/components/formeditor/images/mac/insertimage.png Binary files differnew file mode 100644 index 0000000..b8673e1 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/insertimage.png diff --git a/tools/designer/src/components/formeditor/images/mac/minus.png b/tools/designer/src/components/formeditor/images/mac/minus.png Binary files differnew file mode 100644 index 0000000..8d2eaed --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/minus.png diff --git a/tools/designer/src/components/formeditor/images/mac/plus.png b/tools/designer/src/components/formeditor/images/mac/plus.png Binary files differnew file mode 100644 index 0000000..1ee4542 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/plus.png diff --git a/tools/designer/src/components/formeditor/images/mac/redo.png b/tools/designer/src/components/formeditor/images/mac/redo.png Binary files differnew file mode 100644 index 0000000..8875bf2 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/redo.png diff --git a/tools/designer/src/components/formeditor/images/mac/resetproperty.png b/tools/designer/src/components/formeditor/images/mac/resetproperty.png Binary files differnew file mode 100644 index 0000000..9048252 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/resetproperty.png diff --git a/tools/designer/src/components/formeditor/images/mac/resourceeditortool.png b/tools/designer/src/components/formeditor/images/mac/resourceeditortool.png Binary files differnew file mode 100644 index 0000000..7ef511c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/resourceeditortool.png diff --git a/tools/designer/src/components/formeditor/images/mac/signalslottool.png b/tools/designer/src/components/formeditor/images/mac/signalslottool.png Binary files differnew file mode 100644 index 0000000..71c9b07 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/signalslottool.png diff --git a/tools/designer/src/components/formeditor/images/mac/tabordertool.png b/tools/designer/src/components/formeditor/images/mac/tabordertool.png Binary files differnew file mode 100644 index 0000000..f54faf9 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/tabordertool.png diff --git a/tools/designer/src/components/formeditor/images/mac/textanchor.png b/tools/designer/src/components/formeditor/images/mac/textanchor.png Binary files differnew file mode 100644 index 0000000..baa9dda --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textanchor.png diff --git a/tools/designer/src/components/formeditor/images/mac/textbold.png b/tools/designer/src/components/formeditor/images/mac/textbold.png Binary files differnew file mode 100644 index 0000000..38400bd --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textbold.png diff --git a/tools/designer/src/components/formeditor/images/mac/textcenter.png b/tools/designer/src/components/formeditor/images/mac/textcenter.png Binary files differnew file mode 100644 index 0000000..2ef5b2e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textcenter.png diff --git a/tools/designer/src/components/formeditor/images/mac/textitalic.png b/tools/designer/src/components/formeditor/images/mac/textitalic.png Binary files differnew file mode 100644 index 0000000..0170ee2 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textitalic.png diff --git a/tools/designer/src/components/formeditor/images/mac/textjustify.png b/tools/designer/src/components/formeditor/images/mac/textjustify.png Binary files differnew file mode 100644 index 0000000..39cd6c1 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textjustify.png diff --git a/tools/designer/src/components/formeditor/images/mac/textleft.png b/tools/designer/src/components/formeditor/images/mac/textleft.png Binary files differnew file mode 100644 index 0000000..83a66d5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textleft.png diff --git a/tools/designer/src/components/formeditor/images/mac/textright.png b/tools/designer/src/components/formeditor/images/mac/textright.png Binary files differnew file mode 100644 index 0000000..e7c0464 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textright.png diff --git a/tools/designer/src/components/formeditor/images/mac/textsubscript.png b/tools/designer/src/components/formeditor/images/mac/textsubscript.png Binary files differnew file mode 100644 index 0000000..ff431f3 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textsubscript.png diff --git a/tools/designer/src/components/formeditor/images/mac/textsuperscript.png b/tools/designer/src/components/formeditor/images/mac/textsuperscript.png Binary files differnew file mode 100644 index 0000000..cb67a33 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textsuperscript.png diff --git a/tools/designer/src/components/formeditor/images/mac/textunder.png b/tools/designer/src/components/formeditor/images/mac/textunder.png Binary files differnew file mode 100644 index 0000000..968bac5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/textunder.png diff --git a/tools/designer/src/components/formeditor/images/mac/undo.png b/tools/designer/src/components/formeditor/images/mac/undo.png Binary files differnew file mode 100644 index 0000000..a3bd5e0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/undo.png diff --git a/tools/designer/src/components/formeditor/images/mac/up.png b/tools/designer/src/components/formeditor/images/mac/up.png Binary files differnew file mode 100644 index 0000000..e437312 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/up.png diff --git a/tools/designer/src/components/formeditor/images/mac/widgettool.png b/tools/designer/src/components/formeditor/images/mac/widgettool.png Binary files differnew file mode 100644 index 0000000..e1aa353 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/mac/widgettool.png diff --git a/tools/designer/src/components/formeditor/images/minus-16.png b/tools/designer/src/components/formeditor/images/minus-16.png Binary files differnew file mode 100644 index 0000000..745b445 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/minus-16.png diff --git a/tools/designer/src/components/formeditor/images/plus-16.png b/tools/designer/src/components/formeditor/images/plus-16.png Binary files differnew file mode 100644 index 0000000..ef43788 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/plus-16.png diff --git a/tools/designer/src/components/formeditor/images/prefix-add.png b/tools/designer/src/components/formeditor/images/prefix-add.png Binary files differnew file mode 100644 index 0000000..cfbb053 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/prefix-add.png diff --git a/tools/designer/src/components/formeditor/images/qt3logo.png b/tools/designer/src/components/formeditor/images/qt3logo.png Binary files differnew file mode 100644 index 0000000..7202850 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/qt3logo.png diff --git a/tools/designer/src/components/formeditor/images/qtlogo.png b/tools/designer/src/components/formeditor/images/qtlogo.png Binary files differnew file mode 100644 index 0000000..038fa2c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/qtlogo.png diff --git a/tools/designer/src/components/formeditor/images/reload.png b/tools/designer/src/components/formeditor/images/reload.png Binary files differnew file mode 100644 index 0000000..18c752e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/reload.png diff --git a/tools/designer/src/components/formeditor/images/resetproperty.png b/tools/designer/src/components/formeditor/images/resetproperty.png Binary files differnew file mode 100644 index 0000000..9048252 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/resetproperty.png diff --git a/tools/designer/src/components/formeditor/images/sort.png b/tools/designer/src/components/formeditor/images/sort.png Binary files differnew file mode 100644 index 0000000..883bfa9 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/sort.png diff --git a/tools/designer/src/components/formeditor/images/submenu.png b/tools/designer/src/components/formeditor/images/submenu.png Binary files differnew file mode 100644 index 0000000..3deb28e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/submenu.png diff --git a/tools/designer/src/components/formeditor/images/widgets/calendarwidget.png b/tools/designer/src/components/formeditor/images/widgets/calendarwidget.png Binary files differnew file mode 100644 index 0000000..26737b8 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/calendarwidget.png diff --git a/tools/designer/src/components/formeditor/images/widgets/checkbox.png b/tools/designer/src/components/formeditor/images/widgets/checkbox.png Binary files differnew file mode 100644 index 0000000..ab6f53e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/checkbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/columnview.png b/tools/designer/src/components/formeditor/images/widgets/columnview.png Binary files differnew file mode 100644 index 0000000..4132ee6 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/columnview.png diff --git a/tools/designer/src/components/formeditor/images/widgets/combobox.png b/tools/designer/src/components/formeditor/images/widgets/combobox.png Binary files differnew file mode 100644 index 0000000..bf3ed79 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/combobox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/commandlinkbutton.png b/tools/designer/src/components/formeditor/images/widgets/commandlinkbutton.png Binary files differnew file mode 100644 index 0000000..6bbd84a --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/commandlinkbutton.png diff --git a/tools/designer/src/components/formeditor/images/widgets/dateedit.png b/tools/designer/src/components/formeditor/images/widgets/dateedit.png Binary files differnew file mode 100644 index 0000000..6827fa7 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/dateedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/datetimeedit.png b/tools/designer/src/components/formeditor/images/widgets/datetimeedit.png Binary files differnew file mode 100644 index 0000000..7d8e6fe --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/datetimeedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/dial.png b/tools/designer/src/components/formeditor/images/widgets/dial.png Binary files differnew file mode 100644 index 0000000..050d1db --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/dial.png diff --git a/tools/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png b/tools/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png Binary files differnew file mode 100644 index 0000000..b1f89fb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/dockwidget.png b/tools/designer/src/components/formeditor/images/widgets/dockwidget.png Binary files differnew file mode 100644 index 0000000..9eee04f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/dockwidget.png diff --git a/tools/designer/src/components/formeditor/images/widgets/doublespinbox.png b/tools/designer/src/components/formeditor/images/widgets/doublespinbox.png Binary files differnew file mode 100644 index 0000000..5686ac8 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/doublespinbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/fontcombobox.png b/tools/designer/src/components/formeditor/images/widgets/fontcombobox.png Binary files differnew file mode 100644 index 0000000..6848f15 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/fontcombobox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/frame.png b/tools/designer/src/components/formeditor/images/widgets/frame.png Binary files differnew file mode 100644 index 0000000..68f5da0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/frame.png diff --git a/tools/designer/src/components/formeditor/images/widgets/graphicsview.png b/tools/designer/src/components/formeditor/images/widgets/graphicsview.png Binary files differnew file mode 100644 index 0000000..93fe760 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/graphicsview.png diff --git a/tools/designer/src/components/formeditor/images/widgets/groupbox.png b/tools/designer/src/components/formeditor/images/widgets/groupbox.png Binary files differnew file mode 100644 index 0000000..4025b4d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/groupbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png b/tools/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png Binary files differnew file mode 100644 index 0000000..62fd1ad --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png diff --git a/tools/designer/src/components/formeditor/images/widgets/hscrollbar.png b/tools/designer/src/components/formeditor/images/widgets/hscrollbar.png Binary files differnew file mode 100644 index 0000000..466c58d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/hscrollbar.png diff --git a/tools/designer/src/components/formeditor/images/widgets/hslider.png b/tools/designer/src/components/formeditor/images/widgets/hslider.png Binary files differnew file mode 100644 index 0000000..525bd1c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/hslider.png diff --git a/tools/designer/src/components/formeditor/images/widgets/hsplit.png b/tools/designer/src/components/formeditor/images/widgets/hsplit.png Binary files differnew file mode 100644 index 0000000..1ea8f2a --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/hsplit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/label.png b/tools/designer/src/components/formeditor/images/widgets/label.png Binary files differnew file mode 100644 index 0000000..5d7d7b4 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/label.png diff --git a/tools/designer/src/components/formeditor/images/widgets/lcdnumber.png b/tools/designer/src/components/formeditor/images/widgets/lcdnumber.png Binary files differnew file mode 100644 index 0000000..c3cac18 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/lcdnumber.png diff --git a/tools/designer/src/components/formeditor/images/widgets/line.png b/tools/designer/src/components/formeditor/images/widgets/line.png Binary files differnew file mode 100644 index 0000000..5c64dfb --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/line.png diff --git a/tools/designer/src/components/formeditor/images/widgets/lineedit.png b/tools/designer/src/components/formeditor/images/widgets/lineedit.png Binary files differnew file mode 100644 index 0000000..75fc890 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/lineedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/listbox.png b/tools/designer/src/components/formeditor/images/widgets/listbox.png Binary files differnew file mode 100644 index 0000000..367e67f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/listbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/listview.png b/tools/designer/src/components/formeditor/images/widgets/listview.png Binary files differnew file mode 100644 index 0000000..d1308d5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/listview.png diff --git a/tools/designer/src/components/formeditor/images/widgets/mdiarea.png b/tools/designer/src/components/formeditor/images/widgets/mdiarea.png Binary files differnew file mode 100644 index 0000000..7783dd5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/mdiarea.png diff --git a/tools/designer/src/components/formeditor/images/widgets/plaintextedit.png b/tools/designer/src/components/formeditor/images/widgets/plaintextedit.png Binary files differnew file mode 100644 index 0000000..077bf16 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/plaintextedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/progress.png b/tools/designer/src/components/formeditor/images/widgets/progress.png Binary files differnew file mode 100644 index 0000000..44ae094 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/progress.png diff --git a/tools/designer/src/components/formeditor/images/widgets/pushbutton.png b/tools/designer/src/components/formeditor/images/widgets/pushbutton.png Binary files differnew file mode 100644 index 0000000..61f779c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/pushbutton.png diff --git a/tools/designer/src/components/formeditor/images/widgets/radiobutton.png b/tools/designer/src/components/formeditor/images/widgets/radiobutton.png Binary files differnew file mode 100644 index 0000000..10c1d8c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/radiobutton.png diff --git a/tools/designer/src/components/formeditor/images/widgets/scrollarea.png b/tools/designer/src/components/formeditor/images/widgets/scrollarea.png Binary files differnew file mode 100644 index 0000000..651ea24 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/scrollarea.png diff --git a/tools/designer/src/components/formeditor/images/widgets/spacer.png b/tools/designer/src/components/formeditor/images/widgets/spacer.png Binary files differnew file mode 100644 index 0000000..8a0931b --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/spacer.png diff --git a/tools/designer/src/components/formeditor/images/widgets/spinbox.png b/tools/designer/src/components/formeditor/images/widgets/spinbox.png Binary files differnew file mode 100644 index 0000000..cdd9fe1 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/spinbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/tabbar.png b/tools/designer/src/components/formeditor/images/widgets/tabbar.png Binary files differnew file mode 100644 index 0000000..d5d3783 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/tabbar.png diff --git a/tools/designer/src/components/formeditor/images/widgets/table.png b/tools/designer/src/components/formeditor/images/widgets/table.png Binary files differnew file mode 100644 index 0000000..4bbd9c2 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/table.png diff --git a/tools/designer/src/components/formeditor/images/widgets/tabwidget.png b/tools/designer/src/components/formeditor/images/widgets/tabwidget.png Binary files differnew file mode 100644 index 0000000..1254bb6 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/tabwidget.png diff --git a/tools/designer/src/components/formeditor/images/widgets/textedit.png b/tools/designer/src/components/formeditor/images/widgets/textedit.png Binary files differnew file mode 100644 index 0000000..32e897d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/textedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/timeedit.png b/tools/designer/src/components/formeditor/images/widgets/timeedit.png Binary files differnew file mode 100644 index 0000000..c66d91b --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/timeedit.png diff --git a/tools/designer/src/components/formeditor/images/widgets/toolbox.png b/tools/designer/src/components/formeditor/images/widgets/toolbox.png Binary files differnew file mode 100644 index 0000000..2ab71dc --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/toolbox.png diff --git a/tools/designer/src/components/formeditor/images/widgets/toolbutton.png b/tools/designer/src/components/formeditor/images/widgets/toolbutton.png Binary files differnew file mode 100644 index 0000000..0bff069 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/toolbutton.png diff --git a/tools/designer/src/components/formeditor/images/widgets/vline.png b/tools/designer/src/components/formeditor/images/widgets/vline.png Binary files differnew file mode 100644 index 0000000..35a7300 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/vline.png diff --git a/tools/designer/src/components/formeditor/images/widgets/vscrollbar.png b/tools/designer/src/components/formeditor/images/widgets/vscrollbar.png Binary files differnew file mode 100644 index 0000000..28b7c40 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/vscrollbar.png diff --git a/tools/designer/src/components/formeditor/images/widgets/vslider.png b/tools/designer/src/components/formeditor/images/widgets/vslider.png Binary files differnew file mode 100644 index 0000000..59f06ba --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/vslider.png diff --git a/tools/designer/src/components/formeditor/images/widgets/vspacer.png b/tools/designer/src/components/formeditor/images/widgets/vspacer.png Binary files differnew file mode 100644 index 0000000..ce5e8bd --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/vspacer.png diff --git a/tools/designer/src/components/formeditor/images/widgets/widget.png b/tools/designer/src/components/formeditor/images/widgets/widget.png Binary files differnew file mode 100644 index 0000000..1cf960e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/widget.png diff --git a/tools/designer/src/components/formeditor/images/widgets/widgetstack.png b/tools/designer/src/components/formeditor/images/widgets/widgetstack.png Binary files differnew file mode 100644 index 0000000..2c6964e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/widgetstack.png diff --git a/tools/designer/src/components/formeditor/images/widgets/wizard.png b/tools/designer/src/components/formeditor/images/widgets/wizard.png Binary files differnew file mode 100644 index 0000000..7c0e107 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/widgets/wizard.png diff --git a/tools/designer/src/components/formeditor/images/win/adjustsize.png b/tools/designer/src/components/formeditor/images/win/adjustsize.png Binary files differnew file mode 100644 index 0000000..3cda333 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/adjustsize.png diff --git a/tools/designer/src/components/formeditor/images/win/back.png b/tools/designer/src/components/formeditor/images/win/back.png Binary files differnew file mode 100644 index 0000000..e58177f --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/back.png diff --git a/tools/designer/src/components/formeditor/images/win/buddytool.png b/tools/designer/src/components/formeditor/images/win/buddytool.png Binary files differnew file mode 100644 index 0000000..4cd968b --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/buddytool.png diff --git a/tools/designer/src/components/formeditor/images/win/down.png b/tools/designer/src/components/formeditor/images/win/down.png Binary files differnew file mode 100644 index 0000000..29d1d44 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/down.png diff --git a/tools/designer/src/components/formeditor/images/win/editbreaklayout.png b/tools/designer/src/components/formeditor/images/win/editbreaklayout.png Binary files differnew file mode 100644 index 0000000..07c5fae --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editbreaklayout.png diff --git a/tools/designer/src/components/formeditor/images/win/editcopy.png b/tools/designer/src/components/formeditor/images/win/editcopy.png Binary files differnew file mode 100644 index 0000000..1121b47 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editcopy.png diff --git a/tools/designer/src/components/formeditor/images/win/editcut.png b/tools/designer/src/components/formeditor/images/win/editcut.png Binary files differnew file mode 100644 index 0000000..4b6c82c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editcut.png diff --git a/tools/designer/src/components/formeditor/images/win/editdelete.png b/tools/designer/src/components/formeditor/images/win/editdelete.png Binary files differnew file mode 100644 index 0000000..5a42514 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editdelete.png diff --git a/tools/designer/src/components/formeditor/images/win/editform.png b/tools/designer/src/components/formeditor/images/win/editform.png Binary files differnew file mode 100644 index 0000000..452fcd8 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editform.png diff --git a/tools/designer/src/components/formeditor/images/win/editgrid.png b/tools/designer/src/components/formeditor/images/win/editgrid.png Binary files differnew file mode 100644 index 0000000..789bf7d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editgrid.png diff --git a/tools/designer/src/components/formeditor/images/win/edithlayout.png b/tools/designer/src/components/formeditor/images/win/edithlayout.png Binary files differnew file mode 100644 index 0000000..4dd3f0c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/edithlayout.png diff --git a/tools/designer/src/components/formeditor/images/win/edithlayoutsplit.png b/tools/designer/src/components/formeditor/images/win/edithlayoutsplit.png Binary files differnew file mode 100644 index 0000000..2dcc690 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/edithlayoutsplit.png diff --git a/tools/designer/src/components/formeditor/images/win/editlower.png b/tools/designer/src/components/formeditor/images/win/editlower.png Binary files differnew file mode 100644 index 0000000..ba63094 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editlower.png diff --git a/tools/designer/src/components/formeditor/images/win/editpaste.png b/tools/designer/src/components/formeditor/images/win/editpaste.png Binary files differnew file mode 100644 index 0000000..ffab15a --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editpaste.png diff --git a/tools/designer/src/components/formeditor/images/win/editraise.png b/tools/designer/src/components/formeditor/images/win/editraise.png Binary files differnew file mode 100644 index 0000000..bb8362c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editraise.png diff --git a/tools/designer/src/components/formeditor/images/win/editvlayout.png b/tools/designer/src/components/formeditor/images/win/editvlayout.png Binary files differnew file mode 100644 index 0000000..7ad28fd --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editvlayout.png diff --git a/tools/designer/src/components/formeditor/images/win/editvlayoutsplit.png b/tools/designer/src/components/formeditor/images/win/editvlayoutsplit.png Binary files differnew file mode 100644 index 0000000..720e18b --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/editvlayoutsplit.png diff --git a/tools/designer/src/components/formeditor/images/win/filenew.png b/tools/designer/src/components/formeditor/images/win/filenew.png Binary files differnew file mode 100644 index 0000000..af5d122 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/filenew.png diff --git a/tools/designer/src/components/formeditor/images/win/fileopen.png b/tools/designer/src/components/formeditor/images/win/fileopen.png Binary files differnew file mode 100644 index 0000000..fc6f17e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/fileopen.png diff --git a/tools/designer/src/components/formeditor/images/win/filesave.png b/tools/designer/src/components/formeditor/images/win/filesave.png Binary files differnew file mode 100644 index 0000000..8feec99 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/filesave.png diff --git a/tools/designer/src/components/formeditor/images/win/forward.png b/tools/designer/src/components/formeditor/images/win/forward.png Binary files differnew file mode 100644 index 0000000..34b91f0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/forward.png diff --git a/tools/designer/src/components/formeditor/images/win/insertimage.png b/tools/designer/src/components/formeditor/images/win/insertimage.png Binary files differnew file mode 100644 index 0000000..cfab637 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/insertimage.png diff --git a/tools/designer/src/components/formeditor/images/win/minus.png b/tools/designer/src/components/formeditor/images/win/minus.png Binary files differnew file mode 100644 index 0000000..c0dc274 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/minus.png diff --git a/tools/designer/src/components/formeditor/images/win/plus.png b/tools/designer/src/components/formeditor/images/win/plus.png Binary files differnew file mode 100644 index 0000000..ecf0589 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/plus.png diff --git a/tools/designer/src/components/formeditor/images/win/redo.png b/tools/designer/src/components/formeditor/images/win/redo.png Binary files differnew file mode 100644 index 0000000..686ad14 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/redo.png diff --git a/tools/designer/src/components/formeditor/images/win/resourceeditortool.png b/tools/designer/src/components/formeditor/images/win/resourceeditortool.png Binary files differnew file mode 100644 index 0000000..cc9cb58 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/resourceeditortool.png diff --git a/tools/designer/src/components/formeditor/images/win/signalslottool.png b/tools/designer/src/components/formeditor/images/win/signalslottool.png Binary files differnew file mode 100644 index 0000000..e80fd1c --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/signalslottool.png diff --git a/tools/designer/src/components/formeditor/images/win/tabordertool.png b/tools/designer/src/components/formeditor/images/win/tabordertool.png Binary files differnew file mode 100644 index 0000000..7e6e2de --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/tabordertool.png diff --git a/tools/designer/src/components/formeditor/images/win/textanchor.png b/tools/designer/src/components/formeditor/images/win/textanchor.png Binary files differnew file mode 100644 index 0000000..1911ab0 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textanchor.png diff --git a/tools/designer/src/components/formeditor/images/win/textbold.png b/tools/designer/src/components/formeditor/images/win/textbold.png Binary files differnew file mode 100644 index 0000000..9cbc713 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textbold.png diff --git a/tools/designer/src/components/formeditor/images/win/textcenter.png b/tools/designer/src/components/formeditor/images/win/textcenter.png Binary files differnew file mode 100644 index 0000000..11efb4b --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textcenter.png diff --git a/tools/designer/src/components/formeditor/images/win/textitalic.png b/tools/designer/src/components/formeditor/images/win/textitalic.png Binary files differnew file mode 100644 index 0000000..b30ce14 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textitalic.png diff --git a/tools/designer/src/components/formeditor/images/win/textjustify.png b/tools/designer/src/components/formeditor/images/win/textjustify.png Binary files differnew file mode 100644 index 0000000..9de0c88 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textjustify.png diff --git a/tools/designer/src/components/formeditor/images/win/textleft.png b/tools/designer/src/components/formeditor/images/win/textleft.png Binary files differnew file mode 100644 index 0000000..16f80bc --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textleft.png diff --git a/tools/designer/src/components/formeditor/images/win/textright.png b/tools/designer/src/components/formeditor/images/win/textright.png Binary files differnew file mode 100644 index 0000000..16872df --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textright.png diff --git a/tools/designer/src/components/formeditor/images/win/textsubscript.png b/tools/designer/src/components/formeditor/images/win/textsubscript.png Binary files differnew file mode 100644 index 0000000..d86347d --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textsubscript.png diff --git a/tools/designer/src/components/formeditor/images/win/textsuperscript.png b/tools/designer/src/components/formeditor/images/win/textsuperscript.png Binary files differnew file mode 100644 index 0000000..9109965 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textsuperscript.png diff --git a/tools/designer/src/components/formeditor/images/win/textunder.png b/tools/designer/src/components/formeditor/images/win/textunder.png Binary files differnew file mode 100644 index 0000000..c72eff5 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/textunder.png diff --git a/tools/designer/src/components/formeditor/images/win/undo.png b/tools/designer/src/components/formeditor/images/win/undo.png Binary files differnew file mode 100644 index 0000000..c3b8c513 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/undo.png diff --git a/tools/designer/src/components/formeditor/images/win/up.png b/tools/designer/src/components/formeditor/images/win/up.png Binary files differnew file mode 100644 index 0000000..e437312 --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/up.png diff --git a/tools/designer/src/components/formeditor/images/win/widgettool.png b/tools/designer/src/components/formeditor/images/win/widgettool.png Binary files differnew file mode 100644 index 0000000..a52224e --- /dev/null +++ b/tools/designer/src/components/formeditor/images/win/widgettool.png diff --git a/tools/designer/src/components/formeditor/itemview_propertysheet.cpp b/tools/designer/src/components/formeditor/itemview_propertysheet.cpp new file mode 100644 index 0000000..609ce84 --- /dev/null +++ b/tools/designer/src/components/formeditor/itemview_propertysheet.cpp @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemview_propertysheet.h" + +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtGui/QAbstractItemView> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +struct Property { + Property() : m_sheet(0),m_id(-1) {} + Property(QDesignerPropertySheetExtension *sheet, int id) + : m_sheet(sheet), m_id(id) {} + bool operator==(const Property &p) { return m_sheet == p.m_sheet && m_id == p.m_id; } + uint qHash() { + return ((int)(m_sheet-(QDesignerPropertySheetExtension*)(0))) & m_id; + } + + QDesignerPropertySheetExtension *m_sheet; + int m_id; +}; + +class ItemViewPropertySheetPrivate { + +public: + ItemViewPropertySheetPrivate(QHeaderView *horizontalHeader, + QHeaderView *verticalHeader, + QObject *parent); + + inline void createMapping(int fakeId, QHeaderView *header, const QString &headerName); + inline QStringList realPropertyNames(); + inline QString fakePropertyName(const QString &prefix, const QString &realName); + + QDesignerFormEditorInterface *m_core; + + // Maps index of fake property + // to index of real property in respective sheet + QHash<int, Property> m_propertyIdMap; + + // Maps name of fake property + // to name of real property + QHash<QString, QString> m_propertyNameMap; + +private: + static QDesignerFormEditorInterface *formEditorForObject(QObject *o); + + QHeaderView *m_hHeader; + QHeaderView *m_vHeader; + QHash<QHeaderView *, QDesignerPropertySheetExtension *> m_propertySheet; + QStringList m_realPropertyNames; +}; + +// Name of the fake group +static const char *headerGroup = "Header"; + +// Name of the real properties +static const char *visibleProperty = "visible"; +static const char *cascadingSectionResizesProperty = "cascadingSectionResizes"; +static const char *defaultSectionSizeProperty = "defaultSectionSize"; +static const char *highlightSectionsProperty = "highlightSections"; +static const char *minimumSectionSizeProperty = "minimumSectionSize"; +static const char *showSortIndicatorProperty = "showSortIndicator"; +static const char *stretchLastSectionProperty = "stretchLastSection"; +} // namespace qdesigner_internal + +using namespace qdesigner_internal; + + +/***************** ItemViewPropertySheetPrivate *********************/ + +ItemViewPropertySheetPrivate::ItemViewPropertySheetPrivate(QHeaderView *horizontalHeader, + QHeaderView *verticalHeader, + QObject *parent) + : m_core(formEditorForObject(parent)), + m_hHeader(horizontalHeader), + m_vHeader(verticalHeader) +{ + if (horizontalHeader) + m_propertySheet.insert(horizontalHeader, + qt_extension<QDesignerPropertySheetExtension*> + (m_core->extensionManager(), horizontalHeader)); + if (verticalHeader) + m_propertySheet.insert(verticalHeader, + qt_extension<QDesignerPropertySheetExtension*> + (m_core->extensionManager(), verticalHeader)); +} + +// Find the form editor in the hierarchy. +// We know that the parent of the sheet is the extension manager +// whose parent is the core. +QDesignerFormEditorInterface *ItemViewPropertySheetPrivate::formEditorForObject(QObject *o) +{ + do { + if (QDesignerFormEditorInterface* core = qobject_cast<QDesignerFormEditorInterface*>(o)) + return core; + o = o->parent(); + } while(o); + Q_ASSERT(o); + return 0; +} + +void ItemViewPropertySheetPrivate::createMapping(int fakeId, QHeaderView *header, + const QString &headerName) +{ + const int realPropertyId = m_propertySheet.value(header)->indexOf(headerName); + QDesignerPropertySheetExtension *propertySheet = m_propertySheet.value(header); + m_propertyIdMap.insert(fakeId, Property(propertySheet, realPropertyId)); +} + +QStringList ItemViewPropertySheetPrivate::realPropertyNames() +{ + if (m_realPropertyNames.isEmpty()) + m_realPropertyNames + << QLatin1String(visibleProperty) + << QLatin1String(cascadingSectionResizesProperty) + << QLatin1String(defaultSectionSizeProperty) + << QLatin1String(highlightSectionsProperty) + << QLatin1String(minimumSectionSizeProperty) + << QLatin1String(showSortIndicatorProperty) + << QLatin1String(stretchLastSectionProperty); + return m_realPropertyNames; +} + +QString ItemViewPropertySheetPrivate::fakePropertyName(const QString &prefix, + const QString &realName) +{ + // prefix = "header", realPropertyName = "isVisible" returns "headerIsVisible" + QString fakeName = prefix + realName.at(0).toUpper() + realName.mid(1); + m_propertyNameMap.insert(fakeName, realName); + return fakeName; +} + +/***************** ItemViewPropertySheet *********************/ + +/*! + \class qdesigner_internal::ItemViewPropertySheet + + \brief + Adds header fake properties to QTreeView and QTableView objects + + QHeaderView objects are currently not shown in the object inspector. + This class adds some fake properties to the property sheet + of QTreeView and QTableView objects that nevertheless allow the manipulation + of the headers attached to the item view object. + + Currently the defaultAlignment property is not shown because the property sheet + would only show integers, instead of the Qt::Alignment enumeration. + + The fake properties here need special handling in QDesignerResource, uiloader and uic. + */ + +ItemViewPropertySheet::ItemViewPropertySheet(QTreeView *treeViewObject, QObject *parent) + : QDesignerPropertySheet(treeViewObject, parent), + d(new ItemViewPropertySheetPrivate(treeViewObject->header(), 0, parent)) +{ + QHeaderView *hHeader = treeViewObject->header(); + + foreach (const QString &realPropertyName, d->realPropertyNames()) { + const QString fakePropertyName + = d->fakePropertyName(QLatin1String("header"), realPropertyName); + d->createMapping(createFakeProperty(fakePropertyName, 0), hHeader, realPropertyName); + } + + foreach (int id, d->m_propertyIdMap.keys()) { + setAttribute(id, true); + setPropertyGroup(id, QLatin1String(headerGroup)); + } +} + + +ItemViewPropertySheet::ItemViewPropertySheet(QTableView *tableViewObject, QObject *parent) + : QDesignerPropertySheet(tableViewObject, parent), + d(new ItemViewPropertySheetPrivate(tableViewObject->horizontalHeader(), + tableViewObject->verticalHeader(), parent)) +{ + QHeaderView *hHeader = tableViewObject->horizontalHeader(); + QHeaderView *vHeader = tableViewObject->verticalHeader(); + + foreach (const QString &realPropertyName, d->realPropertyNames()) { + const QString fakePropertyName + = d->fakePropertyName(QLatin1String("horizontalHeader"), realPropertyName); + d->createMapping(createFakeProperty(fakePropertyName, 0), hHeader, realPropertyName); + } + foreach (const QString &realPropertyName, d->realPropertyNames()) { + const QString fakePropertyName + = d->fakePropertyName(QLatin1String("verticalHeader"), realPropertyName); + d->createMapping(createFakeProperty(fakePropertyName, 0), vHeader, realPropertyName); + } + + foreach (int id, d->m_propertyIdMap.keys()) { + setAttribute(id, true); + setPropertyGroup(id, QLatin1String(headerGroup)); + } +} + +ItemViewPropertySheet::~ItemViewPropertySheet() +{ + delete d; +} + +/*! + Returns the mapping of fake property names to real property names + */ +QHash<QString,QString> ItemViewPropertySheet::propertyNameMap() const +{ + return d->m_propertyNameMap; +} + +QVariant ItemViewPropertySheet::property(int index) const +{ + if (d->m_propertyIdMap.contains(index)) { + Property realProperty = d->m_propertyIdMap.value(index); + return realProperty.m_sheet->property(realProperty.m_id); + } else { + return QDesignerPropertySheet::property(index); + } +} + +void ItemViewPropertySheet::setProperty(int index, const QVariant &value) +{ + if (d->m_propertyIdMap.contains(index)) { + Property realProperty = d->m_propertyIdMap.value(index); + realProperty.m_sheet->setProperty(realProperty.m_id, value); + } else { + QDesignerPropertySheet::setProperty(index, value); + } +} + +void ItemViewPropertySheet::setChanged(int index, bool changed) +{ + if (d->m_propertyIdMap.contains(index)) { + Property realProperty = d->m_propertyIdMap.value(index); + realProperty.m_sheet->setChanged(realProperty.m_id, changed); + } + QDesignerPropertySheet::setChanged(index, changed); +} + +bool ItemViewPropertySheet::reset(int index) +{ + if (d->m_propertyIdMap.contains(index)) { + Property realProperty = d->m_propertyIdMap.value(index); + return realProperty.m_sheet->reset(realProperty.m_id); + } else { + return QDesignerPropertySheet::reset(index); + } +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/itemview_propertysheet.h b/tools/designer/src/components/formeditor/itemview_propertysheet.h new file mode 100644 index 0000000..e4c80dd --- /dev/null +++ b/tools/designer/src/components/formeditor/itemview_propertysheet.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ITEMVIEW_PROPERTYSHEET_H +#define ITEMVIEW_PROPERTYSHEET_H + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> + +#include <QtGui/QTreeView> +#include <QtGui/QTableView> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class ItemViewPropertySheetPrivate; + +class ItemViewPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit ItemViewPropertySheet(QTreeView *treeViewObject, QObject *parent = 0); + explicit ItemViewPropertySheet(QTableView *tableViewObject, QObject *parent = 0); + ~ItemViewPropertySheet(); + + QHash<QString,QString> propertyNameMap() const; + + // QDesignerPropertySheet + QVariant property(int index) const; + void setProperty(int index, const QVariant &value); + + void setChanged(int index, bool changed); + + bool reset(int index); + +private: + ItemViewPropertySheetPrivate *d; +}; + +typedef QDesignerPropertySheetFactory<QTreeView, ItemViewPropertySheet> + QTreeViewPropertySheetFactory; +typedef QDesignerPropertySheetFactory<QTableView, ItemViewPropertySheet> + QTableViewPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ITEMVIEW_PROPERTYSHEET_H diff --git a/tools/designer/src/components/formeditor/layout_propertysheet.cpp b/tools/designer/src/components/formeditor/layout_propertysheet.cpp new file mode 100644 index 0000000..a304c6a --- /dev/null +++ b/tools/designer/src/components/formeditor/layout_propertysheet.cpp @@ -0,0 +1,546 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "layout_propertysheet.h" + +// sdk +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerFormEditorInterface> + +// shared +#include <ui4_p.h> +#include <qlayout_widget_p.h> +#include <formbuilderextra_p.h> + +#include <QtGui/QFormLayout> + +#include <QtCore/QHash> +#include <QtCore/QDebug> +#include <QtCore/QTextStream> +#include <QtCore/QByteArray> +#include <QtCore/QRegExp> // Remove once there is an editor for lists + +QT_BEGIN_NAMESPACE + +#define USE_LAYOUT_SIZE_CONSTRAINT + +static const char *leftMargin = "leftMargin"; +static const char *topMargin = "topMargin"; +static const char *rightMargin = "rightMargin"; +static const char *bottomMargin = "bottomMargin"; +static const char *horizontalSpacing = "horizontalSpacing"; +static const char *verticalSpacing = "verticalSpacing"; +static const char *spacing = "spacing"; +static const char *margin = "margin"; +static const char *sizeConstraint = "sizeConstraint"; +static const char *boxStretchPropertyC = "stretch"; +static const char *gridRowStretchPropertyC = "rowStretch"; +static const char *gridColumnStretchPropertyC = "columnStretch"; +static const char *gridRowMinimumHeightPropertyC = "rowMinimumHeight"; +static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth"; + +namespace { + enum LayoutPropertyType { + LayoutPropertyNone, + LayoutPropertyMargin, // Deprecated + LayoutPropertyLeftMargin, + LayoutPropertyTopMargin, + LayoutPropertyRightMargin, + LayoutPropertyBottomMargin, + LayoutPropertySpacing, + LayoutPropertyHorizontalSpacing, + LayoutPropertyVerticalSpacing, + LayoutPropertySizeConstraint, + LayoutPropertyBoxStretch, + LayoutPropertyGridRowStretch, + LayoutPropertyGridColumnStretch, + LayoutPropertyGridRowMinimumHeight, + LayoutPropertyGridColumnMinimumWidth + }; +} + +// Check for a comma-separated list of integers. Used for +// per-cell stretch properties and grid per row/column properties. +// As it works now, they are passed as QByteArray strings. The +// property sheet refuses all invalid values. This could be +// replaced by lists once the property editor can handle them. + +static bool isIntegerList(const QString &s) +{ + // Check for empty string or comma-separated list of integers + static const QRegExp re(QLatin1String("[0-9]+(,[0-9]+)+")); + Q_ASSERT(re.isValid()); + return s.isEmpty() || re.exactMatch(s); +} + +// Quick lookup by name +static LayoutPropertyType layoutPropertyType(const QString &name) +{ + static QHash<QString, LayoutPropertyType> namePropertyMap; + if (namePropertyMap.empty()) { + namePropertyMap.insert(QLatin1String(leftMargin), LayoutPropertyLeftMargin); + namePropertyMap.insert(QLatin1String(topMargin), LayoutPropertyTopMargin); + namePropertyMap.insert(QLatin1String(rightMargin), LayoutPropertyRightMargin); + namePropertyMap.insert(QLatin1String(bottomMargin), LayoutPropertyBottomMargin); + namePropertyMap.insert(QLatin1String(horizontalSpacing), LayoutPropertyHorizontalSpacing); + namePropertyMap.insert(QLatin1String(verticalSpacing), LayoutPropertyVerticalSpacing); + namePropertyMap.insert(QLatin1String(spacing), LayoutPropertySpacing); + namePropertyMap.insert(QLatin1String(margin), LayoutPropertyMargin); + namePropertyMap.insert(QLatin1String(sizeConstraint), LayoutPropertySizeConstraint); + namePropertyMap.insert(QLatin1String(boxStretchPropertyC ), LayoutPropertyBoxStretch); + namePropertyMap.insert(QLatin1String(gridRowStretchPropertyC), LayoutPropertyGridRowStretch); + namePropertyMap.insert(QLatin1String(gridColumnStretchPropertyC), LayoutPropertyGridColumnStretch); + namePropertyMap.insert(QLatin1String(gridRowMinimumHeightPropertyC), LayoutPropertyGridRowMinimumHeight); + namePropertyMap.insert(QLatin1String(gridColumnMinimumWidthPropertyC), LayoutPropertyGridColumnMinimumWidth); + } + return namePropertyMap.value(name, LayoutPropertyNone); +} + +// return the layout margin if it is margin +static int getLayoutMargin(const QLayout *l, LayoutPropertyType type) +{ + int left, top, right, bottom; + l->getContentsMargins(&left, &top, &right, &bottom); + switch (type) { + case LayoutPropertyLeftMargin: + return left; + case LayoutPropertyTopMargin: + return top; + case LayoutPropertyRightMargin: + return right; + case LayoutPropertyBottomMargin: + return bottom; + default: + Q_ASSERT(0); + break; + } + return 0; +} + +// return the layout margin if it is margin +static void setLayoutMargin(QLayout *l, LayoutPropertyType type, int margin) +{ + int left, top, right, bottom; + l->getContentsMargins(&left, &top, &right, &bottom); + switch (type) { + case LayoutPropertyLeftMargin: + left = margin; + break; + case LayoutPropertyTopMargin: + top = margin; + break; + case LayoutPropertyRightMargin: + right = margin; + break; + case LayoutPropertyBottomMargin: + bottom = margin; + break; + default: + Q_ASSERT(0); + break; + } + l->setContentsMargins(left, top, right, bottom); +} + +namespace qdesigner_internal { + +// ---------- LayoutPropertySheet: This sheet is never visible in +// the property editor. Rather, the sheet pulled for QLayoutWidget +// forwards all properties to it. Some properties (grid spacings) must be handled +// manually, as they are QDOC_PROPERTY only and not visible to introspection. Ditto +// for the 4 margins. + +LayoutPropertySheet::LayoutPropertySheet(QLayout *l, QObject *parent) + : QDesignerPropertySheet(l, parent), m_layout(l) +{ + const QString layoutGroup = QLatin1String("Layout"); + int pindex = createFakeProperty(QLatin1String(leftMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(topMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(rightMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(bottomMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + const int visibleMask = LayoutProperties::visibleProperties(m_layout); + if (visibleMask & LayoutProperties::HorizSpacingProperty) { + pindex = createFakeProperty(QLatin1String(horizontalSpacing), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(verticalSpacing), 0); + setPropertyGroup(pindex, layoutGroup); + + setAttribute(indexOf(QLatin1String(spacing)), true); + } + + setAttribute(indexOf(QLatin1String(margin)), true); + // Stretch + if (visibleMask & LayoutProperties::BoxStretchProperty) { + pindex = createFakeProperty(QLatin1String(boxStretchPropertyC), QByteArray()); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + } else { + // Add the grid per-row/column stretch and size limits + if (visibleMask & LayoutProperties::GridColumnStretchProperty) { + const QByteArray empty; + pindex = createFakeProperty(QLatin1String(gridRowStretchPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridColumnStretchPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridRowMinimumHeightPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridColumnMinimumWidthPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + } + } +#ifdef USE_LAYOUT_SIZE_CONSTRAINT + // SizeConstraint cannot possibly be handled as a real property + // as it affects the layout parent widget and thus + // conflicts with Designer's special layout widget. + // It will take effect on the preview only. + pindex = createFakeProperty(QLatin1String(sizeConstraint)); + setPropertyGroup(pindex, layoutGroup); +#endif +} + +LayoutPropertySheet::~LayoutPropertySheet() +{ +} + +void LayoutPropertySheet::setProperty(int index, const QVariant &value) +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + if (QLayoutWidget *lw = qobject_cast<QLayoutWidget *>(m_layout->parent())) { + switch (type) { + case LayoutPropertyLeftMargin: + lw->setLayoutLeftMargin(value.toInt()); + return; + case LayoutPropertyTopMargin: + lw->setLayoutTopMargin(value.toInt()); + return; + case LayoutPropertyRightMargin: + lw->setLayoutRightMargin(value.toInt()); + return; + case LayoutPropertyBottomMargin: + lw->setLayoutBottomMargin(value.toInt()); + return; + case LayoutPropertyMargin: { + const int v = value.toInt(); + lw->setLayoutLeftMargin(v); + lw->setLayoutTopMargin(v); + lw->setLayoutRightMargin(v); + lw->setLayoutBottomMargin(v); + } + return; + default: + break; + } + } + switch (type) { + case LayoutPropertyLeftMargin: + case LayoutPropertyTopMargin: + case LayoutPropertyRightMargin: + case LayoutPropertyBottomMargin: + setLayoutMargin(m_layout, type, value.toInt()); + return; + case LayoutPropertyHorizontalSpacing: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + grid->setHorizontalSpacing(value.toInt()); + return; + } + if (QFormLayout *form = qobject_cast<QFormLayout *>(m_layout)) { + form->setHorizontalSpacing(value.toInt()); + return; + } + break; + case LayoutPropertyVerticalSpacing: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + grid->setVerticalSpacing(value.toInt()); + return; + } + if (QFormLayout *form = qobject_cast<QFormLayout *>(m_layout)) { + form->setVerticalSpacing(value.toInt()); + return; + } + break; + case LayoutPropertyBoxStretch: + // TODO: Remove the regexp check once a proper editor for integer + // lists is in place? + if (QBoxLayout *box = qobject_cast<QBoxLayout *>(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setBoxLayoutStretch(value.toString(), box); + } + break; + case LayoutPropertyGridRowStretch: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setGridLayoutRowStretch(stretch, grid); + } + break; + case LayoutPropertyGridColumnStretch: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setGridLayoutColumnStretch(value.toString(), grid); + } + break; + case LayoutPropertyGridRowMinimumHeight: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + const QString minSize = value.toString(); + if (isIntegerList(minSize)) + QFormBuilderExtra::setGridLayoutRowMinimumHeight(minSize, grid); + } + break; + case LayoutPropertyGridColumnMinimumWidth: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) { + const QString minSize = value.toString(); + if (isIntegerList(minSize)) + QFormBuilderExtra::setGridLayoutColumnMinimumWidth(minSize, grid); + } + break; + default: + break; + } + QDesignerPropertySheet::setProperty(index, value); +} + +QVariant LayoutPropertySheet::property(int index) const +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + if (const QLayoutWidget *lw = qobject_cast<QLayoutWidget *>(m_layout->parent())) { + switch (type) { + case LayoutPropertyLeftMargin: + return lw->layoutLeftMargin(); + case LayoutPropertyTopMargin: + return lw->layoutTopMargin(); + case LayoutPropertyRightMargin: + return lw->layoutRightMargin(); + case LayoutPropertyBottomMargin: + return lw->layoutBottomMargin(); + default: + break; + } + } + switch (type) { + case LayoutPropertyLeftMargin: + case LayoutPropertyTopMargin: + case LayoutPropertyRightMargin: + case LayoutPropertyBottomMargin: + return getLayoutMargin(m_layout, type); + case LayoutPropertyHorizontalSpacing: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return grid->horizontalSpacing(); + if (const QFormLayout *form = qobject_cast<QFormLayout *>(m_layout)) + return form->horizontalSpacing(); + break; + case LayoutPropertyVerticalSpacing: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return grid->verticalSpacing(); + if (const QFormLayout *form = qobject_cast<QFormLayout *>(m_layout)) + return form->verticalSpacing(); + case LayoutPropertyBoxStretch: + if (const QBoxLayout *box = qobject_cast<QBoxLayout *>(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::boxLayoutStretch(box).toUtf8())); + break; + case LayoutPropertyGridRowStretch: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutRowStretch(grid).toUtf8())); + break; + case LayoutPropertyGridColumnStretch: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutColumnStretch(grid).toUtf8())); + break; + case LayoutPropertyGridRowMinimumHeight: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutRowMinimumHeight(grid).toUtf8())); + break; + case LayoutPropertyGridColumnMinimumWidth: + if (const QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutColumnMinimumWidth(grid).toUtf8())); + break; + default: + break; + } + return QDesignerPropertySheet::property(index); +} + +bool LayoutPropertySheet::reset(int index) +{ + int left, top, right, bottom; + m_layout->getContentsMargins(&left, &top, &right, &bottom); + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + bool rc = true; + switch (type) { + case LayoutPropertyLeftMargin: + m_layout->setContentsMargins(-1, top, right, bottom); + break; + case LayoutPropertyTopMargin: + m_layout->setContentsMargins(left, -1, right, bottom); + break; + case LayoutPropertyRightMargin: + m_layout->setContentsMargins(left, top, -1, bottom); + break; + case LayoutPropertyBottomMargin: + m_layout->setContentsMargins(left, top, right, -1); + break; + case LayoutPropertyBoxStretch: + if (QBoxLayout *box = qobject_cast<QBoxLayout *>(m_layout)) + QFormBuilderExtra::clearBoxLayoutStretch(box); + break; + case LayoutPropertyGridRowStretch: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + QFormBuilderExtra::clearGridLayoutRowStretch(grid); + break; + case LayoutPropertyGridColumnStretch: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + QFormBuilderExtra::clearGridLayoutColumnStretch(grid); + break; + case LayoutPropertyGridRowMinimumHeight: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + QFormBuilderExtra::clearGridLayoutRowMinimumHeight(grid); + break; + case LayoutPropertyGridColumnMinimumWidth: + if (QGridLayout *grid = qobject_cast<QGridLayout *>(m_layout)) + QFormBuilderExtra::clearGridLayoutColumnMinimumWidth(grid); + break; + default: + rc = QDesignerPropertySheet::reset(index); + break; + } + return rc; +} + +void LayoutPropertySheet::setChanged(int index, bool changed) +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + switch (type) { + case LayoutPropertySpacing: + if (LayoutProperties::visibleProperties(m_layout) & LayoutProperties::HorizSpacingProperty) { + setChanged(indexOf(QLatin1String(horizontalSpacing)), changed); + setChanged(indexOf(QLatin1String(verticalSpacing)), changed); + } + break; + case LayoutPropertyMargin: + setChanged(indexOf(QLatin1String(leftMargin)), changed); + setChanged(indexOf(QLatin1String(topMargin)), changed); + setChanged(indexOf(QLatin1String(rightMargin)), changed); + setChanged(indexOf(QLatin1String(bottomMargin)), changed); + break; + default: + break; + } + QDesignerPropertySheet::setChanged(index, changed); +} + +void LayoutPropertySheet::stretchAttributesToDom(QDesignerFormEditorInterface *core, QLayout *lt, DomLayout *domLayout) +{ + // Check if the respective stretch properties of the layout are changed. + // If so, set them to the DOM + const int visibleMask = LayoutProperties::visibleProperties(lt); + if (!(visibleMask & (LayoutProperties::BoxStretchProperty|LayoutProperties::GridColumnStretchProperty|LayoutProperties::GridRowStretchProperty))) + return; + const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), lt); + Q_ASSERT(sheet); + + // Stretch + if (visibleMask & LayoutProperties::BoxStretchProperty) { + const int index = sheet->indexOf(QLatin1String(boxStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridColumnStretchProperty) { + const int index = sheet->indexOf(QLatin1String(gridColumnStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeColumnStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridRowStretchProperty) { + const int index = sheet->indexOf(QLatin1String(gridRowStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeRowStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridRowMinimumHeightProperty) { + const int index = sheet->indexOf(QLatin1String(gridRowMinimumHeightPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeRowMinimumHeight(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridColumnMinimumWidthProperty) { + const int index = sheet->indexOf(QLatin1String(gridColumnMinimumWidthPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeColumnMinimumWidth(sheet->property(index).toString()); + } +} + +void LayoutPropertySheet::markChangedStretchProperties(QDesignerFormEditorInterface *core, QLayout *lt, const DomLayout *domLayout) +{ + // While the actual values are applied by the form builder, we still need + // to mark them as 'changed'. + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), lt); + Q_ASSERT(sheet); + if (!domLayout->attributeStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(boxStretchPropertyC)), true); + if (!domLayout->attributeRowStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridRowStretchPropertyC)), true); + if (!domLayout->attributeColumnStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridColumnStretchPropertyC)), true); + if (!domLayout->attributeColumnMinimumWidth().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridColumnMinimumWidthPropertyC)), true); + if (!domLayout->attributeRowMinimumHeight().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridRowMinimumHeightPropertyC)), true); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/layout_propertysheet.h b/tools/designer/src/components/formeditor/layout_propertysheet.h new file mode 100644 index 0000000..bb2b785 --- /dev/null +++ b/tools/designer/src/components/formeditor/layout_propertysheet.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAYOUT_PROPERTYSHEET_H +#define LAYOUT_PROPERTYSHEET_H + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> + +#include <QtGui/QLayout> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class DomLayout; + +namespace qdesigner_internal { + +class LayoutPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit LayoutPropertySheet(QLayout *object, QObject *parent = 0); + virtual ~LayoutPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual QVariant property(int index) const; + virtual bool reset(int index); + void setChanged(int index, bool changed); + + static void stretchAttributesToDom(QDesignerFormEditorInterface *core, QLayout *lt, DomLayout *domLayout); + static void markChangedStretchProperties(QDesignerFormEditorInterface *core, QLayout *lt, const DomLayout *domLayout); + +private: + QLayout *m_layout; +}; + +typedef QDesignerPropertySheetFactory<QLayout, LayoutPropertySheet> LayoutPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LAYOUT_PROPERTYSHEET_H diff --git a/tools/designer/src/components/formeditor/line_propertysheet.cpp b/tools/designer/src/components/formeditor/line_propertysheet.cpp new file mode 100644 index 0000000..d13779e --- /dev/null +++ b/tools/designer/src/components/formeditor/line_propertysheet.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "line_propertysheet.h" +#include "formwindow.h" + +// sdk +#include <QtDesigner/QExtensionManager> + +#include <QtGui/QLayout> +#include <QtCore/QMetaObject> +#include <QtCore/QMetaProperty> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +LinePropertySheet::LinePropertySheet(Line *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +LinePropertySheet::~LinePropertySheet() +{ +} + +bool LinePropertySheet::isVisible(int index) const +{ + const QString name = propertyName(index); + + if (name == QLatin1String("frameShape")) + return false; + return QDesignerPropertySheet::isVisible(index); +} + +void LinePropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +QString LinePropertySheet::propertyGroup(int index) const +{ + return QDesignerPropertySheet::propertyGroup(index); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/line_propertysheet.h b/tools/designer/src/components/formeditor/line_propertysheet.h new file mode 100644 index 0000000..5149cac --- /dev/null +++ b/tools/designer/src/components/formeditor/line_propertysheet.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LINE_PROPERTYSHEET_H +#define LINE_PROPERTYSHEET_H + +#include <qdesigner_propertysheet_p.h> +#include <qdesigner_widget_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class LinePropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit LinePropertySheet(Line *object, QObject *parent = 0); + virtual ~LinePropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + virtual QString propertyGroup(int index) const; +}; + +typedef QDesignerPropertySheetFactory<Line, LinePropertySheet> LinePropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LINE_PROPERTYSHEET_H diff --git a/tools/designer/src/components/formeditor/previewactiongroup.cpp b/tools/designer/src/components/formeditor/previewactiongroup.cpp new file mode 100644 index 0000000..aa52872 --- /dev/null +++ b/tools/designer/src/components/formeditor/previewactiongroup.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewactiongroup.h" + +#include <deviceprofile_p.h> +#include <shared_settings_p.h> + +#include <QtGui/QStyleFactory> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +enum { MaxDeviceActions = 20 }; + +namespace qdesigner_internal { + +PreviewActionGroup::PreviewActionGroup(QDesignerFormEditorInterface *core, QObject *parent) : + QActionGroup(parent), + m_core(core) +{ + /* Create a list of up to MaxDeviceActions invisible actions to be + * populated with device profiles (actiondata: index) followed by the + * standard style actions (actiondata: style name). */ + connect(this, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); + setExclusive(true); + + const QString objNamePostfix = QLatin1String("_action"); + // Create invisible actions for devices. Set index as action data. + QString objNamePrefix = QLatin1String("__qt_designer_device_"); + for (int i = 0; i < MaxDeviceActions; i++) { + QAction *a = new QAction(this); + QString objName = objNamePrefix; + objName += QString::number(i); + objName += objNamePostfix; + a->setObjectName(objName); + a->setVisible(false); + a->setData(i); + addAction(a); + } + // Create separator at index MaxDeviceActions + QAction *sep = new QAction(this); + sep->setObjectName(QLatin1String("__qt_designer_deviceseparator")); + sep->setSeparator(true); + sep->setVisible(false); + addAction(sep); + // Populate devices + updateDeviceProfiles(); + + // Add style actions + const QStringList styles = QStyleFactory::keys(); + const QStringList::const_iterator cend = styles.constEnd(); + // Make sure ObjectName is unique in case toolbar solution is used. + objNamePrefix = QLatin1String("__qt_designer_style_"); + // Create styles. Set style name string as action data. + for (QStringList::const_iterator it = styles.constBegin(); it != cend ;++it) { + QAction *a = new QAction(tr("%1 Style").arg(*it), this); + QString objName = objNamePrefix; + objName += *it; + objName += objNamePostfix; + a->setObjectName(objName); + a->setData(*it); + addAction(a); + } +} + +void PreviewActionGroup::updateDeviceProfiles() +{ + typedef QList<DeviceProfile> DeviceProfileList; + typedef QList<QAction *> ActionList; + + const QDesignerSharedSettings settings(m_core); + const DeviceProfileList profiles = settings.deviceProfiles(); + const ActionList al = actions(); + // Separator? + const bool hasProfiles = !profiles.empty(); + al.at(MaxDeviceActions)->setVisible(hasProfiles); + int index = 0; + if (hasProfiles) { + // Make actions visible + const int maxIndex = qMin(static_cast<int>(MaxDeviceActions), profiles.size()); + for (; index < maxIndex; index++) { + const QString name = profiles.at(index).name(); + al.at(index)->setText(name); + al.at(index)->setVisible(true); + } + } + // Hide rest + for ( ; index < MaxDeviceActions; index++) + al.at(index)->setVisible(false); +} + +void PreviewActionGroup::slotTriggered(QAction *a) +{ + // Device or style according to data. + const QVariant data = a->data(); + switch (data.type()) { + case QVariant::String: + emit preview(data.toString(), -1); + break; + case QVariant::Int: + emit preview(QString(), data.toInt()); + break; + default: + break; + } +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/previewactiongroup.h b/tools/designer/src/components/formeditor/previewactiongroup.h new file mode 100644 index 0000000..851f554 --- /dev/null +++ b/tools/designer/src/components/formeditor/previewactiongroup.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PREVIEWACTIONGROUP_H +#define PREVIEWACTIONGROUP_H + +#include <QtGui/QActionGroup> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +/* PreviewActionGroup: To be used as a submenu for 'Preview in...' + * Offers a menu of styles and device profiles. */ + +class PreviewActionGroup : public QActionGroup +{ + Q_DISABLE_COPY(PreviewActionGroup) + Q_OBJECT +public: + explicit PreviewActionGroup(QDesignerFormEditorInterface *core, QObject *parent = 0); + +signals: + void preview(const QString &style, int deviceProfileIndex); + +public slots: + void updateDeviceProfiles(); + +private slots: + void slotTriggered(QAction *); + +private: + QDesignerFormEditorInterface *m_core; +}; +} + +QT_END_NAMESPACE + +#endif // PREVIEWACTIONGROUP_H diff --git a/tools/designer/src/components/formeditor/qdesigner_resource.cpp b/tools/designer/src/components/formeditor/qdesigner_resource.cpp new file mode 100644 index 0000000..75a53b7 --- /dev/null +++ b/tools/designer/src/components/formeditor/qdesigner_resource.cpp @@ -0,0 +1,2665 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_resource.h" +#include "formwindow.h" +#include "dynamicpropertysheet.h" +#include "qdesigner_tabwidget_p.h" +#include "qdesigner_toolbox_p.h" +#include "qdesigner_stackedbox_p.h" +#include "qdesigner_toolbar_p.h" +#include "qdesigner_dockwidget_p.h" +#include "qdesigner_menu_p.h" +#include "qdesigner_menubar_p.h" +#include "qdesigner_membersheet_p.h" +#include "qtresourcemodel_p.h" +#include "qmdiarea_container.h" +#include "qwizard_container.h" +#include "itemview_propertysheet.h" +#include "layout_propertysheet.h" + +#include <ui4_p.h> +#include <formbuilderextra_p.h> +#include <resourcebuilder_p.h> +#include <textbuilder_p.h> +#include <qdesigner_widgetitem_p.h> + +// shared +#include <widgetdatabase_p.h> +#include <metadatabase_p.h> +#include <layout_p.h> +#include <layoutinfo_p.h> +#include <spacer_widget_p.h> +#include <pluginmanager_p.h> +#include <widgetfactory_p.h> +#include <abstractlanguage.h> +#include <abstractintrospection_p.h> + +#include <qlayout_widget_p.h> +#include <qdesigner_utils_p.h> +#include <ui4_p.h> + +// sdk +#include <QtDesigner/QDesignerPropertySheetExtension> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerExtraInfoExtension> +#include <QtDesigner/QDesignerFormWindowToolInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerContainerExtension> +#include <abstractdialoggui_p.h> + +#include <QtGui/QMenu> +#include <QtGui/QMessageBox> +#include <QtGui/QLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QTabWidget> +#include <QtGui/QToolBox> +#include <QtGui/QStackedWidget> +#include <QtGui/QToolBar> +#include <QtGui/QTabBar> +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QButtonGroup> +#include <QtGui/QApplication> +#include <QtGui/QMainWindow> +#include <QtGui/QSplitter> +#include <QtGui/QMdiArea> +#include <QtGui/QWorkspace> +#include <QtGui/QMenuBar> +#include <QtGui/QFileDialog> +#include <QtGui/QHeaderView> +#include <QtGui/QTreeView> +#include <QtGui/QTableView> +#include <QtGui/QWizardPage> +#include <private/qlayoutengine_p.h> + +#include <QtCore/QBuffer> +#include <QtCore/QDir> +#include <QtCore/QMetaProperty> +#include <QtCore/qdebug.h> +#include <QtCore/QXmlStreamWriter> + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList<DomProperty*> DomPropertyList; +} + +static const char *currentUiVersion = "4.0"; +static const char *clipboardObjectName = "__qt_fake_top_level"; + +#define OLD_RESOURCE_FORMAT // Support pre 4.4 format. + +namespace qdesigner_internal { + +// -------------------- QDesignerResourceBuilder: A resource builder that works on the property sheet icon types. +class QDesignerResourceBuilder : public QResourceBuilder +{ +public: + QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache); + + void setPixmapCache(DesignerPixmapCache *pixmapCache) { m_pixmapCache = pixmapCache; } + void setIconCache(DesignerIconCache *iconCache) { m_iconCache = iconCache; } + bool isSaveRelative() const { return m_saveRelative; } + void setSaveRelative(bool relative) { m_saveRelative = relative; } + QStringList usedQrcFiles() const { return m_usedQrcFiles.keys(); } +#ifdef OLD_RESOURCE_FORMAT + QStringList loadedQrcFiles() const { return m_loadedQrcFiles.keys(); } // needed only for loading old resource attribute of <iconset> tag. +#endif + + virtual QVariant loadResource(const QDir &workingDirectory, const DomProperty *icon) const; + + virtual QVariant toNativeValue(const QVariant &value) const; + + virtual DomProperty *saveResource(const QDir &workingDirectory, const QVariant &value) const; + + virtual bool isResourceType(const QVariant &value) const; +private: + + QDesignerFormEditorInterface *m_core; + DesignerPixmapCache *m_pixmapCache; + DesignerIconCache *m_iconCache; + bool m_saveRelative; + mutable QMap<QString, bool> m_usedQrcFiles; + mutable QMap<QString, bool> m_loadedQrcFiles; +}; + +QDesignerResourceBuilder::QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache) : + m_core(core), + m_pixmapCache(pixmapCache), + m_iconCache(iconCache), + m_saveRelative(true) +{ +} + +static inline void setIconPixmap(QIcon::Mode m, QIcon::State s, const QDir &workingDirectory, const QString &v, PropertySheetIconValue &icon) +{ + icon.setPixmap(m, s, PropertySheetPixmapValue(QFileInfo(workingDirectory, v).absoluteFilePath())); +} + +QVariant QDesignerResourceBuilder::loadResource(const QDir &workingDirectory, const DomProperty *property) const +{ + switch (property->kind()) { + case DomProperty::Pixmap: { + PropertySheetPixmapValue pixmap; + DomResourcePixmap *dp = property->elementPixmap(); + if (!dp->text().isEmpty()) { + pixmap.setPath(QFileInfo(workingDirectory, dp->text()).absoluteFilePath()); +#ifdef OLD_RESOURCE_FORMAT + if (dp->hasAttributeResource()) + m_loadedQrcFiles.insert(QFileInfo(workingDirectory, dp->attributeResource()).absoluteFilePath(), false); +#endif + } + return qVariantFromValue(pixmap); + } + + case DomProperty::IconSet: { + PropertySheetIconValue icon; + DomResourceIcon *di = property->elementIconSet(); + if (const int flags = iconStateFlags(di)) { // new, post 4.4 format + if (flags & NormalOff) + setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->elementNormalOff()->text(), icon); + if (flags & NormalOn) + setIconPixmap(QIcon::Normal, QIcon::On, workingDirectory, di->elementNormalOn()->text(), icon); + if (flags & DisabledOff) + setIconPixmap(QIcon::Disabled, QIcon::Off, workingDirectory, di->elementDisabledOff()->text(), icon); + if (flags & DisabledOn) + setIconPixmap(QIcon::Disabled, QIcon::On, workingDirectory, di->elementDisabledOn()->text(), icon); + if (flags & ActiveOff) + setIconPixmap(QIcon::Active, QIcon::Off, workingDirectory, di->elementActiveOff()->text(), icon); + if (flags & ActiveOn) + setIconPixmap(QIcon::Active, QIcon::On, workingDirectory, di->elementActiveOn()->text(), icon); + if (flags & SelectedOff) + setIconPixmap(QIcon::Selected, QIcon::Off, workingDirectory, di->elementSelectedOff()->text(), icon); + if (flags & SelectedOn) + setIconPixmap(QIcon::Selected, QIcon::On, workingDirectory, di->elementSelectedOn()->text(), icon); + } else { +#ifdef OLD_RESOURCE_FORMAT + setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->text(), icon); + if (di->hasAttributeResource()) + m_loadedQrcFiles.insert(QFileInfo(workingDirectory, di->attributeResource()).absoluteFilePath(), false); +#endif + } + return qVariantFromValue(icon); + } + default: + break; + } + return QVariant(); +} + +QVariant QDesignerResourceBuilder::toNativeValue(const QVariant &value) const +{ + if (qVariantCanConvert<PropertySheetPixmapValue>(value)) { + if (m_pixmapCache) + return m_pixmapCache->pixmap(qVariantValue<PropertySheetPixmapValue>(value)); + } else if (qVariantCanConvert<PropertySheetIconValue>(value)) { + if (m_iconCache) + return m_iconCache->icon(qVariantValue<PropertySheetIconValue>(value)); + } + return value; +} + +DomProperty *QDesignerResourceBuilder::saveResource(const QDir &workingDirectory, const QVariant &value) const +{ + DomProperty *p = new DomProperty; + if (qVariantCanConvert<PropertySheetPixmapValue>(value)) { + const PropertySheetPixmapValue pix = qvariant_cast<PropertySheetPixmapValue>(value); + DomResourcePixmap *rp = new DomResourcePixmap; + const QString pixPath = pix.path(); + switch (pix.pixmapSource(m_core)) { + case PropertySheetPixmapValue::LanguageResourcePixmap: + rp->setText(pixPath); + break; + case PropertySheetPixmapValue::ResourcePixmap: { + rp->setText(pixPath); + const QString qrcFile = m_core->resourceModel()->qrcPath(pixPath); + if (!qrcFile.isEmpty()) { + m_usedQrcFiles.insert(qrcFile, false); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Add qrc path + rp->setAttributeResource(workingDirectory.relativeFilePath(qrcFile)); +#endif + } + } + break; + case PropertySheetPixmapValue::FilePixmap: + rp->setText(m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath); + break; + } + p->setElementPixmap(rp); + return p; + } else if (qVariantCanConvert<PropertySheetIconValue>(value)) { + const PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(value); + const QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> pixmaps = icon.paths(); + if (!pixmaps.isEmpty()) { + DomResourceIcon *ri = new DomResourceIcon; + QMapIterator<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> itPix(pixmaps); + while (itPix.hasNext()) { + const QIcon::Mode mode = itPix.next().key().first; + const QIcon::State state = itPix.key().second; + DomResourcePixmap *rp = new DomResourcePixmap; + const PropertySheetPixmapValue pix = itPix.value(); + const PropertySheetPixmapValue::PixmapSource ps = pix.pixmapSource(m_core); + const QString pixPath = pix.path(); + rp->setText(ps == PropertySheetPixmapValue::FilePixmap && m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath); + if (state == QIcon::Off) { + switch (mode) { + case QIcon::Normal: + ri->setElementNormalOff(rp); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format. + ri->setText(rp->text()); +#endif + if (ps == PropertySheetPixmapValue::ResourcePixmap) { + // Be sure that ri->text() file comes from active resourceSet (i.e. make appropriate + // resourceSet active before calling this method). + const QString qrcFile = m_core->resourceModel()->qrcPath(ri->text()); + if (!qrcFile.isEmpty()) { + m_usedQrcFiles.insert(qrcFile, false); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format. + ri->setAttributeResource(workingDirectory.relativeFilePath(qrcFile)); +#endif + } + } + break; + case QIcon::Disabled: ri->setElementDisabledOff(rp); break; + case QIcon::Active: ri->setElementActiveOff(rp); break; + case QIcon::Selected: ri->setElementSelectedOff(rp); break; + } + } else { + switch (mode) { + case QIcon::Normal: ri->setElementNormalOn(rp); break; + case QIcon::Disabled: ri->setElementDisabledOn(rp); break; + case QIcon::Active: ri->setElementActiveOn(rp); break; + case QIcon::Selected: ri->setElementSelectedOn(rp); break; + } + } + } + p->setElementIconSet(ri); + return p; + } + } + delete p; + return 0; +} + +bool QDesignerResourceBuilder::isResourceType(const QVariant &value) const +{ + if (qVariantCanConvert<PropertySheetPixmapValue>(value) || qVariantCanConvert<PropertySheetIconValue>(value)) + return true; + return false; +} +// ------------------------- QDesignerTextBuilder +class QDesignerTextBuilder : public QTextBuilder +{ +public: + QDesignerTextBuilder() {} + + virtual QVariant loadText(const DomProperty *icon) const; + + virtual QVariant toNativeValue(const QVariant &value) const; + + virtual DomProperty *saveText(const QVariant &value) const; +}; + +QVariant QDesignerTextBuilder::loadText(const DomProperty *text) const +{ + const DomString *str = text->elementString(); + PropertySheetStringValue strVal(str->text()); + if (str->hasAttributeComment()) { + strVal.setDisambiguation(str->attributeComment()); + } + if (str->hasAttributeExtraComment()) { + strVal.setComment(str->attributeExtraComment()); + } + if (str->hasAttributeNotr()) { + const QString notr = str->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + strVal.setTranslatable(translatable); + } + return qVariantFromValue(strVal); +} + +QVariant QDesignerTextBuilder::toNativeValue(const QVariant &value) const +{ + if (qVariantCanConvert<PropertySheetStringValue>(value)) + return qVariantFromValue(qVariantValue<PropertySheetStringValue>(value).value()); + return value; +} + +DomProperty *QDesignerTextBuilder::saveText(const QVariant &value) const +{ + if (!qVariantCanConvert<PropertySheetStringValue>(value) && !qVariantCanConvert<QString>(value)) + return 0; + + DomProperty *property = new DomProperty(); + DomString *domStr = new DomString(); + + if (qVariantCanConvert<PropertySheetStringValue>(value)) { + PropertySheetStringValue str = qVariantValue<PropertySheetStringValue>(value); + + domStr->setText(str.value()); + + const QString property_comment = str.disambiguation(); + if (!property_comment.isEmpty()) + domStr->setAttributeComment(property_comment); + const QString property_extraComment = str.comment(); + if (!property_extraComment.isEmpty()) + domStr->setAttributeExtraComment(property_extraComment); + const bool property_translatable = str.translatable(); + if (!property_translatable) + domStr->setAttributeNotr(QLatin1String("true")); + } else { + domStr->setText(value.toString()); + } + + property->setElementString(domStr); + return property; +} + +QDesignerResource::QDesignerResource(FormWindow *formWindow) : + QEditorFormBuilder(formWindow->core()), + m_formWindow(formWindow), + m_topLevelSpacerCount(0), + m_copyWidget(false), + m_selected(0), + m_resourceBuilder(new QDesignerResourceBuilder(m_formWindow->core(), m_formWindow->pixmapCache(), m_formWindow->iconCache())) +{ + setWorkingDirectory(formWindow->absoluteDir()); + setResourceBuilder(m_resourceBuilder); + setTextBuilder(new QDesignerTextBuilder()); + + // ### generalise + const QString designerWidget = QLatin1String("QDesignerWidget"); + const QString layoutWidget = QLatin1String("QLayoutWidget"); + const QString widget = QLatin1String("QWidget"); + m_internal_to_qt.insert(layoutWidget, widget); + m_internal_to_qt.insert(designerWidget, widget); + m_internal_to_qt.insert(QLatin1String("QDesignerDialog"), QLatin1String("QDialog")); + m_internal_to_qt.insert(QLatin1String("QDesignerMenuBar"), QLatin1String("QMenuBar")); + m_internal_to_qt.insert(QLatin1String("QDesignerMenu"), QLatin1String("QMenu")); + m_internal_to_qt.insert(QLatin1String("QDesignerDockWidget"), QLatin1String("QDockWidget")); + m_internal_to_qt.insert(QLatin1String("QDesignerQ3WidgetStack"), QLatin1String("Q3WidgetStack")); + + // invert + QHash<QString, QString>::const_iterator cend = m_internal_to_qt.constEnd(); + for (QHash<QString, QString>::const_iterator it = m_internal_to_qt.constBegin();it != cend; ++it ) { + if (it.value() != designerWidget && it.value() != layoutWidget) + m_qt_to_internal.insert(it.value(), it.key()); + + } +} + +QDesignerResource::~QDesignerResource() +{ +} + +static inline QString messageBoxTitle() +{ + return QApplication::translate("Designer", "Qt Designer"); +} + +void QDesignerResource::save(QIODevice *dev, QWidget *widget) +{ + m_topLevelSpacerCount = 0; + + QAbstractFormBuilder::save(dev, widget); + + if (QSimpleResource::warningsEnabled() && m_topLevelSpacerCount != 0) { + const QString message = QApplication::translate("Designer", "This file contains top level spacers.<br>" + "They have <b>NOT</b> been saved into the form."); + const QString infoMessage = QApplication::translate("Designer", "Perhaps you forgot to create a layout?"); + + core()->dialogGui()->message(widget->window(), QDesignerDialogGuiInterface::TopLevelSpacerMessage, + QMessageBox::Warning, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + } +} + +void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) +{ + QAbstractFormBuilder::saveDom(ui, widget); + + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget); + Q_ASSERT(sheet != 0); + + const QVariant classVar = sheet->property(sheet->indexOf(QLatin1String("objectName"))); + QString classStr; + if (classVar.canConvert(QVariant::String)) + classStr = classVar.toString(); + else + classStr = qVariantValue<PropertySheetStringValue>(classVar).value(); + ui->setElementClass(classStr); + + for (int index = 0; index < m_formWindow->toolCount(); ++index) { + QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index); + Q_ASSERT(tool != 0); + tool->saveToDom(ui, widget); + } + + const QString author = m_formWindow->author(); + if (!author.isEmpty()) { + ui->setElementAuthor(author); + } + + const QString comment = m_formWindow->comment(); + if (!comment.isEmpty()) { + ui->setElementComment(comment); + } + + const QString exportMacro = m_formWindow->exportMacro(); + if (!exportMacro.isEmpty()) { + ui->setElementExportMacro(exportMacro); + } + + const QVariantMap designerFormData = m_formWindow->formData(); + if (!designerFormData.empty()) { + DomPropertyList domPropertyList; + const QVariantMap::const_iterator cend = designerFormData.constEnd(); + for (QVariantMap::const_iterator it = designerFormData.constBegin(); it != cend; ++it) { + if (DomProperty *prop = variantToDomProperty(this, widget->metaObject(), it.key(), it.value())) + domPropertyList += prop; + } + if (!domPropertyList.empty()) { + DomDesignerData* domDesignerFormData = new DomDesignerData; + domDesignerFormData->setElementProperty(domPropertyList); + ui->setElementDesignerdata(domDesignerFormData); + } + } + + if (!m_formWindow->includeHints().isEmpty()) { + const QString local = QLatin1String("local"); + const QString global = QLatin1String("global"); + QList<DomInclude*> ui_includes; + foreach (QString includeHint, m_formWindow->includeHints()) { + if (includeHint.isEmpty()) + continue; + DomInclude *incl = new DomInclude; + const QString location = includeHint.at(0) == QLatin1Char('<') ? global : local; + includeHint.remove(QLatin1Char('"')); + includeHint.remove(QLatin1Char('<')); + includeHint.remove(QLatin1Char('>')); + incl->setAttributeLocation(location); + incl->setText(includeHint); + ui_includes.append(incl); + } + + DomIncludes *includes = new DomIncludes; + includes->setElementInclude(ui_includes); + ui->setElementIncludes(includes); + } + + int defaultMargin = INT_MIN, defaultSpacing = INT_MIN; + m_formWindow->layoutDefault(&defaultMargin, &defaultSpacing); + + if (defaultMargin != INT_MIN || defaultSpacing != INT_MIN) { + DomLayoutDefault *def = new DomLayoutDefault; + if (defaultMargin != INT_MIN) + def->setAttributeMargin(defaultMargin); + if (defaultSpacing != INT_MIN) + def->setAttributeSpacing(defaultSpacing); + ui->setElementLayoutDefault(def); + } + + QString marginFunction, spacingFunction; + m_formWindow->layoutFunction(&marginFunction, &spacingFunction); + if (!marginFunction.isEmpty() || !spacingFunction.isEmpty()) { + DomLayoutFunction *def = new DomLayoutFunction; + + if (!marginFunction.isEmpty()) + def->setAttributeMargin(marginFunction); + if (!spacingFunction.isEmpty()) + def->setAttributeSpacing(spacingFunction); + ui->setElementLayoutFunction(def); + } + + QString pixFunction = m_formWindow->pixmapFunction(); + if (!pixFunction.isEmpty()) { + ui->setElementPixmapFunction(pixFunction); + } + + if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) + extra->saveUiExtraInfo(ui); + + if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) { + const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(m_formWindow->mainContainer()); + const QStringList fakeSlots = item->fakeSlots(); + const QStringList fakeSignals =item->fakeSignals(); + if (!fakeSlots.empty() || !fakeSignals.empty()) { + DomSlots *domSlots = new DomSlots(); + domSlots->setElementSlot(fakeSlots); + domSlots->setElementSignal(fakeSignals); + ui->setElementSlots(domSlots); + } + } +} + +namespace { + enum LoadPreCheck { LoadPreCheckFailed, LoadPreCheckVersion3, LoadPreCheckVersionMismatch, LoadPreCheckOk }; + // Pair of major, minor + typedef QPair<int, int> UiVersion; +} + +static UiVersion uiVersion(const QString &attr) +{ + const QStringList versions = attr.split(QLatin1Char('.')); + if (versions.empty()) + return UiVersion(-1, -1); + + bool ok = false; + UiVersion rc(versions.at(0).toInt(&ok), 0); + + if (!ok) + return UiVersion(-1, -1); + + if (versions.size() > 1) { + const int minorVersion = versions.at(1).toInt(&ok); + if (ok) + rc.second = minorVersion; + } + return rc; +} + +// Read version and language attributes of an <UI> element. +static bool readUiAttributes(QIODevice *dev, QString *errorMessage, + QString *version, + QString *language) +{ + const QString uiElement = QLatin1String("ui"); + const QString versionAttribute = QLatin1String("version"); + const QString languageAttribute = QLatin1String("language"); + QXmlStreamReader reader(dev); + // Read up to first element + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + const QStringRef tag = reader.name(); + if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) { + const QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(versionAttribute)) + *version = attributes.value(versionAttribute).toString(); + if (attributes.hasAttribute(languageAttribute)) + *language = attributes.value(languageAttribute).toString(); + return true; + } else { + *errorMessage = QCoreApplication::translate("Designer", "Invalid ui file: The root element <ui> is missing."); + return false; + + } + } + } + *errorMessage = QCoreApplication::translate("Designer", "An error has occurred while reading the ui file at line %1, column %2: %3") + .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()); + return false; +} + +// While loading a file, check language, version and extra extension +static LoadPreCheck loadPrecheck(QDesignerFormEditorInterface *core, + QIODevice *dev, + QString *errorMessage, QString *versionString) +{ + QString language; + // Read attributes of <ui> and rewind + if (!readUiAttributes(dev, errorMessage, versionString, &language)) { + // XML error: Mimick the behaviour occurring if an XML error is + // detected later on, report to warning log and have embedding + // application display a dialog. + designerWarning(*errorMessage); + errorMessage->clear(); + return LoadPreCheckFailed; + } + dev->seek(0); + + // Check language unless extension present (Jambi) + if (!language.isEmpty() && !qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) { + if (language.toLower() != QLatin1String("c++")) { + // Jambi?! + *errorMessage = QApplication::translate("Designer", "This file cannot be read because it was created using %1.").arg(language); + return LoadPreCheckFailed; + } + } + + // Version + if (!versionString->isEmpty()) { + const UiVersion version = uiVersion(*versionString); + switch (version.first) { + case 3: + return LoadPreCheckVersion3; + case 4: + break; + default: + *errorMessage = QApplication::translate("Designer", "This file was created using Designer from Qt-%1 and cannot be read.").arg(*versionString); + return LoadPreCheckVersionMismatch; + } + } + return LoadPreCheckOk; +} + +QWidget *QDesignerResource::load(QIODevice *dev, QWidget *parentWidget) +{ + // Run loadPreCheck for version and language + QString errorMessage; + QString version; + switch (loadPrecheck(core(), dev, &errorMessage, &version)) { + case LoadPreCheckFailed: + case LoadPreCheckVersionMismatch: + if (!errorMessage.isEmpty()) + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok); + return 0; + case LoadPreCheckVersion3: { + QWidget *w = 0; + QByteArray ba; + if (runUIC( m_formWindow->fileName(), UIC_ConvertV3, ba, errorMessage)) { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + w = load(&buffer, parentWidget); + if (w) { + // Force the form to pop up a save file dialog + m_formWindow->setFileName(QString()); + } else { + errorMessage = QApplication::translate("Designer", "The converted file could not be read."); + } + } + if (w) { + const QString message = QApplication::translate("Designer", + "This file was created using Designer from Qt-%1 and" + " will be converted to a new form by Qt Designer.").arg(version); + const QString infoMessage = QApplication::translate("Designer", + "The old form has not been touched, but you will have to save the form" + " under a new name."); + + core()->dialogGui()->message(parentWidget->window(), + QDesignerDialogGuiInterface::UiVersionMismatchMessage, + QMessageBox::Information, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + return w; + } + + const QString message = QApplication::translate("Designer", + "This file was created using Designer from Qt-%1 and " + "could not be read:\n%2").arg(version).arg(errorMessage); + const QString infoMessage = QApplication::translate("Designer", + "Please run it through <b>uic3 -convert</b> to convert " + "it to Qt-4's ui format."); + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + return 0; + } + + case LoadPreCheckOk: + break; + } + return QEditorFormBuilder::load(dev, parentWidget); +} + +bool QDesignerResource::saveRelative() const +{ + return m_resourceBuilder->isSaveRelative(); +} + +void QDesignerResource::setSaveRelative(bool relative) +{ + m_resourceBuilder->setSaveRelative(relative); +} + +static bool addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals) +{ + if (!domSlots) + return false; + + bool rc = false; + foreach (const QString &fakeSlot, domSlots->elementSlot()) + if (fakeSlots.indexOf(fakeSlot) == -1) { + fakeSlots += fakeSlot; + rc = true; + } + + foreach (const QString &fakeSignal, domSlots->elementSignal()) + if (fakeSignals.indexOf(fakeSignal) == -1) { + fakeSignals += fakeSignal; + rc = true; + } + return rc; +} + +QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) +{ + // Load extra info extension. This is used by Jambi for preventing + // C++ ui files from being loaded + if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) { + if (!extra->loadUiExtraInfo(ui)) { + const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load."); + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok); + return 0; + } + } + + qdesigner_internal::WidgetFactory *factory = qobject_cast<qdesigner_internal::WidgetFactory*>(core()->widgetFactory()); + Q_ASSERT(factory != 0); + + QDesignerFormWindowInterface *previousFormWindow = factory->currentFormWindow(m_formWindow); + + m_isMainWidget = true; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + QWidget *mainWidget = QAbstractFormBuilder::create(ui, parentWidget); + + if (mainWidget && m_formWindow) { + m_formWindow->setAuthor(ui->elementAuthor()); + m_formWindow->setComment(ui->elementComment()); + m_formWindow->setExportMacro(ui->elementExportMacro()); + + // Designer data + QVariantMap designerFormData; + if (ui->hasElementDesignerdata()) { + const DomPropertyList domPropertyList = ui->elementDesignerdata()->elementProperty(); + const DomPropertyList::const_iterator cend = domPropertyList.constEnd(); + for (DomPropertyList::const_iterator it = domPropertyList.constBegin(); it != cend; ++it) { + const QVariant vprop = domPropertyToVariant(this, mainWidget->metaObject(), *it); + if (vprop.type() != QVariant::Invalid) + designerFormData.insert((*it)->attributeName(), vprop); + } + } + m_formWindow->setFormData(designerFormData); + + m_formWindow->setPixmapFunction(ui->elementPixmapFunction()); + + if (DomLayoutDefault *def = ui->elementLayoutDefault()) { + m_formWindow->setLayoutDefault(def->attributeMargin(), def->attributeSpacing()); + } + + if (DomLayoutFunction *fun = ui->elementLayoutFunction()) { + m_formWindow->setLayoutFunction(fun->attributeMargin(), fun->attributeSpacing()); + } + + if (DomIncludes *includes = ui->elementIncludes()) { + const QString global = QLatin1String("global"); + QStringList includeHints; + foreach (DomInclude *incl, includes->elementInclude()) { + QString text = incl->text(); + + if (text.isEmpty()) + continue; + + if (incl->hasAttributeLocation() && incl->attributeLocation() == global ) { + text = text.prepend(QLatin1Char('<')).append(QLatin1Char('>')); + } else { + text = text.prepend(QLatin1Char('"')).append(QLatin1Char('"')); + } + + includeHints.append(text); + } + + m_formWindow->setIncludeHints(includeHints); + } + + // Register all button groups the form builder adds as children of the main container for them to be found + // in the signal slot editor + const QObjectList mchildren = mainWidget->children(); + if (!mchildren.empty()) { + QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase(); + const QObjectList::const_iterator cend = mchildren.constEnd(); + for (QObjectList::const_iterator it = mchildren.constBegin(); it != cend; ++it) + if (QButtonGroup *bg = qobject_cast<QButtonGroup*>(*it)) + mdb->add(bg); + } + // Load tools + for (int index = 0; index < m_formWindow->toolCount(); ++index) { + QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index); + Q_ASSERT(tool != 0); + tool->loadFromDom(ui, mainWidget); + } + } + + factory->currentFormWindow(previousFormWindow); + + if (const DomSlots *domSlots = ui->elementSlots()) { + if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) { + QStringList fakeSlots; + QStringList fakeSignals; + if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { + MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(mainWidget); + item->setFakeSlots(fakeSlots); + item->setFakeSignals(fakeSignals); + } + } + } + if (mainWidget) { + // Initialize the mainwindow geometry. Has it been explicitly specified? + bool hasExplicitGeometry = false; + const QList<DomProperty *> properties = ui->elementWidget()->elementProperty(); + if (!properties.empty()) { + const QString geometry = QLatin1String("geometry"); + foreach (const DomProperty *p, properties) + if (p->attributeName() == geometry) { + hasExplicitGeometry = true; + break; + } + } + if (hasExplicitGeometry) { + // Geometry was specified explicitly: Verify that smartMinSize is respected + // (changed fonts, label wrapping policies, etc). This does not happen automatically in docked mode. + const QSize size = mainWidget->size(); + const QSize minSize = size.expandedTo(qSmartMinSize(mainWidget)); + if (minSize != size) + mainWidget->resize(minSize); + } else { + // No explicit Geometry: perform an adjustSize() to resize the form correctly before embedding it into a container + // (which might otherwise squeeze the form) + mainWidget->adjustSize(); + } + // Some integration wizards create forms with main containers + // based on derived classes of QWidget and load them into Designer + // without the plugin existing. This will trigger the auto-promotion + // mechanism of Designer, which will set container=false for + // QWidgets. For the main container, force container=true and warn. + const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase(); + const int wdbIndex = wdb->indexOfObject(mainWidget); + if (wdbIndex != -1) { + QDesignerWidgetDataBaseItemInterface *item = wdb->item(wdbIndex); + // Promoted main container that is not of container type + if (item->isPromoted() && !item->isContainer()) { + item->setContainer(true); + qWarning("** WARNING The form's main container is an unknown custom widget '%s'." + " Defaulting to a promoted instance of '%s', assuming container.", + item->name().toUtf8().constData(), item->extends().toUtf8().constData()); + } + } + } + return mainWidget; +} + +QWidget *QDesignerResource::create(DomWidget *ui_widget, QWidget *parentWidget) +{ + const QString className = ui_widget->attributeClass(); + if (!m_isMainWidget && className == QLatin1String("QWidget") && ui_widget->elementLayout().size() && + !ui_widget->hasAttributeNative()) { + // ### check if elementLayout.size() == 1 + + QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget); + + if (container == 0) { + // generate a QLayoutWidget iff the parent is not an QDesignerContainerExtension. + ui_widget->setAttributeClass(QLatin1String("QLayoutWidget")); + } + } + + // save the actions + const QList<DomActionRef*> actionRefs = ui_widget->elementAddAction(); + ui_widget->setElementAddAction(QList<DomActionRef*>()); + + QWidget *w = QAbstractFormBuilder::create(ui_widget, parentWidget); + + // restore the actions + ui_widget->setElementAddAction(actionRefs); + + if (w == 0) + return 0; + + // ### generalize using the extension manager + QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(w); + QDesignerMenuBar *menuBar = qobject_cast<QDesignerMenuBar*>(w); + + if (menu) { + menu->interactive(false); + menu->hide(); + } else if (menuBar) { + menuBar->interactive(false); + } + + foreach (DomActionRef *ui_action_ref, actionRefs) { + const QString name = ui_action_ref->attributeName(); + if (name == QLatin1String("separator")) { + QAction *sep = new QAction(w); + sep->setSeparator(true); + w->addAction(sep); + addMenuAction(sep); + } else if (QAction *a = m_actions.value(name)) { + w->addAction(a); + } else if (QActionGroup *g = m_actionGroups.value(name)) { + w->addActions(g->actions()); + } else if (QMenu *menu = qFindChild<QMenu*>(w, name)) { + w->addAction(menu->menuAction()); + addMenuAction(menu->menuAction()); + } + } + + if (menu) { + menu->interactive(true); + menu->adjustSpecialActions(); + } else if (menuBar) { + menuBar->interactive(true); + menuBar->adjustSpecialActions(); + } + + ui_widget->setAttributeClass(className); // fix the class name + applyExtensionDataFromDOM(this, core(), ui_widget, w, true); + + // store user-defined scripts + if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) { + const QString designerSource = QLatin1String("designer"); + const DomScripts domScripts = ui_widget->elementScript(); + if (!domScripts.empty()) { + foreach (const DomScript *script, domScripts) { + if (script->hasAttributeSource() && script->attributeSource() == designerSource) { + metaDataBase->metaDataBaseItem(w)->setScript(script->text()); + } + } + } + } + + return w; +} + +QLayout *QDesignerResource::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) +{ + QLayout *l = QAbstractFormBuilder::create(ui_layout, layout, parentWidget); + + if (QGridLayout *gridLayout = qobject_cast<QGridLayout*>(l)) { + QLayoutSupport::createEmptyCells(gridLayout); + } else { + if (QFormLayout *formLayout = qobject_cast<QFormLayout*>(l)) + QLayoutSupport::createEmptyCells(formLayout); + } + // While the actual values are applied by the form builder, we still need + // to mark them as 'changed'. + LayoutPropertySheet::markChangedStretchProperties(core(), l, ui_layout); + return l; +} + +QLayoutItem *QDesignerResource::create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget) +{ + if (ui_layoutItem->kind() == DomLayoutItem::Spacer) { + const DomSpacer *domSpacer = ui_layoutItem->elementSpacer(); + const QHash<QString, DomProperty*> properties = propertyMap(domSpacer->elementProperty()); + Spacer *spacer = static_cast<Spacer*>(core()->widgetFactory()->createWidget(QLatin1String("Spacer"), parentWidget)); + if (domSpacer->hasAttributeName()) + changeObjectName(spacer, domSpacer->attributeName()); + core()->metaDataBase()->add(spacer); + + spacer->setInteractiveMode(false); + applyProperties(spacer, ui_layoutItem->elementSpacer()->elementProperty()); + spacer->setInteractiveMode(true); + + if (m_formWindow) { + m_formWindow->manageWidget(spacer); + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), spacer)) + sheet->setChanged(sheet->indexOf(QLatin1String("orientation")), true); + } + + return new QWidgetItem(spacer); + } else if (ui_layoutItem->kind() == DomLayoutItem::Layout && parentWidget) { + DomLayout *ui_layout = ui_layoutItem->elementLayout(); + QLayoutWidget *layoutWidget = new QLayoutWidget(m_formWindow, parentWidget); + core()->metaDataBase()->add(layoutWidget); + if (m_formWindow) + m_formWindow->manageWidget(layoutWidget); + (void) create(ui_layout, 0, layoutWidget); + return new QWidgetItem(layoutWidget); + } + return QAbstractFormBuilder::create(ui_layoutItem, layout, parentWidget); +} + +void QDesignerResource::changeObjectName(QObject *o, QString objName) +{ + m_formWindow->unify(o, objName, true); + o->setObjectName(objName); + +} + +/* If the property is a enum or flag value, retrieve + * the existing enum/flag via property sheet and use it to convert */ + +static bool readDomEnumerationValue(const DomProperty *p, + const QDesignerPropertySheetExtension* sheet, int index, + QVariant &v) +{ + switch (p->kind()) { + case DomProperty::Set: { + const QVariant sheetValue = sheet->property(index); + if (qVariantCanConvert<PropertySheetFlagValue>(sheetValue)) { + const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(sheetValue); + bool ok = false; + v = f.metaFlags.parseFlags(p->elementSet(), &ok); + if (!ok) + designerWarning(f.metaFlags.messageParseFailed(p->elementSet())); + return true; + } + } + break; + case DomProperty::Enum: { + const QVariant sheetValue = sheet->property(index); + if (qVariantCanConvert<PropertySheetEnumValue>(sheetValue)) { + const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(sheetValue); + bool ok = false; + v = e.metaEnum.parseEnum(p->elementEnum(), &ok); + if (!ok) + designerWarning(e.metaEnum.messageParseFailed(p->elementEnum())); + return true; + } + } + break; + default: + break; + } + return false; +} + +void QDesignerResource::applyProperties(QObject *o, const QList<DomProperty*> &properties) +{ + if (properties.empty()) + return; + + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o); + if (!sheet) + return; + + QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), o); + const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed(); + + const QString objectNameProperty = QLatin1String("objectName"); + const DomPropertyList::const_iterator cend = properties.constEnd(); + for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) { + const DomProperty *p = *it; + const QString propertyName = p->attributeName(); + const int index = sheet->indexOf(propertyName); + QVariant v; + if (!readDomEnumerationValue(p, sheet, index, v)) + v = toVariant(o->metaObject(), *it); + + if (p->kind() == DomProperty::String) { + if (index != -1 && sheet->property(index).userType() == qMetaTypeId<PropertySheetKeySequenceValue>()) { + const DomString *key = p->elementString(); + PropertySheetKeySequenceValue keyVal(QKeySequence(key->text())); + if (key->hasAttributeComment()) + keyVal.setDisambiguation(key->attributeComment()); + if (key->hasAttributeExtraComment()) + keyVal.setComment(key->attributeExtraComment()); + if (key->hasAttributeNotr()) { + const QString notr = key->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + keyVal.setTranslatable(translatable); + } + v = qVariantFromValue(keyVal); + } else { + const DomString *str = p->elementString(); + PropertySheetStringValue strVal(v.toString()); + if (str->hasAttributeComment()) + strVal.setDisambiguation(str->attributeComment()); + if (str->hasAttributeExtraComment()) + strVal.setComment(str->attributeExtraComment()); + if (str->hasAttributeNotr()) { + const QString notr = str->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + strVal.setTranslatable(translatable); + } + v = qVariantFromValue(strVal); + } + } + + formBuilderExtra->applyPropertyInternally(o, propertyName, v); + if (index != -1) { + sheet->setProperty(index, v); + sheet->setChanged(index, true); + } else if (dynamicPropertiesAllowed) { + QVariant defaultValue = QVariant(v.type()); + bool isDefault = (v == defaultValue); + if (qVariantCanConvert<PropertySheetIconValue>(v)) { + defaultValue = QVariant(QVariant::Icon); + isDefault = (qVariantValue<PropertySheetIconValue>(v) == PropertySheetIconValue()); + } else if (qVariantCanConvert<PropertySheetPixmapValue>(v)) { + defaultValue = QVariant(QVariant::Pixmap); + isDefault = (qVariantValue<PropertySheetPixmapValue>(v) == PropertySheetPixmapValue()); + } else if (qVariantCanConvert<PropertySheetStringValue>(v)) { + defaultValue = QVariant(QVariant::String); + isDefault = (qVariantValue<PropertySheetStringValue>(v) == PropertySheetStringValue()); + } else if (qVariantCanConvert<PropertySheetKeySequenceValue>(v)) { + defaultValue = QVariant(QVariant::KeySequence); + isDefault = (qVariantValue<PropertySheetKeySequenceValue>(v) == PropertySheetKeySequenceValue()); + } + if (defaultValue.type() != QVariant::UserType) { + const int idx = dynamicSheet->addDynamicProperty(p->attributeName(), defaultValue); + if (idx != -1) { + sheet->setProperty(idx, v); + sheet->setChanged(idx, !isDefault); + } + } + } + + if (propertyName == objectNameProperty) + changeObjectName(o, o->objectName()); + } +} + +QWidget *QDesignerResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &_name) +{ + QString name = _name; + QString className = widgetName; + if (m_isMainWidget) + m_isMainWidget = false; + + QWidget *w = core()->widgetFactory()->createWidget(className, parentWidget); + if (!w) + return 0; + + if (name.isEmpty()) { + QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(w))) + name = qtify(item->name()); + } + + changeObjectName(w, name); + + QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget); + if (!qobject_cast<QMenu*>(w) && (!parentWidget || !container)) { + m_formWindow->manageWidget(w); + if (parentWidget) { + QList<QWidget *> list = qVariantValue<QWidgetList>(parentWidget->property("_q_widgetOrder")); + list.append(w); + parentWidget->setProperty("_q_widgetOrder", qVariantFromValue(list)); + QList<QWidget *> zOrder = qVariantValue<QWidgetList>(parentWidget->property("_q_zOrder")); + zOrder.append(w); + parentWidget->setProperty("_q_zOrder", qVariantFromValue(list)); + } + } else { + core()->metaDataBase()->add(w); + } + + w->setWindowFlags(w->windowFlags() & ~Qt::Window); + // Make sure it is non-modal (for example, KDialog calls setModal(true) in the constructor). + w->setWindowModality(Qt::NonModal); + + return w; +} + +QLayout *QDesignerResource::createLayout(const QString &layoutName, QObject *parent, const QString &name) +{ + QWidget *layoutBase = 0; + QLayout *layout = qobject_cast<QLayout*>(parent); + + if (parent->isWidgetType()) + layoutBase = static_cast<QWidget*>(parent); + else { + Q_ASSERT( layout != 0 ); + layoutBase = layout->parentWidget(); + } + + LayoutInfo::Type layoutType = LayoutInfo::layoutType(layoutName); + if (layoutType == LayoutInfo::NoLayout) { + designerWarning(QCoreApplication::translate("QDesignerResource", "The layout type '%1' is not supported, defaulting to grid.").arg(layoutName)); + layoutType = LayoutInfo::Grid; + } + QLayout *lay = core()->widgetFactory()->createLayout(layoutBase, layout, layoutType); + if (lay != 0) + changeObjectName(lay, name); + + return lay; +} + +// save +DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive) +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(widget); + if (!item) + return 0; + + if (qobject_cast<Spacer*>(widget) && m_copyWidget == false) { + ++m_topLevelSpacerCount; + return 0; + } + + const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase(); + QDesignerWidgetDataBaseItemInterface *widgetInfo = 0; + const int widgetInfoIndex = wdb->indexOfObject(widget, false); + if (widgetInfoIndex != -1) { + widgetInfo = wdb->item(widgetInfoIndex); + // Recursively add all dependent custom widgets + QDesignerWidgetDataBaseItemInterface *customInfo = widgetInfo; + while (customInfo && customInfo->isCustom()) { + m_usedCustomWidgets.insert(customInfo, true); + const QString extends = customInfo->extends(); + if (extends == customInfo->name()) { + break; // There are faulty files around that have name==extends + } else { + const int extendsIndex = wdb->indexOfClassName(customInfo->extends()); + customInfo = extendsIndex != -1 ? wdb->item(extendsIndex) : static_cast<QDesignerWidgetDataBaseItemInterface *>(0); + } + } + } + + DomWidget *w = 0; + + if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget)) + w = saveWidget(tabWidget, ui_parentWidget); + else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) + w = saveWidget(stackedWidget, ui_parentWidget); + else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget)) + w = saveWidget(toolBox, ui_parentWidget); + else if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) + w = saveWidget(toolBar, ui_parentWidget); + else if (QDesignerDockWidget *dockWidget = qobject_cast<QDesignerDockWidget*>(widget)) + w = saveWidget(dockWidget, ui_parentWidget); + else if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) + w = saveWidget(widget, container, ui_parentWidget); + else if (QTreeView *treeView = qobject_cast<QTreeView*>(widget)) + w = saveWidget(treeView, ui_parentWidget); + else if (QTableView *tableView = qobject_cast<QTableView*>(widget)) + w = saveWidget(tableView, ui_parentWidget); + else if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(widget)) + w = saveWidget(wizardPage, ui_parentWidget); + else + w = QAbstractFormBuilder::createDom(widget, ui_parentWidget, recursive); + + Q_ASSERT( w != 0 ); + + if (!qobject_cast<QLayoutWidget*>(widget) && w->attributeClass() == QLatin1String("QWidget")) { + w->setAttributeNative(true); + } + + const QString className = w->attributeClass(); + if (m_internal_to_qt.contains(className)) + w->setAttributeClass(m_internal_to_qt.value(className)); + + w->setAttributeName(widget->objectName()); + + if (isPromoted( core(), widget)) { // is promoted? + Q_ASSERT(widgetInfo != 0); + + w->setAttributeName(widget->objectName()); + w->setAttributeClass(widgetInfo->name()); + + QList<DomProperty*> prop_list = w->elementProperty(); + foreach (DomProperty *prop, prop_list) { + if (prop->attributeName() == QLatin1String("geometry")) { + if (DomRect *rect = prop->elementRect()) { + rect->setElementX(widget->x()); + rect->setElementY(widget->y()); + } + break; + } + } + } else if (widgetInfo != 0 && m_usedCustomWidgets.contains(widgetInfo)) { + if (widgetInfo->name() != w->attributeClass()) + w->setAttributeClass(widgetInfo->name()); + } + addExtensionDataToDOM(this, core(), w, widget); + + addUserDefinedScripts(widget, w); + return w; +} + +DomLayout *QDesignerResource::createDom(QLayout *layout, DomLayout *ui_parentLayout, DomWidget *ui_parentWidget) +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(layout); + + if (item == 0) { + layout = qFindChild<QLayout*>(layout); + // refresh the meta database item + item = core()->metaDataBase()->item(layout); + } + + if (item == 0) { + // nothing to do. + return 0; + } + + if (qobject_cast<QSplitter*>(layout->parentWidget()) != 0) { + // nothing to do. + return 0; + } + + m_chain.push(layout); + + DomLayout *l = QAbstractFormBuilder::createDom(layout, ui_parentLayout, ui_parentWidget); + Q_ASSERT(l != 0); + LayoutPropertySheet::stretchAttributesToDom(core(), layout, l); + + m_chain.pop(); + + return l; +} + +DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget) +{ + DomLayoutItem *ui_item = 0; + + if (Spacer *s = qobject_cast<Spacer*>(item->widget())) { + if (!core()->metaDataBase()->item(s)) + return 0; + + DomSpacer *spacer = new DomSpacer(); + const QString objectName = s->objectName(); + if (!objectName.isEmpty()) + spacer->setAttributeName(objectName); + const QList<DomProperty*> properties = computeProperties(item->widget()); + // ### filter the properties + spacer->setElementProperty(properties); + + ui_item = new DomLayoutItem(); + ui_item->setElementSpacer(spacer); + m_laidout.insert(item->widget(), true); + } else if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(item->widget())) { + // Do not save a QLayoutWidget if it is within a layout (else it is saved as "QWidget" + Q_ASSERT(layoutWidget->layout()); + DomLayout *l = createDom(layoutWidget->layout(), ui_layout, ui_parentWidget); + ui_item = new DomLayoutItem(); + ui_item->setElementLayout(l); + m_laidout.insert(item->widget(), true); + } else if (!item->spacerItem()) { // we use spacer as fake item in the Designer + ui_item = QAbstractFormBuilder::createDom(item, ui_layout, ui_parentWidget); + } else { + return 0; + } + + if (m_chain.size() && item->widget()) { + if (QGridLayout *grid = qobject_cast<QGridLayout*>(m_chain.top())) { + const int index = Utils::indexOfWidget(grid, item->widget()); + + int row, column, rowspan, colspan; + grid->getItemPosition(index, &row, &column, &rowspan, &colspan); + ui_item->setAttributeRow(row); + ui_item->setAttributeColumn(column); + + if (colspan != 1) + ui_item->setAttributeColSpan(colspan); + + if (rowspan != 1) + ui_item->setAttributeRowSpan(rowspan); + } else { + if (QFormLayout *form = qobject_cast<QFormLayout*>(m_chain.top())) { + const int index = Utils::indexOfWidget(form, item->widget()); + int row, column, colspan; + getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan); + ui_item->setAttributeRow(row); + ui_item->setAttributeColumn(column); + if (colspan != 1) + ui_item->setAttributeColSpan(colspan); + } + } + } + + return ui_item; +} + +static void addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item) +{ + const DomSlots *domSlots = domCustomWidget->elementSlots(); + if (!domSlots) + return; + + // Merge in new slots, signals + QStringList fakeSlots = item->fakeSlots(); + QStringList fakeSignals = item->fakeSignals(); + if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { + item->setFakeSlots(fakeSlots); + item->setFakeSignals(fakeSignals); + } +} + +void QDesignerResource::addCustomWidgetsToWidgetDatabase(DomCustomWidgetList& custom_widget_list) +{ + // Perform one iteration of adding the custom widgets to the database, + // looking up the base class and inheriting its data. + // Remove the succeeded custom widgets from the list. + // Classes whose base class could not be found are left in the list. + QDesignerWidgetDataBaseInterface *db = m_formWindow->core()->widgetDataBase(); + for (int i=0; i < custom_widget_list.size(); ) { + bool classInserted = false; + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + QString includeFile; + IncludeType includeType = IncludeLocal; + if (const DomHeader *header = custom_widget->elementHeader()) { + includeFile = header->text(); + if (header->hasAttributeLocation() && header->attributeLocation() == QLatin1String("global")) + includeType = IncludeGlobal; + } + const bool domIsContainer = custom_widget->elementContainer(); + // Append a new item + if (base_class.isEmpty()) { + WidgetDataBaseItem *item = new WidgetDataBaseItem(customClassName); + item->setPromoted(false); + item->setGroup(QApplication::translate("Designer", "Custom Widgets")); + item->setIncludeFile(buildIncludeFile(includeFile, includeType)); + item->setContainer(domIsContainer); + item->setCustom(true); + addFakeMethodsToWidgetDataBase(custom_widget, item); + db->append(item); + custom_widget_list.removeAt(i); + classInserted = true; + } else { + // Create a new entry cloned from base class. Note that this will ignore existing + // classes, eg, plugin custom widgets. + QDesignerWidgetDataBaseItemInterface *item = + appendDerived(db, customClassName, QApplication::translate("Designer", "Promoted Widgets"), + base_class, + buildIncludeFile(includeFile, includeType), + true,true); + // Ok, base class found. + if (item) { + // Hack to accommodate for old UI-files in which "contains" is not set properly: + // Apply "contains" from DOM only if true (else, eg classes from QFrame might not accept + // dropping child widgets on them as container=false). This also allows for + // QWidget-derived stacked pages. + if (domIsContainer) + item->setContainer(domIsContainer); + + addFakeMethodsToWidgetDataBase(custom_widget, static_cast<WidgetDataBaseItem*>(item)); + custom_widget_list.removeAt(i); + classInserted = true; + } + } + // Skip failed item. + if (!classInserted) + i++; + } + +} +void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets) +{ + if (dom_custom_widgets == 0) + return; + DomCustomWidgetList custom_widget_list = dom_custom_widgets->elementCustomWidget(); + // Attempt to insert each item derived from its base class. + // This should at most require two iterations in the event that the classes are out of order + // (derived first, max depth: promoted custom plugin = 2) + for (int iteration = 0; iteration < 2; iteration++) { + addCustomWidgetsToWidgetDatabase(custom_widget_list); + if (custom_widget_list.empty()) + return; + } + // Oops, there are classes left whose base class could not be found. + // Default them to QWidget with warnings. + const QString fallBackBaseClass = QLatin1String("QWidget"); + for (int i=0; i < custom_widget_list.size(); i++ ) { + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + qDebug() << "** WARNING The base class " << base_class << " of the custom widget class " << customClassName + << " could not be found. Defaulting to " << fallBackBaseClass << '.'; + custom_widget->setElementExtends(fallBackBaseClass); + } + // One more pass. + addCustomWidgetsToWidgetDatabase(custom_widget_list); + Q_ASSERT(custom_widget_list.empty()); +} + +DomTabStops *QDesignerResource::saveTabStops() +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow); + Q_ASSERT(item); + + QStringList tabStops; + foreach (QWidget *widget, item->tabOrder()) { + if (m_formWindow->mainContainer()->isAncestorOf(widget)) + tabStops.append(widget->objectName()); + } + + if (tabStops.count()) { + DomTabStops *dom = new DomTabStops; + dom->setElementTabStop(tabStops); + return dom; + } + + return 0; +} + +void QDesignerResource::applyTabStops(QWidget *widget, DomTabStops *tabStops) +{ + if (!tabStops) + return; + + QList<QWidget*> tabOrder; + foreach (QString widgetName, tabStops->elementTabStop()) { + if (QWidget *w = qFindChild<QWidget*>(widget, widgetName)) { + tabOrder.append(w); + } + } + + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow); + Q_ASSERT(item); + item->setTabOrder(tabOrder); +} + +/* Unmanaged container pages occur when someone adds a page in a custom widget + * constructor. They don't have a meta DB entry which causes createDom + * to return 0. */ +inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core, + QWidget *container, int index, QWidget *page) +{ + return QCoreApplication::translate("QDesignerResource", +"The container extension of the widget '%1' (%2) returned a widget not managed by Designer '%3' (%4) when queried for page #%5.\n" +"Container pages should only be added by specifying them in XML returned by the domXml() method of the custom widget."). + arg(container->objectName(), WidgetFactory::classNameOf(core, container), + page->objectName(), WidgetFactory::classNameOf(core, page)). + arg(index); +} + +DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList<DomWidget*> ui_widget_list; + + for (int i=0; i<container->count(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + if (DomWidget *ui_page = createDom(page, ui_widget)) { + ui_widget_list.append(ui_page); + } else { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + } + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList<DomWidget*> ui_widget_list; + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) { + for (int i=0; i<container->count(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + if (DomWidget *ui_page = createDom(page, ui_widget)) { + ui_widget_list.append(ui_page); + } else { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + } + } + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(toolBar, ui_parentWidget, false); + if (const QMainWindow *mainWindow = qobject_cast<QMainWindow*>(toolBar->parentWidget())) { + const bool toolBarBreak = mainWindow->toolBarBreak(toolBar); + const Qt::ToolBarArea area = mainWindow->toolBarArea(toolBar); + + QList<DomProperty*> attributes = ui_widget->elementAttribute(); + + DomProperty *attr = new DomProperty(); + attr->setAttributeName(QLatin1String("toolBarArea")); + attr->setElementEnum(QLatin1String(toolBarAreaMetaEnum().valueToKey(area))); + attributes << attr; + + attr = new DomProperty(); + attr->setAttributeName(QLatin1String("toolBarBreak")); + attr->setElementBool(toolBarBreak ? QLatin1String("true") : QLatin1String("false")); + attributes << attr; + ui_widget->setElementAttribute(attributes); + } + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(dockWidget, ui_parentWidget, true); + if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(dockWidget->parentWidget())) { + const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(dockWidget); + DomProperty *attr = new DomProperty(); + attr->setAttributeName(QLatin1String("dockWidgetArea")); + attr->setElementNumber(int(area)); + ui_widget->setElementAttribute(ui_widget->elementAttribute() << attr); + } + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QTreeView *treeView, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(treeView, ui_parentWidget, true); + + QDesignerPropertySheetExtension *sheet + = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), treeView); + ItemViewPropertySheet *itemViewSheet = static_cast<ItemViewPropertySheet*>(sheet); + + if (itemViewSheet) { + QHash<QString,QString> nameMap = itemViewSheet->propertyNameMap(); + foreach (const QString &fakeName, nameMap.keys()) { + int index = itemViewSheet->indexOf(fakeName); + if (sheet->isChanged(index)) { + DomProperty *domAttr = createProperty(treeView->header(), nameMap.value(fakeName), + itemViewSheet->property(index)); + domAttr->setAttributeName(fakeName); + ui_widget->setElementAttribute(ui_widget->elementAttribute() << domAttr); + } + } + } + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QTableView *tableView, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(tableView, ui_parentWidget, true); + + QDesignerPropertySheetExtension *sheet + = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), tableView); + ItemViewPropertySheet *itemViewSheet = static_cast<ItemViewPropertySheet*>(sheet); + + if (itemViewSheet) { + QHash<QString,QString> nameMap = itemViewSheet->propertyNameMap(); + foreach (const QString &fakeName, nameMap.keys()) { + int index = itemViewSheet->indexOf(fakeName); + if (sheet->isChanged(index)) { + DomProperty *domAttr; + if (fakeName.startsWith(QLatin1String("horizontal"))) { + domAttr = createProperty(tableView->horizontalHeader(), nameMap.value(fakeName), + itemViewSheet->property(index)); + } else { + domAttr = createProperty(tableView->verticalHeader(), nameMap.value(fakeName), + itemViewSheet->property(index)); + } + domAttr->setAttributeName(fakeName); + ui_widget->setElementAttribute(ui_widget->elementAttribute() << domAttr); + } + } + } + + return ui_widget; +} + +static void saveStringProperty(DomProperty *property, const PropertySheetStringValue &value) +{ + DomString *str = new DomString(); + str->setText(value.value()); + + const QString property_comment = value.disambiguation(); + if (!property_comment.isEmpty()) + str->setAttributeComment(property_comment); + const QString property_extraComment = value.comment(); + if (!property_extraComment.isEmpty()) + str->setAttributeExtraComment(property_extraComment); + const bool property_translatable = value.translatable(); + if (!property_translatable) + str->setAttributeNotr(QLatin1String("true")); + + property->setElementString(str); +} + +static void saveKeySequenceProperty(DomProperty *property, const PropertySheetKeySequenceValue &value) +{ + DomString *str = new DomString(); + str->setText(value.value().toString()); + + const QString property_comment = value.disambiguation(); + if (!property_comment.isEmpty()) + str->setAttributeComment(property_comment); + const QString property_extraComment = value.comment(); + if (!property_extraComment.isEmpty()) + str->setAttributeExtraComment(property_extraComment); + const bool property_translatable = value.translatable(); + if (!property_translatable) + str->setAttributeNotr(QLatin1String("true")); + + property->setElementString(str); +} + +DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList<DomWidget*> ui_widget_list; + + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) { + const int current = widget->currentIndex(); + for (int i=0; i<container->count(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + DomWidget *ui_page = createDom(page, ui_widget); + if (!ui_page) { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + continue; + } + QList<DomProperty*> ui_attribute_list; + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + // attribute `icon' + widget->setCurrentIndex(i); + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget); + PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String("currentTabIcon")))); + DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), qVariantFromValue(icon)); + if (p) { + p->setAttributeName(strings.iconAttribute); + ui_attribute_list.append(p); + } + // attribute `title' + p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentTabText")))); + if (p) { + p->setAttributeName(strings.titleAttribute); + ui_attribute_list.append(p); + } + + // attribute `toolTip' + QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentTabToolTip"))); + if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.toolTipAttribute); + ui_attribute_list.append(p); + } + } + + // attribute `whatsThis' + v = sheet->property(sheet->indexOf(QLatin1String("currentTabWhatsThis"))); + if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.whatsThisAttribute); + ui_attribute_list.append(p); + } + } + + ui_page->setElementAttribute(ui_attribute_list); + + ui_widget_list.append(ui_page); + } + widget->setCurrentIndex(current); + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList<DomWidget*> ui_widget_list; + + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) { + const int current = widget->currentIndex(); + for (int i=0; i<container->count(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + DomWidget *ui_page = createDom(page, ui_widget); + if (!ui_page) { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + continue; + } + + // attribute `label' + QList<DomProperty*> ui_attribute_list; + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + // attribute `icon' + widget->setCurrentIndex(i); + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget); + PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String("currentItemIcon")))); + DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), qVariantFromValue(icon)); + if (p) { + p->setAttributeName(strings.iconAttribute); + ui_attribute_list.append(p); + } + p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentItemText")))); + if (p) { + p->setAttributeName(strings.labelAttribute); + ui_attribute_list.append(p); + } + + // attribute `toolTip' + QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentItemToolTip"))); + if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.toolTipAttribute); + ui_attribute_list.append(p); + } + } + + ui_page->setElementAttribute(ui_attribute_list); + + ui_widget_list.append(ui_page); + } + widget->setCurrentIndex(current); + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(wizardPage, ui_parentWidget, true); + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), wizardPage); + // Save the page id (string) attribute, append to existing attributes + const QString pageIdPropertyName = QLatin1String(QWizardPagePropertySheet::pageIdProperty); + const int pageIdIndex = sheet->indexOf(pageIdPropertyName); + if (pageIdIndex != -1 && sheet->isChanged(pageIdIndex)) { + DomProperty *property = variantToDomProperty(this, wizardPage->metaObject(), pageIdPropertyName, sheet->property(pageIdIndex)); + Q_ASSERT(property); + property->elementString()->setAttributeNotr(QLatin1String("true")); + DomPropertyList attributes = ui_widget->elementAttribute(); + attributes.push_back(property); + ui_widget->setElementAttribute(attributes); + } + return ui_widget; +} + +// Do not save the 'currentTabName' properties of containers +static inline bool checkContainerProperty(const QWidget *w, const QString &propertyName) +{ + if (qobject_cast<const QToolBox *>(w)) + return QToolBoxWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast<const QTabWidget *>(w)) + return QTabWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast<const QStackedWidget *>(w)) + return QStackedWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast<const QMdiArea *>(w) || qobject_cast<const QWorkspace *>(w)) + return QMdiAreaPropertySheet::checkProperty(propertyName); + return true; +} + +bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const +{ + const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj); + + const int pindex = meta->indexOfProperty(prop); + if (pindex != -1 && !(meta->property(pindex)->attributes(obj) & QDesignerMetaPropertyInterface::StoredAttribute)) + return false; + + if (prop == QLatin1String("objectName") || prop == QLatin1String("spacerName")) // ### don't store the property objectName + return false; + + QWidget *check_widget = 0; + if (obj->isWidgetType()) + check_widget = static_cast<QWidget*>(obj); + + if (check_widget && prop == QLatin1String("geometry")) { + if (check_widget == m_formWindow->mainContainer()) + return true; // Save although maincontainer is technically laid-out by embedding container + if (m_selected && m_selected == check_widget) + return true; + + return !LayoutInfo::isWidgetLaidout(core(), check_widget); + } + + if (check_widget && !checkContainerProperty(check_widget, prop)) + return false; + + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), obj)) { + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), obj); + const int pindex = sheet->indexOf(prop); + if (sheet->isAttribute(pindex)) + return false; + + if (!dynamicSheet || !dynamicSheet->isDynamicProperty(pindex)) + return sheet->isChanged(pindex); + if (!sheet->isVisible(pindex)) + return false; + return true; + } + + return false; +} + +bool QDesignerResource::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout) +{ + if (item->widget() == 0) { + return false; + } + + QGridLayout *grid = qobject_cast<QGridLayout*>(layout); + QBoxLayout *box = qobject_cast<QBoxLayout*>(layout); + + if (grid != 0) { + const int rowSpan = ui_item->hasAttributeRowSpan() ? ui_item->attributeRowSpan() : 1; + const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1; + grid->addWidget(item->widget(), ui_item->attributeRow(), ui_item->attributeColumn(), rowSpan, colSpan, item->alignment()); + return true; + } else if (box != 0) { + box->addItem(item); + return true; + } + + return QAbstractFormBuilder::addItem(ui_item, item, layout); +} + +bool QDesignerResource::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + core()->metaDataBase()->add(widget); // ensure the widget is in the meta database + + if (! QAbstractFormBuilder::addItem(ui_widget, widget, parentWidget) || qobject_cast<QMainWindow*> (parentWidget)) { + if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget)) + container->addWidget(widget); + } + + if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) { + const int tabIndex = tabWidget->count() - 1; + const int current = tabWidget->currentIndex(); + + tabWidget->setCurrentIndex(tabIndex); + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget); + if (DomProperty *picon = attributes.value(strings.iconAttribute)) { + QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabIcon")), v); + } + if (DomProperty *ptext = attributes.value(strings.titleAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabText")), v); + } + if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabToolTip")), v); + } + if (DomProperty *ptext = attributes.value(strings.whatsThisAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabWhatsThis")), v); + } + tabWidget->setCurrentIndex(current); + } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) { + const int itemIndex = toolBox->count() - 1; + const int current = toolBox->currentIndex(); + + toolBox->setCurrentIndex(itemIndex); + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget); + if (DomProperty *picon = attributes.value(strings.iconAttribute)) { + QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemIcon")), v); + } + if (DomProperty *ptext = attributes.value(strings.labelAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemText")), v); + } + if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemToolTip")), v); + } + toolBox->setCurrentIndex(current); + } + + return true; +} + +bool QDesignerResource::copy(QIODevice *dev, const FormBuilderClipboard &selection) +{ + m_copyWidget = true; + + DomUI *ui = copy(selection); + + m_laidout.clear(); + m_copyWidget = false; + + if (!ui) + return false; + + QXmlStreamWriter writer(dev); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + ui->write(writer); + writer.writeEndDocument(); + delete ui; + return true; +} + +DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection) +{ + if (selection.empty()) + return 0; + + m_copyWidget = true; + + DomWidget *ui_widget = new DomWidget(); + ui_widget->setAttributeName(QLatin1String(clipboardObjectName)); + bool hasItems = false; + // Widgets + if (!selection.m_widgets.empty()) { + QList<DomWidget*> ui_widget_list; + const int size = selection.m_widgets.size(); + for (int i=0; i< size; ++i) { + QWidget *w = selection.m_widgets.at(i); + m_selected = w; + DomWidget *ui_child = createDom(w, ui_widget); + m_selected = 0; + if (ui_child) + ui_widget_list.append(ui_child); + } + if (!ui_widget_list.empty()) { + ui_widget->setElementWidget(ui_widget_list); + hasItems = true; + } + } + // actions + if (!selection.m_actions.empty()) { + QList<DomAction*> domActions; + foreach(QAction* action, selection.m_actions) + if (DomAction *domAction = createDom(action)) + domActions += domAction; + if (!domActions.empty()) { + ui_widget-> setElementAction(domActions); + hasItems = true; + } + } + + m_laidout.clear(); + m_copyWidget = false; + + if (!hasItems) { + delete ui_widget; + return 0; + } + // UI + DomUI *ui = new DomUI(); + ui->setAttributeVersion(QLatin1String(currentUiVersion)); + ui->setElementWidget(ui_widget); + ui->setElementResources(saveResources(m_resourceBuilder->usedQrcFiles())); + if (DomCustomWidgets *cws = saveCustomWidgets()) + ui->setElementCustomWidgets(cws); + return ui; +} + +FormBuilderClipboard QDesignerResource::paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent) +{ + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + const int saved = m_isMainWidget; + m_isMainWidget = false; + + FormBuilderClipboard rc; + + // Widgets + const DomWidget *topLevel = ui->elementWidget(); + initialize(ui); + const QList<DomWidget*> domWidgets = topLevel->elementWidget(); + if (!domWidgets.empty()) { + const QPoint offset = m_formWindow->grid(); + foreach (DomWidget* domWidget, domWidgets) { + if (QWidget *w = create(domWidget, widgetParent)) { + w->move(w->pos() + offset); + // ### change the init properties of w + rc.m_widgets.append(w); + } + } + } + const QList<DomAction*> domActions = topLevel->elementAction(); + if (!domActions.empty()) + foreach (DomAction *domAction, domActions) + if (QAction *a = create(domAction, actionParent)) + rc.m_actions .append(a); + + m_isMainWidget = saved; + + if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) + extra->loadUiExtraInfo(ui); + + createResources(ui->elementResources()); + + return rc; +} + +FormBuilderClipboard QDesignerResource::paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent) +{ + DomUI ui; + QXmlStreamReader reader(dev); + bool uiInitialized = false; + + const QString uiElement = QLatin1String("ui"); + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().compare(uiElement, Qt::CaseInsensitive)) { + ui.read(reader); + uiInitialized = true; + } else { + //: Parsing clipboard contents + reader.raiseError(QCoreApplication::translate("QDesignerResource", "Unexpected element <%1>").arg(reader.name().toString())); + } + } + } + if (reader.hasError()) { + //: Parsing clipboard contents + designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents at line %1, column %2: %3") + .arg(reader.lineNumber()).arg(reader.columnNumber()) + .arg(reader.errorString())); + uiInitialized = false; + } else if (uiInitialized == false) { + //: Parsing clipboard contents + designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents: The root element <ui> is missing.")); + } + + if (!uiInitialized) + return FormBuilderClipboard(); + + FormBuilderClipboard clipBoard = paste(&ui, widgetParent, actionParent); + + return clipBoard; +} + +void QDesignerResource::layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing) +{ + QAbstractFormBuilder::layoutInfo(layout, parent, margin, spacing); +} + +DomCustomWidgets *QDesignerResource::saveCustomWidgets() +{ + if (m_usedCustomWidgets.isEmpty()) + return 0; + + // We would like the list to be in order of the widget database indexes + // to ensure that base classes come first (nice optics) + QDesignerFormEditorInterface *core = m_formWindow->core(); + QDesignerWidgetDataBaseInterface *db = core->widgetDataBase(); + const bool isInternalWidgetDataBase = qobject_cast<const WidgetDataBase *>(db); + typedef QMap<int,DomCustomWidget*> OrderedDBIndexDomCustomWidgetMap; + OrderedDBIndexDomCustomWidgetMap orderedMap; + + const QString global = QLatin1String("global"); + foreach (QDesignerWidgetDataBaseItemInterface *item, m_usedCustomWidgets.keys()) { + const QString name = item->name(); + DomCustomWidget *custom_widget = new DomCustomWidget; + + custom_widget->setElementClass(name); + if (item->isContainer()) + custom_widget->setElementContainer(item->isContainer()); + + if (!item->includeFile().isEmpty()) { + DomHeader *header = new DomHeader; + const IncludeSpecification spec = includeSpecification(item->includeFile()); + header->setText(spec.first); + if (spec.second == IncludeGlobal) { + header->setAttributeLocation(global); + } + custom_widget->setElementHeader(header); + custom_widget->setElementExtends(item->extends()); + } + + if (isInternalWidgetDataBase) { + WidgetDataBaseItem *internalItem = static_cast<WidgetDataBaseItem *>(item); + const QStringList fakeSlots = internalItem->fakeSlots(); + const QStringList fakeSignals = internalItem->fakeSignals(); + if (!fakeSlots.empty() || !fakeSignals.empty()) { + DomSlots *domSlots = new DomSlots(); + domSlots->setElementSlot(fakeSlots); + domSlots->setElementSignal(fakeSignals); + custom_widget->setElementSlots(domSlots); + } + const QString addPageMethod = internalItem->addPageMethod(); + if (!addPageMethod.isEmpty()) + custom_widget->setElementAddPageMethod(addPageMethod); + } + + // Look up static per-class scripts of designer + if (DomScript *domScript = createScript(customWidgetScript(core, name), ScriptCustomWidgetPlugin)) + custom_widget->setElementScript(domScript); + + orderedMap.insert(db->indexOfClassName(name), custom_widget); + } + + DomCustomWidgets *customWidgets = new DomCustomWidgets; + customWidgets->setElementCustomWidget(orderedMap.values()); + return customWidgets; +} + +bool QDesignerResource::canCompressMargins(QObject *object) const +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) { + if (qobject_cast<QLayout *>(object)) { + const int l = sheet->property(sheet->indexOf(QLatin1String("leftMargin"))).toInt(); + const int t = sheet->property(sheet->indexOf(QLatin1String("topMargin"))).toInt(); + const int r = sheet->property(sheet->indexOf(QLatin1String("rightMargin"))).toInt(); + const int b = sheet->property(sheet->indexOf(QLatin1String("bottomMargin"))).toInt(); + if (l == t && l == r && l == b) + return true; + } + } + return false; +} + +bool QDesignerResource::canCompressSpacings(QObject *object) const +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) { + if (qobject_cast<QGridLayout *>(object)) { + const int h = sheet->property(sheet->indexOf(QLatin1String("horizontalSpacing"))).toInt(); + const int v = sheet->property(sheet->indexOf(QLatin1String("verticalSpacing"))).toInt(); + if (h == v) + return true; + } + } + return false; +} + +QList<DomProperty*> QDesignerResource::computeProperties(QObject *object) +{ + QList<DomProperty*> properties; + if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) { + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), object); + const int count = sheet->count(); + QList<DomProperty *> marginProperties; + QList<DomProperty *> spacingProperties; + const bool compressMargins = canCompressMargins(object); + const bool compressSpacings = canCompressSpacings(object); + for (int index = 0; index < count; ++index) { + if (!sheet->isChanged(index) && (!dynamicSheet || !dynamicSheet->isDynamicProperty(index))) + continue; + + const QString propertyName = sheet->propertyName(index); + // Suppress windowModality in legacy forms that have it set on child widgets + if (propertyName == QLatin1String("windowModality") && !sheet->isVisible(index)) + continue; + + const QVariant value = sheet->property(index); + if (DomProperty *p = createProperty(object, propertyName, value)) { + if (compressMargins && (propertyName == QLatin1String("leftMargin") + || propertyName == QLatin1String("rightMargin") + || propertyName == QLatin1String("topMargin") + || propertyName == QLatin1String("bottomMargin"))) { + marginProperties.append(p); + } else if (compressSpacings && (propertyName == QLatin1String("horizontalSpacing") + || propertyName == QLatin1String("verticalSpacing"))) { + spacingProperties.append(p); + } else { + properties.append(p); + } + } + } + if (compressMargins) { + if (marginProperties.count() == 4) { // if we have 3 it means one is reset so we can't compress + DomProperty *marginProperty = marginProperties.at(0); + marginProperty->setAttributeName(QLatin1String("margin")); + properties.append(marginProperty); + delete marginProperties.at(1); + delete marginProperties.at(2); + delete marginProperties.at(3); + } else { + properties += marginProperties; + } + } + if (compressSpacings) { + if (spacingProperties.count() == 2) { + DomProperty *spacingProperty = spacingProperties.at(0); + spacingProperty->setAttributeName(QLatin1String("spacing")); + properties.append(spacingProperty); + delete spacingProperties.at(1); + } else { + properties += spacingProperties; + } + } + } + return properties; +} + +DomProperty *QDesignerResource::applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property) +{ + if (!property) + return 0; + + QExtensionManager *mgr = core()->extensionManager(); + if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(mgr, object)) { + const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(mgr, object); + const QDesignerPropertySheet *designerSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))); + const int index = sheet->indexOf(propertyName); + if ((dynamicSheet && dynamicSheet->isDynamicProperty(index)) || (designerSheet && designerSheet->isDefaultDynamicProperty(index))) + property->setAttributeStdset(0); + } + return property; +} + +// Optimistic check for a standard setter function +static inline bool hasSetter(QDesignerFormEditorInterface *core, QObject *object, const QString &propertyName) +{ + const QDesignerMetaObjectInterface *meta = core->introspection()->metaObject(object); + const int pindex = meta->indexOfProperty(propertyName); + if (pindex == -1) + return true; + return meta->property(pindex)->hasSetter(); +} + +DomProperty *QDesignerResource::createProperty(QObject *object, const QString &propertyName, const QVariant &value) +{ + if (!checkProperty(object, propertyName)) { + return 0; + } + + if (qVariantCanConvert<PropertySheetFlagValue>(value)) { + const PropertySheetFlagValue f = qVariantValue<PropertySheetFlagValue>(value); + const QString flagString = f.metaFlags.toString(f.value, DesignerMetaFlags::FullyQualified); + if (flagString.isEmpty()) + return 0; + + DomProperty *p = new DomProperty; + // check if we have a standard cpp set function + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + p->setAttributeName(propertyName); + p->setElementSet(flagString); + return applyProperStdSetAttribute(object, propertyName, p); + } else if (qVariantCanConvert<PropertySheetEnumValue>(value)) { + const PropertySheetEnumValue e = qVariantValue<PropertySheetEnumValue>(value); + bool ok; + const QString id = e.metaEnum.toString(e.value, DesignerMetaEnum::FullyQualified, &ok); + if (!ok) + designerWarning(e.metaEnum.messageToStringFailed(e.value)); + if (id.isEmpty()) + return 0; + + DomProperty *p = new DomProperty; + // check if we have a standard cpp set function + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + p->setAttributeName(propertyName); + p->setElementEnum(id); + return applyProperStdSetAttribute(object, propertyName, p); + } else if (qVariantCanConvert<PropertySheetStringValue>(value)) { + const PropertySheetStringValue strVal = qVariantValue<PropertySheetStringValue>(value); + DomProperty *p = new DomProperty; + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + + p->setAttributeName(propertyName); + + saveStringProperty(p, strVal); + + return applyProperStdSetAttribute(object, propertyName, p); + } else if (qVariantCanConvert<PropertySheetKeySequenceValue>(value)) { + const PropertySheetKeySequenceValue keyVal = qVariantValue<PropertySheetKeySequenceValue>(value); + DomProperty *p = new DomProperty; + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + + p->setAttributeName(propertyName); + + saveKeySequenceProperty(p, keyVal); + + return applyProperStdSetAttribute(object, propertyName, p); + } + + return applyProperStdSetAttribute(object, propertyName, QAbstractFormBuilder::createProperty(object, propertyName, value)); +} + +QStringList QDesignerResource::mergeWithLoadedPaths(const QStringList &paths) const +{ + QStringList newPaths = paths; +#ifdef OLD_RESOURCE_FORMAT + QStringList loadedPaths = m_resourceBuilder->loadedQrcFiles(); + QStringListIterator it(loadedPaths); + while (it.hasNext()) { + const QString path = it.next(); + if (!newPaths.contains(path)) + newPaths << path; + } +#endif + return newPaths; +} + + +void QDesignerResource::createResources(DomResources *resources) +{ + QStringList paths; + if (resources != 0) { + const QList<DomResource*> dom_include = resources->elementInclude(); + foreach (DomResource *res, dom_include) { + QString path = QDir::cleanPath(m_formWindow->absoluteDir().absoluteFilePath(res->attributeLocation())); + while (!QFile::exists(path)) { + QWidget *dialogParent = m_formWindow->core()->topLevel(); + const QString promptTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "Loading qrc file", 0, QApplication::UnicodeUTF8); + const QString prompt = QApplication::translate("qdesigner_internal::QDesignerResource", "The specified qrc file <p><b>%1</b></p><p>could not be found. Do you want to update the file location?</p>", 0, QApplication::UnicodeUTF8).arg(path); + + const QMessageBox::StandardButton answer = core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::ResourceLoadFailureMessage, + QMessageBox::Warning, promptTitle, prompt, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); + if (answer == QMessageBox::Yes) { + const QFileInfo fi(path); + const QString fileDialogTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "New location for %1", 0, QApplication::UnicodeUTF8).arg(fi.fileName()); + const QString fileDialogPattern = QApplication::translate("qdesigner_internal::QDesignerResource", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8); + path = core()->dialogGui()->getOpenFileName(dialogParent, fileDialogTitle, fi.absolutePath(), fileDialogPattern); + if (path.isEmpty()) + break; + } else { + break; + } + } + if (!path.isEmpty()) { + paths << path; + m_formWindow->addResourceFile(path); + } + } + } + +#ifdef OLD_RESOURCE_FORMAT + paths = mergeWithLoadedPaths(paths); +#endif + + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + if (resourceSet) { + QStringList oldPaths = resourceSet->activeQrcPaths(); + QStringList newPaths = oldPaths; + QStringListIterator it(paths); + while (it.hasNext()) { + const QString path = it.next(); + if (!newPaths.contains(path)) + newPaths << path; + } + resourceSet->activateQrcPaths(newPaths); + } else { + resourceSet = m_formWindow->core()->resourceModel()->addResourceSet(paths); + m_formWindow->setResourceSet(resourceSet); + QObject::connect(m_formWindow->core()->resourceModel(), SIGNAL(resourceSetActivated(QtResourceSet *, bool)), + m_formWindow, SLOT(resourceSetActivated(QtResourceSet *, bool))); + } +} + +DomResources *QDesignerResource::saveResources() +{ + QStringList paths; + if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveAll) { + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + QList<DomResource*> dom_include; + if (resourceSet) + paths = resourceSet->activeQrcPaths(); + } else if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveOnlyUsedQrcFiles) { + paths = m_resourceBuilder->usedQrcFiles(); + } + + return saveResources(paths); +} + +DomResources *QDesignerResource::saveResources(const QStringList &qrcPaths) +{ + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + QList<DomResource*> dom_include; + if (resourceSet) { + const QStringList activePaths = resourceSet->activeQrcPaths(); + foreach (QString path, activePaths) { + if (qrcPaths.contains(path)) { + DomResource *dom_res = new DomResource; + QString conv_path = path; + if (m_resourceBuilder->isSaveRelative()) + conv_path = m_formWindow->absoluteDir().relativeFilePath(path); + dom_res->setAttributeLocation(conv_path.replace(QDir::separator(), QLatin1Char('/'))); + dom_include.append(dom_res); + } + } + } + + DomResources *dom_resources = new DomResources; + dom_resources->setElementInclude(dom_include); + + return dom_resources; +} + +DomAction *QDesignerResource::createDom(QAction *action) +{ + if (!core()->metaDataBase()->item(action) || action->menu()) + return 0; + + return QAbstractFormBuilder::createDom(action); +} + +DomActionGroup *QDesignerResource::createDom(QActionGroup *actionGroup) +{ + if (core()->metaDataBase()->item(actionGroup) != 0) { + return QAbstractFormBuilder::createDom(actionGroup); + } + + return 0; +} + +QAction *QDesignerResource::create(DomAction *ui_action, QObject *parent) +{ + if (QAction *action = QAbstractFormBuilder::create(ui_action, parent)) { + core()->metaDataBase()->add(action); + return action; + } + + return 0; +} + +QActionGroup *QDesignerResource::create(DomActionGroup *ui_action_group, QObject *parent) +{ + if (QActionGroup *actionGroup = QAbstractFormBuilder::create(ui_action_group, parent)) { + core()->metaDataBase()->add(actionGroup); + return actionGroup; + } + + return 0; +} + +DomActionRef *QDesignerResource::createActionRefDom(QAction *action) +{ + if (!core()->metaDataBase()->item(action) + || (!action->isSeparator() && !action->menu() && action->objectName().isEmpty())) + return 0; + + return QAbstractFormBuilder::createActionRefDom(action); +} + +void QDesignerResource::addMenuAction(QAction *action) +{ + core()->metaDataBase()->add(action); +} + +QAction *QDesignerResource::createAction(QObject *parent, const QString &name) +{ + if (QAction *action = QAbstractFormBuilder::createAction(parent, name)) { + core()->metaDataBase()->add(action); + return action; + } + + return 0; +} + +QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QString &name) +{ + if (QActionGroup *actionGroup = QAbstractFormBuilder::createActionGroup(parent, name)) { + core()->metaDataBase()->add(actionGroup); + return actionGroup; + } + + return 0; +} + +/* Apply the attributes to a widget via property sheet where appropriate, + * that is, the sheet handles attributive fake properties */ +void QDesignerResource::applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget) +{ + const DomPropertyList attributes = ui_widget->elementAttribute(); + if (attributes.empty()) + return; + QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), widget); + const DomPropertyList::const_iterator acend = attributes.constEnd(); + for (DomPropertyList::const_iterator it = attributes.constBegin(); it != acend; ++it) { + const QString name = (*it)->attributeName(); + const int index = sheet->indexOf(name); + if (index == -1) { + const QString msg = QString::fromUtf8("Unable to apply attributive property '%1' to '%2'. It does not exist.").arg(name, widget->objectName()); + designerWarning(msg); + } else { + sheet->setProperty(index, domPropertyToVariant(this, widget->metaObject(), *it)); + sheet->setChanged(index, true); + } + } +} + +void QDesignerResource::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + QAbstractFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget); + // Apply the page id attribute of a QWizardPage (which is an attributive fake property) + if (qobject_cast<const QWizardPage*>(widget)) + applyAttributesToPropertySheet(ui_widget, widget); +} + +// Add user defined scripts (dialog box) belonging to QWidget to DomWidget. +void QDesignerResource::addUserDefinedScripts(QWidget *w, DomWidget *ui_widget) +{ + QDesignerFormEditorInterface *core = m_formWindow->core(); + DomScripts domScripts = ui_widget->elementScript(); + // Look up user-defined scripts of designer + if (const qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<const qdesigner_internal::MetaDataBase *>(core->metaDataBase())) { + if (const qdesigner_internal::MetaDataBaseItem *metaItem = metaDataBase->metaDataBaseItem(w)) { + addScript(metaItem->script(), ScriptDesigner, domScripts); + } + } + if (!domScripts.empty()) + ui_widget->setElementScript(domScripts); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qdesigner_resource.h b/tools/designer/src/components/formeditor/qdesigner_resource.h new file mode 100644 index 0000000..3d6a842 --- /dev/null +++ b/tools/designer/src/components/formeditor/qdesigner_resource.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_RESOURCE_H +#define QDESIGNER_RESOURCE_H + +#include "formeditor_global.h" +#include "qsimpleresource_p.h" + +#include <QtCore/QHash> +#include <QtCore/QStack> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE + +class DomCustomWidget; +class DomCustomWidgets; +class DomResource; + +class QDesignerContainerExtension; +class QDesignerFormEditorInterface; +class QDesignerCustomWidgetInterface; +class QDesignerWidgetDataBaseItemInterface; + +class QTabWidget; +class QStackedWidget; +class QToolBox; +class QToolBar; +class QTreeView; +class QTableView; +class QDesignerDockWidget; +class QLayoutWidget; +class QWizardPage; + +namespace qdesigner_internal { + +class FormWindow; + +class QT_FORMEDITOR_EXPORT QDesignerResource : public QEditorFormBuilder +{ +public: + explicit QDesignerResource(FormWindow *fw); + virtual ~QDesignerResource(); + + virtual void save(QIODevice *dev, QWidget *widget); + + virtual bool copy(QIODevice *dev, const FormBuilderClipboard &selection); + virtual DomUI *copy(const FormBuilderClipboard &selection); + + virtual FormBuilderClipboard paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent = 0); + virtual FormBuilderClipboard paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent = 0); + + bool saveRelative() const; + void setSaveRelative(bool relative); + + virtual QWidget *load(QIODevice *dev, QWidget *parentWidget = 0); + +protected: + using QEditorFormBuilder::create; + using QEditorFormBuilder::createDom; + + virtual void saveDom(DomUI *ui, QWidget *widget); + virtual QWidget *create(DomUI *ui, QWidget *parentWidget); + virtual QWidget *create(DomWidget *ui_widget, QWidget *parentWidget); + virtual QLayout *create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget); + virtual QLayoutItem *create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget); + virtual void applyProperties(QObject *o, const QList<DomProperty*> &properties); + virtual QList<DomProperty*> computeProperties(QObject *obj); + virtual DomProperty *createProperty(QObject *object, const QString &propertyName, const QVariant &value); + + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual QLayout *createLayout(const QString &layoutName, QObject *parent, const QString &name); + virtual void createCustomWidgets(DomCustomWidgets *); + virtual void createResources(DomResources*); + virtual void applyTabStops(QWidget *widget, DomTabStops *tabStops); + + virtual bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout); + virtual bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + + virtual DomWidget *createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive = true); + virtual DomLayout *createDom(QLayout *layout, DomLayout *ui_layout, DomWidget *ui_parentWidget); + virtual DomLayoutItem *createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget); + + virtual QAction *create(DomAction *ui_action, QObject *parent); + virtual QActionGroup *create(DomActionGroup *ui_action_group, QObject *parent); + virtual void addMenuAction(QAction *action); + + virtual DomAction *createDom(QAction *action); + virtual DomActionGroup *createDom(QActionGroup *actionGroup); + virtual DomActionRef *createActionRefDom(QAction *action); + + virtual QAction *createAction(QObject *parent, const QString &name); + virtual QActionGroup *createActionGroup(QObject *parent, const QString &name); + + virtual bool checkProperty(QObject *obj, const QString &prop) const; + + DomWidget *saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QToolBox *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QTreeView *treeView, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QTableView *tableView, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget); + + virtual DomCustomWidgets *saveCustomWidgets(); + virtual DomTabStops *saveTabStops(); + virtual DomResources *saveResources(); + + virtual void layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing); + + virtual void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + + void changeObjectName(QObject *o, QString name); + DomProperty *applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property); + +private: + void addUserDefinedScripts(QWidget *w, DomWidget *ui_widget); + DomResources *saveResources(const QStringList &qrcPaths); + bool canCompressMargins(QObject *object) const; + bool canCompressSpacings(QObject *object) const; + QStringList mergeWithLoadedPaths(const QStringList &paths) const; + void applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget); + + typedef QList<DomCustomWidget*> DomCustomWidgetList; + void addCustomWidgetsToWidgetDatabase(DomCustomWidgetList& list); + FormWindow *m_formWindow; + bool m_isMainWidget; + QHash<QString, QString> m_internal_to_qt; + QHash<QString, QString> m_qt_to_internal; + QStack<QLayout*> m_chain; + QHash<QDesignerWidgetDataBaseItemInterface*, bool> m_usedCustomWidgets; + int m_topLevelSpacerCount; + bool m_copyWidget; + QWidget *m_selected; + class QDesignerResourceBuilder *m_resourceBuilder; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_RESOURCE_H diff --git a/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp b/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp new file mode 100644 index 0000000..e3e4a97 --- /dev/null +++ b/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayoutwidget_propertysheet.h" +#include "qlayout_widget_p.h" +#include "formwindow.h" +#include "formeditor.h" + +#include <QtDesigner/QExtensionManager> + +#include <QtGui/QLayout> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +QLayoutWidgetPropertySheet::QLayoutWidgetPropertySheet(QLayoutWidget *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +QLayoutWidgetPropertySheet::~QLayoutWidgetPropertySheet() +{ +} + +bool QLayoutWidgetPropertySheet::isVisible(int index) const +{ + static const QString layoutPropertyGroup = QLatin1String("Layout"); + if (propertyGroup(index) == layoutPropertyGroup) + return QDesignerPropertySheet::isVisible(index); + return false; +} + +void QLayoutWidgetPropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +bool QLayoutWidgetPropertySheet::dynamicPropertiesAllowed() const +{ + return false; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.h b/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.h new file mode 100644 index 0000000..e96adaf --- /dev/null +++ b/tools/designer/src/components/formeditor/qlayoutwidget_propertysheet.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUTWIDGET_PROPERTYSHEET_H +#define QLAYOUTWIDGET_PROPERTYSHEET_H + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> +#include <qlayout_widget_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QLayoutWidgetPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit QLayoutWidgetPropertySheet(QLayoutWidget *object, QObject *parent = 0); + virtual ~QLayoutWidgetPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + + virtual bool dynamicPropertiesAllowed() const; +}; + +typedef QDesignerPropertySheetFactory<QLayoutWidget, QLayoutWidgetPropertySheet> QLayoutWidgetPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QLAYOUTWIDGET_PROPERTYSHEET_H diff --git a/tools/designer/src/components/formeditor/qmainwindow_container.cpp b/tools/designer/src/components/formeditor/qmainwindow_container.cpp new file mode 100644 index 0000000..7fd21d1 --- /dev/null +++ b/tools/designer/src/components/formeditor/qmainwindow_container.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmainwindow_container.h" +#include "qdesigner_toolbar_p.h" +#include "formwindow.h" + +#include <QtCore/qdebug.h> + +#include <QtGui/QLayout> +#include <QtGui/QMenuBar> +#include <QtGui/QToolBar> +#include <QtGui/QStatusBar> +#include <QtGui/QDockWidget> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +QMainWindowContainer::QMainWindowContainer(QMainWindow *widget, QObject *parent) + : QObject(parent), + m_mainWindow(widget) +{ +} + +int QMainWindowContainer::count() const +{ + return m_widgets.count(); +} + +QWidget *QMainWindowContainer::widget(int index) const +{ + if (index == -1) + return 0; + + return m_widgets.at(index); +} + +int QMainWindowContainer::currentIndex() const +{ + return m_mainWindow->centralWidget() ? 0 : -1; +} + +void QMainWindowContainer::setCurrentIndex(int index) +{ + Q_UNUSED(index); +} + + +namespace { + // Pair of <area,break_before> + typedef QPair<Qt::ToolBarArea,bool> ToolBarData; + + ToolBarData toolBarData(QToolBar *me) { + const QMainWindow *mw = qobject_cast<const QMainWindow*>(me->parentWidget()); + if (!mw || !mw->layout() || mw->layout()->indexOf(me) == -1) + return ToolBarData(Qt::TopToolBarArea,false); + return ToolBarData(mw->toolBarArea(me), mw->toolBarBreak(me)); + } + +Qt::DockWidgetArea dockWidgetArea(QDockWidget *me) +{ + if (const QMainWindow *mw = qobject_cast<const QMainWindow*>(me->parentWidget())) { + // Make sure that me is actually managed by mw, otherwise + // QMainWindow::dockWidgetArea() will be VERY upset + QList<QLayout*> candidates; + if (mw->layout()) { + candidates.append(mw->layout()); + candidates += qFindChildren<QLayout*>(mw->layout()); + } + foreach (QLayout *l, candidates) { + if (l->indexOf(me) != -1) { + return mw->dockWidgetArea(me); + } + } + } + return Qt::LeftDockWidgetArea; +} +} + +void QMainWindowContainer::addWidget(QWidget *widget) +{ + // remove all the occurrences of widget + m_widgets.removeAll(widget); + + // the + if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) { + m_widgets.append(widget); + const ToolBarData data = toolBarData(toolBar); + m_mainWindow->addToolBar(data.first, toolBar); + if (data.second) m_mainWindow->insertToolBarBreak(toolBar); + toolBar->show(); + } + + else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(widget)) { + if (menuBar != m_mainWindow->menuBar()) + m_mainWindow->setMenuBar(menuBar); + + m_widgets.append(widget); + menuBar->show(); + } + + else if (QStatusBar *statusBar = qobject_cast<QStatusBar*>(widget)) { + if (statusBar != m_mainWindow->statusBar()) + m_mainWindow->setStatusBar(statusBar); + + m_widgets.append(widget); + statusBar->show(); + } + + else if (QDockWidget *dockWidget = qobject_cast<QDockWidget*>(widget)) { + m_widgets.append(widget); + m_mainWindow->addDockWidget(dockWidgetArea(dockWidget), dockWidget); + dockWidget->show(); + + if (FormWindow *fw = FormWindow::findFormWindow(m_mainWindow)) { + fw->manageWidget(widget); + } + } + + else if (widget) { + m_widgets.prepend(widget); + + if (widget != m_mainWindow->centralWidget()) { + // note that qmainwindow will delete the current central widget if you + // call setCentralWidget(), we end up with dangeling pointers in m_widgets list + m_widgets.removeAll(m_mainWindow->centralWidget()); + + widget->setParent(m_mainWindow); + m_mainWindow->setCentralWidget(widget); + } + } +} + +void QMainWindowContainer::insertWidget(int index, QWidget *widget) +{ + Q_UNUSED(index); + + addWidget(widget); +} + +void QMainWindowContainer::remove(int index) +{ + QWidget *widget = m_widgets.at(index); + if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) { + m_mainWindow->removeToolBar(toolBar); + } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(widget)) { + menuBar->hide(); + menuBar->setParent(0); + m_mainWindow->setMenuBar(0); + } else if (QStatusBar *statusBar = qobject_cast<QStatusBar*>(widget)) { + statusBar->hide(); + statusBar->setParent(0); + m_mainWindow->setStatusBar(0); + } else if (QDockWidget *dockWidget = qobject_cast<QDockWidget*>(widget)) { + m_mainWindow->removeDockWidget(dockWidget); + } + m_widgets.removeAt(index); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qmainwindow_container.h b/tools/designer/src/components/formeditor/qmainwindow_container.h new file mode 100644 index 0000000..aaf942f --- /dev/null +++ b/tools/designer/src/components/formeditor/qmainwindow_container.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMAINWINDOW_CONTAINER_H +#define QMAINWINDOW_CONTAINER_H + +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QExtensionFactory> + +#include <extensionfactory_p.h> + +#include <QtGui/QMainWindow> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QMainWindowContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QMainWindowContainer(QMainWindow *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QMainWindow *m_mainWindow; + QList<QWidget*> m_widgets; +}; + +typedef ExtensionFactory<QDesignerContainerExtension, QMainWindow, QMainWindowContainer> QMainWindowContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QMAINWINDOW_CONTAINER_H diff --git a/tools/designer/src/components/formeditor/qmdiarea_container.cpp b/tools/designer/src/components/formeditor/qmdiarea_container.cpp new file mode 100644 index 0000000..fdeef03 --- /dev/null +++ b/tools/designer/src/components/formeditor/qmdiarea_container.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmdiarea_container.h" + +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtGui/QMdiArea> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QApplication> +#include <QtCore/QDebug> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QMdiAreaContainer::QMdiAreaContainer(QMdiArea *widget, QObject *parent) + : QObject(parent), + m_mdiArea(widget) +{ +} + +int QMdiAreaContainer::count() const +{ + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).count(); +} + +QWidget *QMdiAreaContainer::widget(int index) const +{ + if (index < 0) + return 0; + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).at(index)->widget(); +} + +int QMdiAreaContainer::currentIndex() const +{ + if (QMdiSubWindow *sub = m_mdiArea->activeSubWindow()) + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).indexOf(sub); + return -1; +} + +void QMdiAreaContainer::setCurrentIndex(int index) +{ + if (index < 0) { + qDebug() << "** WARNING Attempt to QMdiAreaContainer::setCurrentIndex(-1)"; + return; + } + QMdiSubWindow *frame = m_mdiArea->subWindowList(QMdiArea::CreationOrder).at(index); + m_mdiArea->setActiveSubWindow(frame); +} + +void QMdiAreaContainer::addWidget(QWidget *widget) +{ + QMdiSubWindow *frame = m_mdiArea->addSubWindow(widget, Qt::Window); + frame->show(); + m_mdiArea->cascadeSubWindows(); + positionNewMdiChild(m_mdiArea, frame); +} + +// Semi-smart positioning of new windows: Make child fill the whole MDI window below +// cascaded other windows +void QMdiAreaContainer::positionNewMdiChild(const QWidget *area, QWidget *mdiChild) +{ + enum { MinSize = 20 }; + const QPoint pos = mdiChild->pos(); + const QSize areaSize = area->size(); + switch (QApplication::layoutDirection()) { + case Qt::LeftToRight: { + const QSize fullSize = QSize(areaSize.width() - pos.x(), areaSize.height() - pos.y()); + if (fullSize.width() > MinSize && fullSize.height() > MinSize) + mdiChild->resize(fullSize); + } + break; + case Qt::RightToLeft: { + const QSize fullSize = QSize(pos.x() + mdiChild->width(), areaSize.height() - pos.y()); + if (fullSize.width() > MinSize && fullSize.height() > MinSize) { + mdiChild->move(0, pos.y()); + mdiChild->resize(fullSize); + } + } + break; + } +} + +void QMdiAreaContainer::insertWidget(int, QWidget *widget) +{ + addWidget(widget); +} + +void QMdiAreaContainer::remove(int index) +{ + QList<QMdiSubWindow *> subWins = m_mdiArea->subWindowList(QMdiArea::CreationOrder); + if (index >= 0 && index < subWins.size()) { + QMdiSubWindow *f = subWins.at(index); + m_mdiArea->removeSubWindow(f->widget()); + delete f; + } +} + +// ---------- MdiAreaPropertySheet, creates fake properties: +// 1) window name (object name of child) +// 2) title (windowTitle of child). + +static const char *subWindowTitleC = "activeSubWindowTitle"; +static const char *subWindowNameC = "activeSubWindowName"; + +QMdiAreaPropertySheet::QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent) : + QDesignerPropertySheet(mdiArea, parent), + m_windowTitleProperty(QLatin1String("windowTitle")) +{ + createFakeProperty(QLatin1String(subWindowNameC), QString()); + createFakeProperty(QLatin1String(subWindowTitleC), QString()); +} + +QMdiAreaPropertySheet::MdiAreaProperty QMdiAreaPropertySheet::mdiAreaProperty(const QString &name) +{ + typedef QHash<QString, MdiAreaProperty> MdiAreaPropertyHash; + static MdiAreaPropertyHash mdiAreaPropertyHash; + if (mdiAreaPropertyHash.empty()) { + mdiAreaPropertyHash.insert(QLatin1String(subWindowNameC), MdiAreaSubWindowName); + mdiAreaPropertyHash.insert(QLatin1String(subWindowTitleC), MdiAreaSubWindowTitle); + } + return mdiAreaPropertyHash.value(name,MdiAreaNone); +} + +void QMdiAreaPropertySheet::setProperty(int index, const QVariant &value) +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + if (QWidget *w = currentWindow()) + w->setObjectName(value.toString()); + break; + case MdiAreaSubWindowTitle: // Forward to window title of subwindow + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + cws->setProperty(index, value); + cws->setChanged(index, true); + } + break; + default: + QDesignerPropertySheet::setProperty(index, value); + break; + } +} + +bool QMdiAreaPropertySheet::reset(int index) +{ + bool rc = true; + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + setProperty(index, QVariant(QString())); + setChanged(index, false); + break; + case MdiAreaSubWindowTitle: // Forward to window title of subwindow + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + rc = cws->reset(index); + } + break; + default: + rc = QDesignerPropertySheet::reset(index); + break; + } + return rc; +} + +QVariant QMdiAreaPropertySheet::property(int index) const +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + if (QWidget *w = currentWindow()) + return w->objectName(); + return QVariant(QString()); + case MdiAreaSubWindowTitle: + if (QWidget *w = currentWindow()) + return w->windowTitle(); + return QVariant(QString()); + case MdiAreaNone: + break; + } + return QDesignerPropertySheet::property(index); +} + +bool QMdiAreaPropertySheet::isEnabled(int index) const +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + case MdiAreaSubWindowTitle: + return currentWindow() != 0; + case MdiAreaNone: + break; + } + return QDesignerPropertySheet::isEnabled(index); +} + +bool QMdiAreaPropertySheet::isChanged(int index) const +{ + bool rc = false; + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + rc = currentWindow() != 0; + break; + case MdiAreaSubWindowTitle: + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + rc = cws->isChanged(index); + } + break; + default: + rc = QDesignerPropertySheet::isChanged(index); + break; + } + return rc; +} + +QWidget *QMdiAreaPropertySheet::currentWindow() const +{ + if (const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), object())) { + const int ci = c->currentIndex(); + if (ci < 0) + return 0; + return c->widget(ci); + } + return 0; +} + +QDesignerPropertySheetExtension *QMdiAreaPropertySheet::currentWindowSheet() const +{ + QWidget *cw = currentWindow(); + if (cw == 0) + return 0; + return qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), cw); +} + +bool QMdiAreaPropertySheet::checkProperty(const QString &propertyName) +{ + return mdiAreaProperty(propertyName) == MdiAreaNone; +} +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qmdiarea_container.h b/tools/designer/src/components/formeditor/qmdiarea_container.h new file mode 100644 index 0000000..462c11f --- /dev/null +++ b/tools/designer/src/components/formeditor/qmdiarea_container.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMDIAREA_CONTAINER_H +#define QMDIAREA_CONTAINER_H + +#include <QtDesigner/QDesignerContainerExtension> + + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> + +#include <QtGui/QMdiArea> +#include <QtGui/QWorkspace> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Container for QMdiArea +class QMdiAreaContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QMdiAreaContainer(QMdiArea *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + + // Semismart positioning of a new MDI child after cascading + static void positionNewMdiChild(const QWidget *area, QWidget *mdiChild); + +private: + QMdiArea *m_mdiArea; +}; + +// PropertySheet for QMdiArea: Fakes window title and name. +// Also works for a QWorkspace as it relies on the container extension. + +class QMdiAreaPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent = 0); + + virtual void setProperty(int index, const QVariant &value); + virtual bool reset(int index); + virtual bool isEnabled(int index) const; + virtual bool isChanged(int index) const; + virtual QVariant property(int index) const; + + // Check whether the property is to be saved. Returns false for the page + // properties (as the property sheet has no concept of 'stored') + static bool checkProperty(const QString &propertyName); + +private: + const QString m_windowTitleProperty; + QWidget *currentWindow() const; + QDesignerPropertySheetExtension *currentWindowSheet() const; + + enum MdiAreaProperty { MdiAreaSubWindowName, MdiAreaSubWindowTitle, MdiAreaNone }; + static MdiAreaProperty mdiAreaProperty(const QString &name); +}; + +// Factories + +typedef ExtensionFactory<QDesignerContainerExtension, QMdiArea, QMdiAreaContainer> QMdiAreaContainerFactory; +typedef QDesignerPropertySheetFactory<QMdiArea, QMdiAreaPropertySheet> QMdiAreaPropertySheetFactory; +typedef QDesignerPropertySheetFactory<QWorkspace, QMdiAreaPropertySheet> QWorkspacePropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QMDIAREA_CONTAINER_H diff --git a/tools/designer/src/components/formeditor/qtbrushmanager.cpp b/tools/designer/src/components/formeditor/qtbrushmanager.cpp new file mode 100644 index 0000000..c28c6b9 --- /dev/null +++ b/tools/designer/src/components/formeditor/qtbrushmanager.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtbrushmanager.h" +#include <QtGui/QPixmap> +#include <QtGui/QPainter> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QtBrushManagerPrivate +{ + QtBrushManager *q_ptr; + Q_DECLARE_PUBLIC(QtBrushManager) +public: + QMap<QString, QBrush> theBrushMap; + QString theCurrentBrush; +}; + +QtBrushManager::QtBrushManager(QObject *parent) + : QDesignerBrushManagerInterface(parent) +{ + d_ptr = new QtBrushManagerPrivate; + d_ptr->q_ptr = this; + +} + +QtBrushManager::~QtBrushManager() +{ + delete d_ptr; +} + +QBrush QtBrushManager::brush(const QString &name) const +{ + if (d_ptr->theBrushMap.contains(name)) + return d_ptr->theBrushMap[name]; + return QBrush(); +} + +QMap<QString, QBrush> QtBrushManager::brushes() const +{ + return d_ptr->theBrushMap; +} + +QString QtBrushManager::currentBrush() const +{ + return d_ptr->theCurrentBrush; +} + +QString QtBrushManager::addBrush(const QString &name, const QBrush &brush) +{ + if (name.isNull()) + return QString(); + + QString newName = name; + QString nameBase = newName; + int i = 0; + while (d_ptr->theBrushMap.contains(newName)) { + newName = nameBase + QString::number(++i); + } + d_ptr->theBrushMap[newName] = brush; + emit brushAdded(newName, brush); + + return newName; +} + +void QtBrushManager::removeBrush(const QString &name) +{ + if (!d_ptr->theBrushMap.contains(name)) + return; + if (currentBrush() == name) + setCurrentBrush(QString()); + emit brushRemoved(name); + d_ptr->theBrushMap.remove(name); +} + +void QtBrushManager::setCurrentBrush(const QString &name) +{ + QBrush newBrush; + if (!name.isNull()) { + if (d_ptr->theBrushMap.contains(name)) + newBrush = d_ptr->theBrushMap[name]; + else + return; + } + d_ptr->theCurrentBrush = name; + emit currentBrushChanged(name, newBrush); +} + +QPixmap QtBrushManager::brushPixmap(const QBrush &brush) const +{ + int w = 64; + int h = 64; + + QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(0, 0, w, h), brush); + return QPixmap::fromImage(img); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qtbrushmanager.h b/tools/designer/src/components/formeditor/qtbrushmanager.h new file mode 100644 index 0000000..f8f1b8a --- /dev/null +++ b/tools/designer/src/components/formeditor/qtbrushmanager.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTBRUSHMANAGER_H +#define QTBRUSHMANAGER_H + +#include <QtDesigner/QDesignerBrushManagerInterface> +#include "formeditor_global.h" + +#include <QtCore/QObject> +#include <QtCore/QMap> +#include <QtGui/QBrush> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QtBrushManagerPrivate; + +class QT_FORMEDITOR_EXPORT QtBrushManager : public QDesignerBrushManagerInterface +{ + Q_OBJECT +public: + QtBrushManager(QObject *parent = 0); + ~QtBrushManager(); + + QBrush brush(const QString &name) const; + QMap<QString, QBrush> brushes() const; + QString currentBrush() const; + + QString addBrush(const QString &name, const QBrush &brush); + void removeBrush(const QString &name); + void setCurrentBrush(const QString &name); + + QPixmap brushPixmap(const QBrush &brush) const; +signals: + void brushAdded(const QString &name, const QBrush &brush); + void brushRemoved(const QString &name); + void currentBrushChanged(const QString &name, const QBrush &brush); + +private: + QtBrushManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(QtBrushManager) + Q_DISABLE_COPY(QtBrushManager) +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/tools/designer/src/components/formeditor/qwizard_container.cpp b/tools/designer/src/components/formeditor/qwizard_container.cpp new file mode 100644 index 0000000..669f71a --- /dev/null +++ b/tools/designer/src/components/formeditor/qwizard_container.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwizard_container.h" + +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtGui/QWizard> +#include <QtGui/QWizardPage> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +typedef QList<int> IdList; +typedef QList<QWizardPage *> WizardPageList; + +namespace qdesigner_internal { + +QWizardContainer::QWizardContainer(QWizard *widget, QObject *parent) : + QObject(parent), + m_wizard(widget) +{ +} + +int QWizardContainer::count() const +{ + return m_wizard->pageIds().size(); +} + +QWidget *QWizardContainer::widget(int index) const +{ + QWidget *rc = 0; + if (index >= 0) { + const IdList idList = m_wizard->pageIds(); + if (index < idList.size()) + rc = m_wizard->page(idList.at(index)); + } + return rc; +} + +int QWizardContainer::currentIndex() const +{ + const IdList idList = m_wizard->pageIds(); + const int currentId = m_wizard->currentId(); + const int rc = idList.empty() ? -1 : idList.indexOf(currentId); + return rc; +} + +void QWizardContainer::setCurrentIndex(int index) +{ + if (index < 0 || m_wizard->pageIds().empty()) + return; + + int currentIdx = currentIndex(); + + if (currentIdx == -1) { + m_wizard->restart(); + currentIdx = currentIndex(); + } + + if (currentIdx == index) + return; + + const int d = qAbs(index - currentIdx); + if (index > currentIdx) { + for (int i = 0; i < d; i++) + m_wizard->next(); + } else { + for (int i = 0; i < d; i++) + m_wizard->back(); + } +} + +static const char *msgWrongType = "** WARNING Attempt to add oject that is not of class WizardPage to a QWizard"; + +void QWizardContainer::addWidget(QWidget *widget) +{ + QWizardPage *page = qobject_cast<QWizardPage *>(widget); + if (!page) { + qWarning("%s", msgWrongType); + return; + } + m_wizard->addPage(page); + // Might be -1 after adding the first page + setCurrentIndex(m_wizard->pageIds().size() - 1); +} + +void QWizardContainer::insertWidget(int index, QWidget *widget) +{ + enum { delta = 5 }; + + QWizardPage *newPage = qobject_cast<QWizardPage *>(widget); + if (!newPage) { + qWarning("%s", msgWrongType); + return; + } + + const IdList idList = m_wizard->pageIds(); + const int pageCount = idList.size(); + if (index >= pageCount) { + addWidget(widget); + return; + } + + // Insert before, reshuffle ids if required + const int idBefore = idList.at(index); + const int newId = idBefore - 1; + const bool needsShuffle = + (index == 0 && newId < 0) // At start: QWizard refuses to insert id -1 + || (index > 0 && idList.at(index - 1) == newId); // In-between + if (needsShuffle) { + // Create a gap by shuffling pages + WizardPageList pageList; + pageList.push_back(newPage); + for (int i = index; i < pageCount; i++) { + pageList.push_back(m_wizard->page(idList.at(i))); + m_wizard->removePage(idList.at(i)); + } + int newId = idBefore + delta; + const WizardPageList::const_iterator wcend = pageList.constEnd(); + for (WizardPageList::const_iterator it = pageList.constBegin(); it != wcend; ++it) { + m_wizard->setPage(newId, *it); + newId += delta; + } + } else { + // Gap found, just insert + m_wizard->setPage(newId, newPage); + } + // Might be at -1 after adding the first page + setCurrentIndex(index); +} + +void QWizardContainer::remove(int index) +{ + if (index < 0) + return; + + const IdList idList = m_wizard->pageIds(); + if (index >= idList.size()) + return; + + m_wizard->removePage(idList.at(index)); + // goto next page, preferably + const int newSize = idList.size() - 1; + if (index < newSize) { + setCurrentIndex(index); + } else { + if (newSize > 0) + setCurrentIndex(newSize - 1); + } +} + +// ---------------- QWizardPagePropertySheet +const char *QWizardPagePropertySheet::pageIdProperty = "pageId"; + +QWizardPagePropertySheet::QWizardPagePropertySheet(QWizardPage *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_pageIdIndex(createFakeProperty(QLatin1String(pageIdProperty), QString())) +{ + setAttribute(m_pageIdIndex, true); +} + +bool QWizardPagePropertySheet::reset(int index) +{ + if (index == m_pageIdIndex) { + setProperty(index, QString()); + return true; + } + return QDesignerPropertySheet::reset(index); +} + +// ---------------- QWizardPropertySheet +QWizardPropertySheet::QWizardPropertySheet(QWizard *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_startId(QLatin1String("startId")) +{ +} + +bool QWizardPropertySheet::isVisible(int index) const +{ + if (propertyName(index) == m_startId) + return false; + return QDesignerPropertySheet::isVisible(index); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qwizard_container.h b/tools/designer/src/components/formeditor/qwizard_container.h new file mode 100644 index 0000000..6667a1d --- /dev/null +++ b/tools/designer/src/components/formeditor/qwizard_container.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIZARD_CONTAINER_H +#define QWIZARD_CONTAINER_H + +#include <QtDesigner/QDesignerContainerExtension> + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> + +#include <QtGui/QWizard> +#include <QtGui/QWizardPage> + +QT_BEGIN_NAMESPACE + +class QWizardPage; + +namespace qdesigner_internal { + +// Container for QWizard. Care must be taken to position +// the QWizard at some valid page after removal/insertion +// as it is not used to having its pages ripped out. +class QWizardContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QWizardContainer(QWizard *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QWizard *m_wizard; +}; + +// QWizardPagePropertySheet: Introduces a attribute string fake property +// "pageId" that allows for specifying enumeration values (uic only). +// This breaks the pattern of having a "currentSth" property for the +// container, but was deemed to make sense here since the Page has +// its own "title" properties. +class QWizardPagePropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT +public: + explicit QWizardPagePropertySheet(QWizardPage *object, QObject *parent = 0); + + virtual bool reset(int index); + + static const char *pageIdProperty; + +private: + const int m_pageIdIndex; +}; + +// QWizardPropertySheet: Hides the "startId" property. It cannot be used +// as QWizard cannot handle setting it as a property before the actual +// page is added. + +class QWizardPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT +public: + explicit QWizardPropertySheet(QWizard *object, QObject *parent = 0); + virtual bool isVisible(int index) const; + +private: + const QString m_startId; +}; + +// Factories +typedef QDesignerPropertySheetFactory<QWizard, QWizardPropertySheet> QWizardPropertySheetFactory; +typedef QDesignerPropertySheetFactory<QWizardPage, QWizardPagePropertySheet> QWizardPagePropertySheetFactory; +typedef ExtensionFactory<QDesignerContainerExtension, QWizard, QWizardContainer> QWizardContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QWIZARD_CONTAINER_H diff --git a/tools/designer/src/components/formeditor/qworkspace_container.cpp b/tools/designer/src/components/formeditor/qworkspace_container.cpp new file mode 100644 index 0000000..03cb382 --- /dev/null +++ b/tools/designer/src/components/formeditor/qworkspace_container.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qworkspace_container.h" +#include "qmdiarea_container.h" + +#include <QtGui/QWorkspace> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QWorkspaceContainer::QWorkspaceContainer(QWorkspace *widget, QObject *parent) + : QObject(parent), + m_workspace(widget) +{ +} + +int QWorkspaceContainer::count() const +{ + return m_workspace->windowList(QWorkspace::CreationOrder).count(); +} + +QWidget *QWorkspaceContainer::widget(int index) const +{ + if (index < 0) + return 0; + return m_workspace->windowList(QWorkspace::CreationOrder).at(index); +} + +int QWorkspaceContainer::currentIndex() const +{ + if (QWidget *aw = m_workspace->activeWindow()) + return m_workspace->windowList(QWorkspace::CreationOrder).indexOf(aw); + return -1; +} + +void QWorkspaceContainer::setCurrentIndex(int index) +{ + m_workspace->setActiveWindow(m_workspace->windowList(QWorkspace::CreationOrder).at(index)); +} + +void QWorkspaceContainer::addWidget(QWidget *widget) +{ + QWidget *frame = m_workspace->addWindow(widget, Qt::Window); + frame->show(); + m_workspace->cascade(); + QMdiAreaContainer::positionNewMdiChild(m_workspace, frame); +} + +void QWorkspaceContainer::insertWidget(int, QWidget *widget) +{ + addWidget(widget); +} + +void QWorkspaceContainer::remove(int /* index */) +{ + // nothing to do here, reparenting to formwindow is apparently sufficient +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/qworkspace_container.h b/tools/designer/src/components/formeditor/qworkspace_container.h new file mode 100644 index 0000000..fa1e66c --- /dev/null +++ b/tools/designer/src/components/formeditor/qworkspace_container.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWORKSPACE_CONTAINER_H +#define QWORKSPACE_CONTAINER_H + +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QExtensionFactory> + +#include <extensionfactory_p.h> +#include <QtGui/QWorkspace> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QWorkspaceContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QWorkspaceContainer(QWorkspace *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QWorkspace *m_workspace; +}; + +typedef ExtensionFactory<QDesignerContainerExtension, QWorkspace, QWorkspaceContainer> QWorkspaceContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QWORKSPACE_CONTAINER_H diff --git a/tools/designer/src/components/formeditor/spacer_propertysheet.cpp b/tools/designer/src/components/formeditor/spacer_propertysheet.cpp new file mode 100644 index 0000000..16dd69d --- /dev/null +++ b/tools/designer/src/components/formeditor/spacer_propertysheet.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "spacer_propertysheet.h" +#include "qdesigner_widget_p.h" +#include "formwindow.h" +#include "spacer_widget_p.h" + +#include <QtDesigner/QExtensionManager> + +#include <QtGui/QLayout> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal +{ +SpacerPropertySheet::SpacerPropertySheet(Spacer *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +SpacerPropertySheet::~SpacerPropertySheet() +{ +} + +bool SpacerPropertySheet::isVisible(int index) const +{ + static const QString spacerGroup = QLatin1String("Spacer"); + return propertyGroup(index) == spacerGroup; +} + +void SpacerPropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +bool SpacerPropertySheet::dynamicPropertiesAllowed() const +{ + return false; +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/spacer_propertysheet.h b/tools/designer/src/components/formeditor/spacer_propertysheet.h new file mode 100644 index 0000000..a83e3d1 --- /dev/null +++ b/tools/designer/src/components/formeditor/spacer_propertysheet.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SPACER_PROPERTYSHEET_H +#define SPACER_PROPERTYSHEET_H + +#include <qdesigner_propertysheet_p.h> +#include <extensionfactory_p.h> +#include <spacer_widget_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class SpacerPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit SpacerPropertySheet(Spacer *object, QObject *parent = 0); + virtual ~SpacerPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + + virtual bool dynamicPropertiesAllowed() const; +}; + +typedef QDesignerPropertySheetFactory<Spacer, SpacerPropertySheet> SpacerPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SPACER_PROPERTYSHEET_H diff --git a/tools/designer/src/components/formeditor/templateoptionspage.cpp b/tools/designer/src/components/formeditor/templateoptionspage.cpp new file mode 100644 index 0000000..dacd0d3 --- /dev/null +++ b/tools/designer/src/components/formeditor/templateoptionspage.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "templateoptionspage.h" +#include "ui_templateoptionspage.h" + +#include <shared_settings_p.h> +#include <iconloader_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <abstractdialoggui_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ----------------- TemplateOptionsWidget +TemplateOptionsWidget::TemplateOptionsWidget(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_core(core), + m_ui(new Ui::TemplateOptionsWidget) +{ + m_ui->setupUi(this); + + m_ui->m_addTemplatePathButton->setIcon( + qdesigner_internal::createIconSet(QString::fromUtf8("plus.png"))); + m_ui->m_removeTemplatePathButton->setIcon( + qdesigner_internal::createIconSet(QString::fromUtf8("minus.png"))); + + connect(m_ui->m_templatePathListWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(templatePathSelectionChanged())); + connect(m_ui->m_addTemplatePathButton, SIGNAL(clicked()), this, SLOT(addTemplatePath())); + connect(m_ui->m_removeTemplatePathButton, SIGNAL(clicked()), this, SLOT(removeTemplatePath())); +} + +TemplateOptionsWidget::~TemplateOptionsWidget() +{ + delete m_ui; +} + +QStringList TemplateOptionsWidget::templatePaths() const +{ + QStringList rc; + const int count = m_ui->m_templatePathListWidget->count(); + for (int i = 0; i < count; i++) { + rc += m_ui->m_templatePathListWidget->item(i)->text(); + } + return rc; +} + +void TemplateOptionsWidget::setTemplatePaths(const QStringList &l) +{ + // add paths and select 0 + m_ui->m_templatePathListWidget->clear(); + if (l.empty()) { + // disable button + templatePathSelectionChanged(); + } else { + const QStringList::const_iterator cend = l.constEnd(); + for (QStringList::const_iterator it = l.constBegin(); it != cend; ++it) + m_ui->m_templatePathListWidget->addItem(*it); + m_ui->m_templatePathListWidget->setCurrentItem(m_ui->m_templatePathListWidget->item(0)); + } +} + +void TemplateOptionsWidget::addTemplatePath() +{ + const QString templatePath = chooseTemplatePath(m_core, this); + if (templatePath.isEmpty()) + return; + + const QList<QListWidgetItem *> existing + = m_ui->m_templatePathListWidget->findItems(templatePath, Qt::MatchExactly); + if (!existing.empty()) + return; + + QListWidgetItem *newItem = new QListWidgetItem(templatePath); + m_ui->m_templatePathListWidget->addItem(newItem); + m_ui->m_templatePathListWidget->setCurrentItem(newItem); +} + +void TemplateOptionsWidget::removeTemplatePath() +{ + const QList<QListWidgetItem *> selectedPaths + = m_ui->m_templatePathListWidget->selectedItems(); + if (selectedPaths.empty()) + return; + delete selectedPaths.front(); +} + +void TemplateOptionsWidget::templatePathSelectionChanged() +{ + const QList<QListWidgetItem *> selectedPaths = m_ui->m_templatePathListWidget->selectedItems(); + m_ui->m_removeTemplatePathButton->setEnabled(!selectedPaths.empty()); +} + +QString TemplateOptionsWidget::chooseTemplatePath(QDesignerFormEditorInterface *core, QWidget *parent) +{ + QString rc = core->dialogGui()->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; +} + +// ----------------- TemplateOptionsPage +TemplateOptionsPage::TemplateOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString TemplateOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("TemplateOptionsPage", "Template Paths"); +} + +QWidget *TemplateOptionsPage::createPage(QWidget *parent) +{ + m_widget = new TemplateOptionsWidget(m_core, parent); + m_initialTemplatePaths = QDesignerSharedSettings(m_core).additionalFormTemplatePaths(); + m_widget->setTemplatePaths(m_initialTemplatePaths); + return m_widget; +} + +void TemplateOptionsPage::apply() +{ + if (m_widget) { + const QStringList newTemplatePaths = m_widget->templatePaths(); + if (newTemplatePaths != m_initialTemplatePaths) { + QDesignerSharedSettings settings(m_core); + settings.setAdditionalFormTemplatePaths(newTemplatePaths); + m_initialTemplatePaths = newTemplatePaths; + } + } +} + +void TemplateOptionsPage::finish() +{ +} +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/templateoptionspage.h b/tools/designer/src/components/formeditor/templateoptionspage.h new file mode 100644 index 0000000..2f17141 --- /dev/null +++ b/tools/designer/src/components/formeditor/templateoptionspage.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_TEMPLATEOPTIONS_H +#define QDESIGNER_TEMPLATEOPTIONS_H + +#include <QtDesigner/private/abstractoptionspage_p.h> + +#include <QtCore/QPointer> +#include <QtCore/QStringList> + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +namespace Ui { + class TemplateOptionsWidget; +} + +/* Present the user with a list of form template paths to save + * form templates. */ +class TemplateOptionsWidget : public QWidget +{ + Q_OBJECT + Q_DISABLE_COPY(TemplateOptionsWidget) +public: + explicit TemplateOptionsWidget(QDesignerFormEditorInterface *core, + QWidget *parent = 0); + ~TemplateOptionsWidget(); + + + QStringList templatePaths() const; + void setTemplatePaths(const QStringList &l); + + static QString chooseTemplatePath(QDesignerFormEditorInterface *core, QWidget *parent); + +private slots: + void addTemplatePath(); + void removeTemplatePath(); + void templatePathSelectionChanged(); + +private: + QDesignerFormEditorInterface *m_core; + Ui::TemplateOptionsWidget *m_ui; +}; + +class TemplateOptionsPage : public QDesignerOptionsPageInterface +{ + Q_DISABLE_COPY(TemplateOptionsPage) +public: + explicit TemplateOptionsPage(QDesignerFormEditorInterface *core); + + virtual QString name() const; + virtual QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +private: + QDesignerFormEditorInterface *m_core; + QStringList m_initialTemplatePaths; + QPointer<TemplateOptionsWidget> m_widget; +}; + +} + +QT_END_NAMESPACE + +#endif // QDESIGNER_TEMPLATEOPTIONS_H diff --git a/tools/designer/src/components/formeditor/templateoptionspage.ui b/tools/designer/src/components/formeditor/templateoptionspage.ui new file mode 100644 index 0000000..3427ffe --- /dev/null +++ b/tools/designer/src/components/formeditor/templateoptionspage.ui @@ -0,0 +1,59 @@ +<ui version="4.0" > + <class>qdesigner_internal::TemplateOptionsWidget</class> + <widget class="QWidget" name="qdesigner_internal::TemplateOptionsWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>376</width> + <height>387</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item row="0" column="0" > + <widget class="QGroupBox" name="m_templatePathGroupBox" > + <property name="title" > + <string>Additional Template Paths</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="3" > + <widget class="QListWidget" name="m_templatePathListWidget" /> + </item> + <item row="1" column="0" > + <widget class="QToolButton" name="m_addTemplatePathButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QToolButton" name="m_removeTemplatePathButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/designer/src/components/formeditor/tool_widgeteditor.cpp b/tools/designer/src/components/formeditor/tool_widgeteditor.cpp new file mode 100644 index 0000000..3a59543 --- /dev/null +++ b/tools/designer/src/components/formeditor/tool_widgeteditor.cpp @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::WidgetEditorTool +*/ + +#include "tool_widgeteditor.h" +#include "formwindow.h" + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetFactoryInterface> +#include <QtDesigner/QDesignerWidgetBoxInterface> + +#include <layoutinfo_p.h> +#include <qdesigner_dnditem_p.h> +#include <qdesigner_resource.h> + +#include <QtGui/qevent.h> +#include <QtGui/QAction> +#include <QtGui/QMainWindow> +#include <QtGui/QCursor> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +WidgetEditorTool::WidgetEditorTool(FormWindow *formWindow) + : QDesignerFormWindowToolInterface(formWindow), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Widgets"), this)), + m_specialDockDrag(false) +{ +} + +QAction *WidgetEditorTool::action() const +{ + return m_action; +} + +WidgetEditorTool::~WidgetEditorTool() +{ +} + +QDesignerFormEditorInterface *WidgetEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *WidgetEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool WidgetEditorTool::mainWindowSeparatorEvent(QWidget *widget, QEvent *event) +{ + QMainWindow *mw = qobject_cast<QMainWindow*>(widget); + if (mw == 0) + return false; + + if (event->type() != QEvent::MouseButtonPress + && event->type() != QEvent::MouseMove + && event->type() != QEvent::MouseButtonRelease) + return false; + + QMouseEvent *e = static_cast<QMouseEvent*>(event); + + if (event->type() == QEvent::MouseButtonPress) { + if (mw->isSeparator(e->pos())) { + m_separator_drag_mw = mw; + return true; + } + return false; + } + + if (event->type() == QEvent::MouseMove) + return m_separator_drag_mw == mw; + + if (event->type() == QEvent::MouseButtonRelease) { + if (m_separator_drag_mw != mw) + return false; + m_separator_drag_mw = 0; + return true; + } + + return false; +} + +bool WidgetEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + const bool passive = core()->widgetFactory()->isPassiveInteractor(widget) != 0 + || mainWindowSeparatorEvent(widget, event); // separators in QMainWindow + // are no longer widgets + switch (event->type()) { + case QEvent::Resize: + case QEvent::Move: + m_formWindow->updateSelection(widget); + break; + + case QEvent::FocusOut: + case QEvent::FocusIn: // Popup cancelled over a form widget: Reset its focus frame + return !(passive || widget == m_formWindow || widget == m_formWindow->mainContainer()); + + case QEvent::Wheel: // Prevent spinboxes and combos from reacting + return !passive; + + case QEvent::KeyPress: + return !passive && handleKeyPressEvent(widget, managedWidget, static_cast<QKeyEvent*>(event)); + + case QEvent::KeyRelease: + return !passive && handleKeyReleaseEvent(widget, managedWidget, static_cast<QKeyEvent*>(event)); + + case QEvent::MouseMove: + return !passive && handleMouseMoveEvent(widget, managedWidget, static_cast<QMouseEvent*>(event)); + + case QEvent::MouseButtonPress: + return !passive && handleMousePressEvent(widget, managedWidget, static_cast<QMouseEvent*>(event)); + + case QEvent::MouseButtonRelease: + return !passive && handleMouseReleaseEvent(widget, managedWidget, static_cast<QMouseEvent*>(event)); + + case QEvent::MouseButtonDblClick: + return !passive && handleMouseButtonDblClickEvent(widget, managedWidget, static_cast<QMouseEvent*>(event)); + + case QEvent::ContextMenu: + return !passive && handleContextMenu(widget, managedWidget, static_cast<QContextMenuEvent*>(event)); + + case QEvent::DragEnter: + return handleDragEnterMoveEvent(widget, managedWidget, static_cast<QDragEnterEvent *>(event), true); + case QEvent::DragMove: + return handleDragEnterMoveEvent(widget, managedWidget, static_cast<QDragEnterEvent *>(event), false); + case QEvent::DragLeave: + return handleDragLeaveEvent(widget, managedWidget, static_cast<QDragLeaveEvent *>(event)); + case QEvent::Drop: + return handleDropEvent(widget, managedWidget, static_cast<QDropEvent *>(event)); + default: + break; + + } // end switch + + return false; +} + +// ### remove me + +bool WidgetEditorTool::handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e) +{ + return m_formWindow->handleContextMenu(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseButtonDblClickEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMousePressEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseMoveEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseReleaseEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) +{ + return m_formWindow->handleKeyPressEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) +{ + return m_formWindow->handleKeyReleaseEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handlePaintEvent(QWidget *widget, QWidget *managedWidget, QPaintEvent *e) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(e); + + return false; +} + +void WidgetEditorTool::detectDockDrag(const QDesignerMimeData *mimeData) +{ + m_specialDockDrag = false; + if (!mimeData) + return; + + QMainWindow *mw = qobject_cast<QMainWindow*>(m_formWindow->mainContainer()); + if (!mw) + return; + + const QList<QDesignerDnDItemInterface*> item_list = mimeData->items(); + + foreach (QDesignerDnDItemInterface *item, item_list) { + if (item->decoration() && item->decoration()->property("_q_dockDrag").toBool()) + m_specialDockDrag = true; + + } +} + +bool WidgetEditorTool::handleDragEnterMoveEvent(QWidget *widget, QWidget * /*managedWidget*/, QDragMoveEvent *e, bool isEnter) +{ + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(e->mimeData()); + if (!mimeData) + return false; + + if (!m_formWindow->hasFeature(QDesignerFormWindowInterface::EditFeature)) { + e->ignore(); + return true; + } + + if (isEnter) + detectDockDrag(mimeData); + + + QPoint globalPos = QPoint(0, 0); + if (m_specialDockDrag) { + m_lastDropTarget = 0; + QMainWindow *mw = qobject_cast<QMainWindow*>(m_formWindow->mainContainer()); + if (mw) + m_lastDropTarget = mw->centralWidget(); + } else { + // If custom widgets have acceptDrops=true, the event occurs for them + const QPoint formPos = widget != m_formWindow ? widget->mapTo(m_formWindow, e->pos()) : e->pos(); + globalPos = m_formWindow->mapToGlobal(formPos); + const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; + QWidget *dropTarget = m_formWindow->widgetUnderMouse(formPos, wum); + if (m_lastDropTarget && dropTarget != m_lastDropTarget) + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Restore); + m_lastDropTarget = dropTarget; + } + + if (m_lastDropTarget) + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Highlight); + + if (isEnter || m_lastDropTarget) + mimeData->acceptEvent(e); + else + e->ignore(); + return true; +} + +bool WidgetEditorTool::handleDropEvent(QWidget *widget, QWidget *, QDropEvent *e) +{ + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(e->mimeData()); + if (!mimeData) + return false; + + if (!m_lastDropTarget || + !m_formWindow->hasFeature(QDesignerFormWindowInterface::EditFeature)) { + e->ignore(); + return true; + } + // FormWindow determines the position from the decoration. + const QPoint globalPos = widget->mapToGlobal(e->pos()); + mimeData->moveDecoration(globalPos); + if (m_specialDockDrag) { + if (!m_formWindow->dropDockWidget(mimeData->items().at(0), globalPos)) { + e->ignore(); + return true; + } + } else if (!m_formWindow->dropWidgets(mimeData->items(), m_lastDropTarget, globalPos)) { + e->ignore(); + return true; + } + mimeData->acceptEvent(e); + return true; +} + +bool WidgetEditorTool::restoreDropHighlighting() +{ + if (!m_lastDropTarget) + return false; + + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(QCursor::pos()), FormWindow::Restore); + m_lastDropTarget = 0; + return true; +} + +bool WidgetEditorTool::handleDragLeaveEvent(QWidget *, QWidget *, QDragLeaveEvent *event) +{ + if (restoreDropHighlighting()) { + event->accept(); + return true; + } + return false; +} + +QWidget *WidgetEditorTool::editor() const +{ + Q_ASSERT(formWindow() != 0); + return formWindow()->mainContainer(); +} + +void WidgetEditorTool::activated() +{ + if (core()->widgetBox()) + core()->widgetBox()->setEnabled(true); + + if (m_formWindow == 0) + return; + + QList<QWidget*> sel = m_formWindow->selectedWidgets(); + foreach (QWidget *w, sel) + m_formWindow->raiseSelection(w); +} + +void WidgetEditorTool::deactivated() +{ + if (core()->widgetBox()) + core()->widgetBox()->setEnabled(false); + + if (m_formWindow == 0) + return; + + m_formWindow->clearSelection(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/tool_widgeteditor.h b/tools/designer/src/components/formeditor/tool_widgeteditor.h new file mode 100644 index 0000000..58df974 --- /dev/null +++ b/tools/designer/src/components/formeditor/tool_widgeteditor.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOOL_WIDGETEDITOR_H +#define TOOL_WIDGETEDITOR_H + +#include <QtDesigner/QDesignerFormWindowToolInterface> + +#include <QtGui/qevent.h> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QAction; +class QMainWindow; + +namespace qdesigner_internal { + +class FormWindow; +class QDesignerMimeData; + +class WidgetEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit WidgetEditorTool(FormWindow *formWindow); + virtual ~WidgetEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + bool handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e); + bool handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handlePaintEvent(QWidget *widget, QWidget *managedWidget, QPaintEvent *e); + + bool handleDragEnterMoveEvent(QWidget *widget, QWidget *managedWidget, QDragMoveEvent *e, bool isEnter); + bool handleDragLeaveEvent(QWidget *widget, QWidget *managedWidget, QDragLeaveEvent *e); + bool handleDropEvent(QWidget *widget, QWidget *managedWidget, QDropEvent *e); + +private: + bool restoreDropHighlighting(); + void detectDockDrag(const QDesignerMimeData *mimeData); + + FormWindow *m_formWindow; + QAction *m_action; + + bool mainWindowSeparatorEvent(QWidget *widget, QEvent *event); + QPointer<QMainWindow> m_separator_drag_mw; + QPointer<QWidget> m_lastDropTarget; + bool m_specialDockDrag; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TOOL_WIDGETEDITOR_H diff --git a/tools/designer/src/components/formeditor/widgetselection.cpp b/tools/designer/src/components/formeditor/widgetselection.cpp new file mode 100644 index 0000000..ce103ec --- /dev/null +++ b/tools/designer/src/components/formeditor/widgetselection.cpp @@ -0,0 +1,746 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetselection.h" +#include "formwindow.h" +#include "formwindowmanager.h" + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QExtensionManager> + +// shared +#include <qdesigner_command_p.h> +#include <qdesigner_propertycommand_p.h> +#include <layout_p.h> +#include <layoutinfo_p.h> +#include <formwindowbase_p.h> +#include <grid_p.h> + +#include <QtGui/QMenu> +#include <QtGui/QWidget> +#include <QtGui/QMouseEvent> +#include <QtGui/QStylePainter> +#include <QtGui/QGridLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QStyleOptionToolButton> +#include <QtGui/QApplication> + +#include <QtCore/QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +enum { debugWidgetSelection = 0 }; + +// Return the layout the widget is in +template <class Layout> +static inline Layout *managedLayoutOf(const QDesignerFormEditorInterface *core, + QWidget *w, + const Layout * /* vs6dummy */ = 0) +{ + if (QWidget *p = w->parentWidget()) + if (QLayout *l = LayoutInfo::managedLayout(core, p)) + return qobject_cast<Layout*>(l); + return 0; +} + +// ----------- WidgetHandle +WidgetHandle::WidgetHandle(FormWindow *parent, WidgetHandle::Type t, WidgetSelection *s) : + InvisibleWidget(parent->mainContainer()), + m_widget(0), + m_type(t), + m_formWindow( parent), + m_sel(s), + m_active(true) +{ + setMouseTracking(false); + setAutoFillBackground(true); + + setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark); + setFixedSize(6, 6); + + updateCursor(); +} + +void WidgetHandle::updateCursor() +{ +#ifndef QT_NO_CURSOR + if (!m_active) { + setCursor(Qt::ArrowCursor); + return; + } + + switch (m_type) { + case LeftTop: + setCursor(Qt::SizeFDiagCursor); + break; + case Top: + setCursor(Qt::SizeVerCursor); + break; + case RightTop: + setCursor(Qt::SizeBDiagCursor); + break; + case Right: + setCursor(Qt::SizeHorCursor); + break; + case RightBottom: + setCursor(Qt::SizeFDiagCursor); + break; + case Bottom: + setCursor(Qt::SizeVerCursor); + break; + case LeftBottom: + setCursor(Qt::SizeBDiagCursor); + break; + case Left: + setCursor(Qt::SizeHorCursor); + break; + default: + Q_ASSERT(0); + } +#endif +} + +QDesignerFormEditorInterface *WidgetHandle::core() const +{ + if (m_formWindow) + return m_formWindow->core(); + + return 0; +} + +void WidgetHandle::setActive(bool a) +{ + m_active = a; + setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark); + updateCursor(); +} + +void WidgetHandle::setWidget(QWidget *w) +{ + m_widget = w; +} + +void WidgetHandle::paintEvent(QPaintEvent *) +{ + QDesignerFormWindowManagerInterface *m = m_formWindow->core()->formWindowManager(); + + QStylePainter p(this); + if (m_formWindow->currentWidget() == m_widget) { + p.setPen(m->activeFormWindow() == m_formWindow ? Qt::blue : Qt::red); + p.drawRect(0, 0, width() - 1, height() - 1); + } +} + +void WidgetHandle::mousePressEvent(QMouseEvent *e) +{ + e->accept(); + + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + if (!(m_widget && e->button() == Qt::LeftButton)) + return; + + if (!(m_active)) + return; + + QWidget *container = m_widget->parentWidget(); + + m_origPressPos = container->mapFromGlobal(e->globalPos()); + m_geom = m_origGeom = m_widget->geometry(); +} + +void WidgetHandle::mouseMoveEvent(QMouseEvent *e) +{ + if (!(m_widget && m_active && e->buttons() & Qt::LeftButton)) + return; + + e->accept(); + + QWidget *container = m_widget->parentWidget(); + + const QPoint rp = container->mapFromGlobal(e->globalPos()); + const QPoint d = rp - m_origPressPos; + + const QRect pr = container->rect(); + + qdesigner_internal::Grid grid; + if (const qdesigner_internal::FormWindowBase *fwb = qobject_cast<const qdesigner_internal::FormWindowBase*>(m_formWindow)) + grid = fwb->designerGrid(); + + switch (m_type) { + + case LeftTop: { + if (rp.x() > pr.width() - 2 * width() || rp.y() > pr.height() - 2 * height()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dx = m_widget->width() - w; + const int dy = m_widget->height() - h; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y() + dy, w, h); + } break; + + case Top: { + if (rp.y() > pr.height() - 2 * height()) + return; + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dy = m_widget->height() - h; + trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, m_widget->width(), h); + } break; + + case RightTop: { + if (rp.x() < 2 * width() || rp.y() > pr.height() - 2 * height()) + return; + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dy = m_widget->height() - h; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, w, h); + } break; + + case Right: { + if (rp.x() < 2 * width()) + return; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + tryResize(m_widget, w, m_widget->height()); + } break; + + case RightBottom: { + if (rp.x() < 2 * width() || rp.y() < 2 * height()) + return; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + tryResize(m_widget, w, h); + } break; + + case Bottom: { + if (rp.y() < 2 * height()) + return; + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + tryResize(m_widget, m_widget->width(), h); + } break; + + case LeftBottom: { + if (rp.x() > pr.width() - 2 * width() || rp.y() < 2 * height()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + int dx = m_widget->width() - w; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, h); + } break; + + case Left: { + if (rp.x() > pr.width() - 2 * width()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + const int dx = m_widget->width() - w; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, m_widget->height()); + } break; + + default: break; + + } // end switch + + m_sel->updateGeometry(); + + if (LayoutInfo::layoutType(m_formWindow->core(), m_widget) != LayoutInfo::NoLayout) + m_formWindow->updateChildSelections(m_widget); +} + +void WidgetHandle::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton || !m_active) + return; + + e->accept(); + + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + switch (WidgetSelection::widgetState(m_formWindow->core(), m_widget)) { + case WidgetSelection::UnlaidOut: + if (m_geom != m_widget->geometry()) { + SetPropertyCommand *cmd = new SetPropertyCommand(m_formWindow); + cmd->init(m_widget, QLatin1String("geometry"), m_widget->geometry()); + cmd->setOldValue(m_origGeom); + m_formWindow->commandHistory()->push(cmd); + m_formWindow->emitSelectionChanged(); + } + break; + case WidgetSelection::LaidOut: + break; + case WidgetSelection::ManagedGridLayout: + changeGridLayoutItemSpan(); + break; + case WidgetSelection::ManagedFormLayout: + changeFormLayoutItemSpan(); + break; + } +} + +// Match the left/right widget handle mouse movements to form layout span-changing operations +static inline int formLayoutLeftHandleOperation(int dx, unsigned possibleOperations) +{ + if (dx < 0) { + if (possibleOperations & ChangeFormLayoutItemRoleCommand::FieldToSpanning) + return ChangeFormLayoutItemRoleCommand::FieldToSpanning; + return 0; + } + if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToField) + return ChangeFormLayoutItemRoleCommand::SpanningToField; + return 0; +} + +static inline int formLayoutRightHandleOperation(int dx, unsigned possibleOperations) +{ + if (dx < 0) { + if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToLabel) + return ChangeFormLayoutItemRoleCommand::SpanningToLabel; + return 0; + } + if (possibleOperations & ChangeFormLayoutItemRoleCommand::LabelToSpanning) + return ChangeFormLayoutItemRoleCommand::LabelToSpanning; + return 0; +} + +// Change form layout item horizontal span +void WidgetHandle::changeFormLayoutItemSpan() +{ + QUndoCommand *cmd = 0; + // Figure out command according to the movement + const int dx = m_widget->geometry().center().x() - m_origGeom.center().x(); + if (qAbs(dx) >= QApplication::startDragDistance()) { + int operation = 0; + if (const unsigned possibleOperations = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) { + switch (m_type) { + case WidgetHandle::Left: + operation = formLayoutLeftHandleOperation(dx, possibleOperations); + break; + case WidgetHandle::Right: + operation = formLayoutRightHandleOperation(dx, possibleOperations); + break; + default: + break; + } + if (operation) { + ChangeFormLayoutItemRoleCommand *fcmd = new ChangeFormLayoutItemRoleCommand(m_formWindow); + fcmd->init(m_widget, static_cast<ChangeFormLayoutItemRoleCommand::Operation>(operation)); + cmd = fcmd; + } + } + } + if (cmd) { + m_formWindow->commandHistory()->push(cmd); + } else { + // Cancelled/Invalid. Restore the size of the widget. + if (QFormLayout *form = managedLayoutOf<QFormLayout>(m_formWindow->core(), m_widget)) { + form->invalidate(); + form->activate(); + m_formWindow->clearSelection(false); + m_formWindow->selectWidget(m_widget); + } + } +} + +void WidgetHandle::changeGridLayoutItemSpan() +{ + QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), m_widget->parentWidget()); + if (!deco) + return; + QGridLayout *grid = managedLayoutOf<QGridLayout>(m_formWindow->core(), m_widget); + if (!grid) + return; + + const QSize size = m_widget->parentWidget()->size(); + + const int index = deco->indexOf(m_widget); + const QRect info = deco->itemInfo(index); + const int top = deco->findItemAt(info.top() - 1, info.left()); + const int left = deco->findItemAt(info.top(), info.left() - 1); + const int bottom = deco->findItemAt(info.bottom() + 1, info.left()); + const int right = deco->findItemAt(info.top(), info.right() + 1); + + const QPoint pt = m_origGeom.center() - m_widget->geometry().center(); + + ChangeLayoutItemGeometry *cmd = 0; + + switch (m_type) { + default: + break; + + case WidgetHandle::Top: { + if (pt.y() < 0 && info.height() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y() + 1, info.x(), info.height() - 1, info.width()); + } else if (pt.y() > 0 && top != -1 && grid->itemAt(top)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y() - 1, info.x(), info.height() + 1, info.width()); + } + } + break; + + case WidgetHandle::Left: { + if (pt.x() < 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x() + 1, info.height(), info.width() - 1); + } else if (pt.x() > 0 && left != -1 && grid->itemAt(left)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x() - 1, info.height(), info.width() + 1); + } + } + break; + + case WidgetHandle::Right: { + if (pt.x() > 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() - 1); + } else if (pt.x() < 0 && right != -1 && grid->itemAt(right)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() + 1); + } + } + break; + + case WidgetHandle::Bottom: { + if (pt.y() > 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height() - 1, info.width()); + } else if (pt.y() < 0 && bottom != -1 && grid->itemAt(bottom)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height() + 1, info.width()); + } + } + break; + } + + if (cmd != 0) { + m_formWindow->commandHistory()->push(cmd); + } else { + grid->invalidate(); + grid->activate(); + m_formWindow->clearSelection(false); + m_formWindow->selectWidget(m_widget); + } +} + +void WidgetHandle::trySetGeometry(QWidget *w, int x, int y, int width, int height) +{ + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + int minw = w->minimumSize().width(); + minw = qMax(minw, 2 * m_formWindow->grid().x()); + + int minh = w->minimumSize().height(); + minh = qMax(minh, 2 * m_formWindow->grid().y()); + + if (qMax(minw, width) > w->maximumWidth() || + qMax(minh, height) > w->maximumHeight()) + return; + + if (width < minw && x != w->x()) + x -= minw - width; + + if (height < minh && y != w->y()) + y -= minh - height; + + w->setGeometry(x, y, qMax(minw, width), qMax(minh, height)); +} + +void WidgetHandle::tryResize(QWidget *w, int width, int height) +{ + int minw = w->minimumSize().width(); + minw = qMax(minw, 16); + + int minh = w->minimumSize().height(); + minh = qMax(minh, 16); + + w->resize(qMax(minw, width), qMax(minh, height)); +} + +// ------------------ WidgetSelection + +WidgetSelection::WidgetState WidgetSelection::widgetState(const QDesignerFormEditorInterface *core, QWidget *w) +{ + bool isManaged; + const LayoutInfo::Type lt = LayoutInfo::laidoutWidgetType(core, w, &isManaged); + if (lt == LayoutInfo::NoLayout) + return UnlaidOut; + if (!isManaged) + return LaidOut; + switch (lt) { + case LayoutInfo::Grid: + return ManagedGridLayout; + case LayoutInfo::Form: + return ManagedFormLayout; + default: + break; + } + return LaidOut; +} + +WidgetSelection::WidgetSelection(FormWindow *parent) : + m_widget(0), + m_formWindow(parent) +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) + m_handles[i] = new WidgetHandle(m_formWindow, static_cast<WidgetHandle::Type>(i), this); + hide(); +} + +void WidgetSelection::setWidget(QWidget *w) +{ + if (m_widget != 0) + m_widget->removeEventFilter(this); + + if (w == 0) { + hide(); + m_widget = 0; + return; + } + + m_widget = w; + + m_widget->installEventFilter(this); + + updateActive(); + + updateGeometry(); + show(); +} + +void WidgetSelection::updateActive() +{ + const WidgetState ws = widgetState(m_formWindow->core(), m_widget); + bool active[WidgetHandle::TypeCount]; + qFill(active, active + WidgetHandle::TypeCount, false); + // Determine active handles + switch (ws) { + case UnlaidOut: + qFill(active, active + WidgetHandle::TypeCount, true); + break; + case ManagedGridLayout: // Grid: Allow changing span + active[WidgetHandle::Left] = active[WidgetHandle::Top] = active[WidgetHandle::Right] = active[WidgetHandle::Bottom] = true; + break; + case ManagedFormLayout: // Form: Allow changing column span + if (const unsigned operation = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) { + active[WidgetHandle::Left] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToField|ChangeFormLayoutItemRoleCommand::FieldToSpanning); + active[WidgetHandle::Right] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToLabel|ChangeFormLayoutItemRoleCommand::LabelToSpanning); + } + break; + default: + break; + } + + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) + if (WidgetHandle *h = m_handles[i]) { + h->setWidget(m_widget); + h->setActive(active[i]); + } +} + +bool WidgetSelection::isUsed() const +{ + return m_widget != 0; +} + +void WidgetSelection::updateGeometry() +{ + if (!m_widget || !m_widget->parentWidget()) + return; + + QPoint p = m_widget->parentWidget()->mapToGlobal(m_widget->pos()); + p = m_formWindow->mapFromGlobal(p); + const QRect r(p, m_widget->size()); + + const int w = 6; + const int h = 6; + + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *hndl = m_handles[ i ]; + if (!hndl) + continue; + switch (i) { + case WidgetHandle::LeftTop: + hndl->move(r.x() - w / 2, r.y() - h / 2); + break; + case WidgetHandle::Top: + hndl->move(r.x() + r.width() / 2 - w / 2, r.y() - h / 2); + break; + case WidgetHandle::RightTop: + hndl->move(r.x() + r.width() - w / 2, r.y() - h / 2); + break; + case WidgetHandle::Right: + hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() / 2 - h / 2); + break; + case WidgetHandle::RightBottom: + hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::Bottom: + hndl->move(r.x() + r.width() / 2 - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::LeftBottom: + hndl->move(r.x() - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::Left: + hndl->move(r.x() - w / 2, r.y() + r.height() / 2 - h / 2); + break; + default: + break; + } + } +} + +void WidgetSelection::hide() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) + h->hide(); + } +} + +void WidgetSelection::show() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) { + h->show(); + h->raise(); + } + } +} + +void WidgetSelection::update() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) + h->update(); + } +} + +QWidget *WidgetSelection::widget() const +{ + return m_widget; +} + +QDesignerFormEditorInterface *WidgetSelection::core() const +{ + if (m_formWindow) + return m_formWindow->core(); + + return 0; +} + +bool WidgetSelection::eventFilter(QObject *object, QEvent *event) +{ + if (object != widget()) + return false; + + switch (event->type()) { + default: break; + + case QEvent::Move: + case QEvent::Resize: + updateGeometry(); + break; + case QEvent::ZOrderChange: + show(); + break; + } // end switch + + return false; +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/formeditor/widgetselection.h b/tools/designer/src/components/formeditor/widgetselection.h new file mode 100644 index 0000000..9099e89 --- /dev/null +++ b/tools/designer/src/components/formeditor/widgetselection.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETSELECTION_H +#define WIDGETSELECTION_H + +#include "formeditor_global.h" +#include <invisible_widget_p.h> + +#include <QtCore/QHash> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QMouseEvent; +class QPaintEvent; + +namespace qdesigner_internal { + +class FormWindow; +class WidgetSelection; + +class QT_FORMEDITOR_EXPORT WidgetHandle: public InvisibleWidget +{ + Q_OBJECT +public: + enum Type + { + LeftTop, + Top, + RightTop, + Right, + RightBottom, + Bottom, + LeftBottom, + Left, + + TypeCount + }; + + WidgetHandle(FormWindow *parent, Type t, WidgetSelection *s); + void setWidget(QWidget *w); + void setActive(bool a); + void updateCursor(); + + void setEnabled(bool) {} + + QDesignerFormEditorInterface *core() const; + +protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + +private: + void changeGridLayoutItemSpan(); + void changeFormLayoutItemSpan(); + void trySetGeometry(QWidget *w, int x, int y, int width, int height); + void tryResize(QWidget *w, int width, int height); + +private: + QWidget *m_widget; + const Type m_type; + QPoint m_origPressPos; + FormWindow *m_formWindow; + WidgetSelection *m_sel; + QRect m_geom, m_origGeom; + bool m_active; +}; + +class QT_FORMEDITOR_EXPORT WidgetSelection: public QObject +{ + Q_OBJECT +public: + WidgetSelection(FormWindow *parent); + + void setWidget(QWidget *w); + bool isUsed() const; + + void updateActive(); + void updateGeometry(); + void hide(); + void show(); + void update(); + + QWidget *widget() const; + + QDesignerFormEditorInterface *core() const; + + virtual bool eventFilter(QObject *object, QEvent *event); + + enum WidgetState { UnlaidOut, LaidOut, ManagedGridLayout, ManagedFormLayout }; + static WidgetState widgetState(const QDesignerFormEditorInterface *core, QWidget *w); + +private: + WidgetHandle *m_handles[WidgetHandle::TypeCount]; + QPointer<QWidget> m_widget; + FormWindow *m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETSELECTION_H diff --git a/tools/designer/src/components/lib/lib.pro b/tools/designer/src/components/lib/lib.pro new file mode 100644 index 0000000..4515b66 --- /dev/null +++ b/tools/designer/src/components/lib/lib.pro @@ -0,0 +1,74 @@ +TEMPLATE = lib +TARGET = QtDesignerComponents +contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +CONFIG += qt depend_prl no_objective_c designer +win32|mac: CONFIG += debug_and_release +QTDIR_build { + DESTDIR = $$QT_BUILD_TREE/lib + !wince*:DLLDESTDIR = $$QT_BUILD_TREE/bin +} + +# QtDesignerComponents uses +DEFINES += QT_STATICPLUGIN + +isEmpty(QT_MAJOR_VERSION) { + VERSION=4.3.0 +} else { + VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} +} + +include(../../../../../src/qt_targets.pri) +QMAKE_TARGET_PRODUCT = Designer +QMAKE_TARGET_DESCRIPTION = Graphical user interface designer. + +#load up the headers info +CONFIG += qt_install_headers +HEADERS_PRI = $$QT_BUILD_TREE/include/QtDesigner/headers.pri +include($$HEADERS_PRI)|clear(HEADERS_PRI) + +#mac frameworks +mac:!static:contains(QT_CONFIG, qt_framework) { + QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET + CONFIG += lib_bundle qt_no_framework_direct_includes qt_framework + CONFIG(debug, debug|release):!build_pass:CONFIG += build_all +} + +SOURCES += qdesigner_components.cpp + +!contains(CONFIG, static) { + DEFINES += QDESIGNER_COMPONENTS_LIBRARY + CONFIG += dll + LIBS += -lQtDesigner +} else { + DEFINES += QT_DESIGNER_STATIC +} + +INCLUDEPATH += . .. \ + $$QT_SOURCE_TREE/tools/designer/src/lib/components \ + $$QT_SOURCE_TREE/tools/designer/src/lib/sdk \ + $$QT_SOURCE_TREE/tools/designer/src/lib/extension \ + $$QT_SOURCE_TREE/tools/designer/src/lib/uilib \ + $$QT_SOURCE_TREE/tools/designer/src/lib/shared + +include(../propertyeditor/propertyeditor.pri) +include(../objectinspector/objectinspector.pri) +include(../signalsloteditor/signalsloteditor.pri) +include(../formeditor/formeditor.pri) +include(../widgetbox/widgetbox.pri) +include(../buddyeditor/buddyeditor.pri) +include(../taskmenu/taskmenu.pri) +include(../tabordereditor/tabordereditor.pri) + +PRECOMPILED_HEADER= lib_pch.h + +include(../../sharedcomponents.pri) +include(../component.pri) + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtDesigner QtGui QtScript QtXml + +target.path=$$[QT_INSTALL_LIBS] +INSTALLS += target +win32 { + dlltarget.path=$$[QT_INSTALL_BINS] + INSTALLS += dlltarget +} diff --git a/tools/designer/src/components/lib/lib_pch.h b/tools/designer/src/components/lib/lib_pch.h new file mode 100644 index 0000000..9f47b25 --- /dev/null +++ b/tools/designer/src/components/lib/lib_pch.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDesigner/QtDesigner> +#include <QtDesigner/QExtensionManager> diff --git a/tools/designer/src/components/lib/qdesigner_components.cpp b/tools/designer/src/components/lib/qdesigner_components.cpp new file mode 100644 index 0000000..42752d9 --- /dev/null +++ b/tools/designer/src/components/lib/qdesigner_components.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDesigner/QDesignerComponents> + +#include <actioneditor_p.h> +#include <widgetdatabase_p.h> +#include <widgetfactory_p.h> + +#include <formeditor/formeditor.h> +#include <widgetbox/widgetbox.h> +#include <propertyeditor/propertyeditor.h> +#include <objectinspector/objectinspector.h> +#include <taskmenu/taskmenu_component.h> +#include "qtresourceview_p.h" +#include <qdesigner_integration_p.h> +#include <signalsloteditor/signalsloteditorwindow.h> + +#include <buddyeditor/buddyeditor_plugin.h> +#include <signalsloteditor/signalsloteditor_plugin.h> +#include <tabordereditor/tabordereditor_plugin.h> + +#include <QtDesigner/QDesignerLanguageExtension> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerResourceBrowserInterface> + +#include <QtCore/qplugin.h> +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> + +// ### keep it in sync with Q_IMPORT_PLUGIN in qplugin.h +#define DECLARE_PLUGIN_INSTANCE(PLUGIN) \ + extern QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGIN(); \ + class Static##PLUGIN##PluginInstance { public: \ + Static##PLUGIN##PluginInstance() { \ + QT_PREPEND_NAMESPACE(qRegisterStaticPluginInstanceFunction) \ + (&qt_plugin_instance_##PLUGIN); \ + } \ + }; + +#define INIT_PLUGIN_INSTANCE(PLUGIN) \ + do { \ + Static##PLUGIN##PluginInstance instance; \ + Q_UNUSED(instance); \ + } while (0) + +DECLARE_PLUGIN_INSTANCE(SignalSlotEditorPlugin) +DECLARE_PLUGIN_INSTANCE(BuddyEditorPlugin) +DECLARE_PLUGIN_INSTANCE(TabOrderEditorPlugin) + +static void initResources() +{ + // Q_INIT_RESOURCE only usable in functions in global namespace + Q_INIT_RESOURCE(formeditor); + Q_INIT_RESOURCE(widgetbox); + Q_INIT_RESOURCE(propertyeditor); +} + + +static void initInstances() +{ + static bool plugins_initialized = false; + + if (!plugins_initialized) { + INIT_PLUGIN_INSTANCE(SignalSlotEditorPlugin); + INIT_PLUGIN_INSTANCE(BuddyEditorPlugin); + INIT_PLUGIN_INSTANCE(TabOrderEditorPlugin); + plugins_initialized = true; + } +} + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerComponents + \brief The QDesignerComponents class provides a central resource for the various components + used in the \QD user interface. + \inmodule QtDesigner + \internal + + The QDesignerComponents class is a factory for each of the standard components present + in the \QD user interface. It is mostly useful for developers who want to implement + a standalone form editing environment using \QD's components, or who need to integrate + \QD's components into an existing integrated development environment (IDE). + + \sa QDesignerFormEditorInterface, QDesignerObjectInspectorInterface, + QDesignerPropertyEditorInterface, QDesignerWidgetBoxInterface +*/ + +/*! + Initializes the resources used by the components.*/ +void QDesignerComponents::initializeResources() +{ + initResources(); +} + +/*! + Initializes the plugins used by the components.*/ +void QDesignerComponents::initializePlugins(QDesignerFormEditorInterface *core) +{ + qdesigner_internal::QDesignerIntegration::initializePlugins(core); +} + +/*! + Constructs a form editor interface with the given \a parent.*/ +QDesignerFormEditorInterface *QDesignerComponents::createFormEditor(QObject *parent) +{ + initInstances(); + return new qdesigner_internal::FormEditor(parent); +} + +/*! + Returns a new task menu with the given \a parent for the \a core interface.*/ +QObject *QDesignerComponents::createTaskMenu(QDesignerFormEditorInterface *core, QObject *parent) +{ + return new qdesigner_internal::TaskMenuComponent(core, parent); +} + +static inline int qtMajorVersion(int qtVersion) { return qtVersion >> 16; } +static inline int qtMinorVersion(int qtVersion) { return (qtVersion >> 8) & 0xFF; } +static inline void setMinorVersion(int minorVersion, int *qtVersion) +{ + *qtVersion &= ~0xFF00; + *qtVersion |= minorVersion << 8; +} + +// Build the version-dependent name of the user widget box file, '$HOME.designer/widgetbox4.4.xml' +static inline QString widgetBoxFileName(int qtVersion, const QDesignerLanguageExtension *lang = 0) +{ + QString rc; { + const QChar dot = QLatin1Char('.'); + QTextStream str(&rc); + str << QDir::homePath() << QDir::separator() << QLatin1String(".designer") << QDir::separator() + << QLatin1String("widgetbox"); + // The naming convention using the version was introduced with 4.4 + const int major = qtMajorVersion(qtVersion); + const int minor = qtMinorVersion(qtVersion); + if (major >= 4 && minor >= 4) + str << major << dot << minor; + if (lang) + str << dot << lang->uiExtension(); + str << QLatin1String(".xml"); + } + return rc; +} + +/*! + Returns a new widget box interface with the given \a parent for the \a core interface.*/ +QDesignerWidgetBoxInterface *QDesignerComponents::createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent) +{ + qdesigner_internal::WidgetBox *widgetBox = new qdesigner_internal::WidgetBox(core, parent); + + const QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core); + + do { + if (lang) { + const QString languageWidgetBox = lang->widgetBoxContents(); + if (!languageWidgetBox.isEmpty()) { + widgetBox->loadContents(lang->widgetBoxContents()); + break; + } + } + + widgetBox->setFileName(QLatin1String(":/trolltech/widgetbox/widgetbox.xml")); + widgetBox->load(); + } while (false); + + const QString userWidgetBoxFile = widgetBoxFileName(QT_VERSION, lang); + + widgetBox->setFileName(userWidgetBoxFile); + if (!QFileInfo(userWidgetBoxFile).exists()) { + // check previous version, that is, are we running the new version for the first time + // If so, try to copy the old widget box file + if (const int minv = qtMinorVersion(QT_VERSION)) { + int oldVersion = QT_VERSION; + setMinorVersion(minv - 1, &oldVersion); + const QString oldWidgetBoxFile = widgetBoxFileName(oldVersion, lang); + if (QFileInfo(oldWidgetBoxFile).exists()) + QFile::copy(oldWidgetBoxFile, userWidgetBoxFile); + } + } + widgetBox->load(); + + return widgetBox; +} + +/*! + Returns a new property editor interface with the given \a parent for the \a core interface.*/ +QDesignerPropertyEditorInterface *QDesignerComponents::createPropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::PropertyEditor(core, parent); +} + +/*! + Returns a new object inspector interface with the given \a parent for the \a core interface.*/ +QDesignerObjectInspectorInterface *QDesignerComponents::createObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::ObjectInspector(core, parent); +} + +/*! + Returns a new action editor interface with the given \a parent for the \a core interface.*/ +QDesignerActionEditorInterface *QDesignerComponents::createActionEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::ActionEditor(core, parent); +} + +/*! + Returns a new resource editor with the given \a parent for the \a core interface.*/ +QWidget *QDesignerComponents::createResourceEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) { + QWidget *w = lang->createResourceBrowser(parent); + if (w) + return w; + } + QtResourceView *resourceView = new QtResourceView(core, parent); + resourceView->setResourceModel(core->resourceModel()); + resourceView->setSettingsKey(QLatin1String("ResourceBrowser")); + qdesigner_internal::QDesignerIntegration *designerIntegration = qobject_cast<qdesigner_internal::QDesignerIntegration *>(core->integration()); + // Note for integrators: make sure you call createResourceEditor() after you instantiated your subclass of designer integration + // (designer doesn't do that since by default editing resources is enabled) + if (designerIntegration) + resourceView->setResourceEditingEnabled(designerIntegration->isResourceEditingEnabled()); + return resourceView; +} + +/*! + Returns a new signal-slot editor with the given \a parent for the \a core interface.*/ +QWidget *QDesignerComponents::createSignalSlotEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::SignalSlotEditorWindow(core, parent); +} + +QT_END_NAMESPACE + diff --git a/tools/designer/src/components/objectinspector/objectinspector.cpp b/tools/designer/src/components/objectinspector/objectinspector.cpp new file mode 100644 index 0000000..4e515be --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspector.cpp @@ -0,0 +1,839 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ObjectInspector +*/ + +#include "objectinspector.h" +#include "objectinspectormodel_p.h" +#include "formwindow.h" + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerTaskMenuExtension> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QDesignerPropertyEditorInterface> + +// shared +#include <qdesigner_utils_p.h> +#include <formwindowbase_p.h> +#include <itemviewfindwidget.h> +#include <qdesigner_dnditem_p.h> +#include <textpropertyeditor_p.h> +#include <qdesigner_command_p.h> +#include <grid_p.h> + +// Qt +#include <QtGui/QApplication> +#include <QtGui/QHeaderView> +#include <QtGui/QScrollBar> +#include <QtGui/QPainter> +#include <QtGui/QVBoxLayout> +#include <QtGui/QItemSelectionModel> +#include <QtGui/QMenu> +#include <QtGui/QTreeView> +#include <QtGui/QItemDelegate> +#include <QtGui/qevent.h> + +#include <QtCore/QVector> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace { + // Selections: Basically, ObjectInspector has to ensure a consistent + // selection, that is, either form-managed widgets (represented + // by the cursor interface selection), or unmanaged widgets/objects, + // for example actions, container pages, menu bars, tool bars + // and the like. The selection state of the latter is managed only in the object inspector. + // As soon as a managed widget is selected, unmanaged objects + // have to be unselected + // Normally, an empty selection is not allowed, the main container + // should be selected in this case (applyCursorSelection()). + // An exception is when clearSelection is called directly for example + // by the action editor that puts an unassociated action into the property + // editor. A hack exists to avoid the update in this case. + + enum SelectionType { + NoSelection, + // A QObject that has a meta database entry + QObjectSelection, + // Unmanaged widget, menu bar or the like + UnmanagedWidgetSelection, + // A widget managed by the form window cursor + ManagedWidgetSelection }; + + typedef QVector<QObject*> QObjectVector; +} + +static inline SelectionType selectionType(const QDesignerFormWindowInterface *fw, QObject *o) +{ + if (!o->isWidgetType()) + return fw->core()->metaDataBase()->item(o) ? QObjectSelection : NoSelection; + return fw->isManaged(qobject_cast<QWidget *>(o)) ? ManagedWidgetSelection : UnmanagedWidgetSelection; +} + +// Return an offset for dropping (when dropping widgets on the object +// inspector, we fake a position on the form based on the widget dropped on). +// Position the dropped widget with form grid offset to avoid overlapping unless we +// drop on a layout. Position doesn't matter in the layout case +// and this enables us to drop on a squeezed layout widget of size zero + +static inline QPoint dropPointOffset(const qdesigner_internal::FormWindowBase *fw, const QWidget *dropTarget) +{ + if (!dropTarget || dropTarget->layout()) + return QPoint(0, 0); + return QPoint(fw->designerGrid().deltaX(), fw->designerGrid().deltaY()); +} + +namespace qdesigner_internal { +// Delegate with object name validator for the object name column +class ObjectInspectorDelegate : public QItemDelegate { +public: + explicit ObjectInspectorDelegate(QObject *parent = 0); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +ObjectInspectorDelegate::ObjectInspectorDelegate(QObject *parent) : + QItemDelegate(parent) +{ +} + +QWidget *ObjectInspectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index) const +{ + if (index.column() != ObjectInspectorModel::ObjectNameColumn) + return QItemDelegate::createEditor(parent, option, index); + // Object name editor + const bool isMainContainer = !index.parent().isValid(); + return new TextPropertyEditor(parent, TextPropertyEditor::EmbeddingTreeView, + isMainContainer ? ValidationObjectNameScope : ValidationObjectName); +} + +// ------------ ObjectInspectorTreeView: +// - Makes the Space key start editing +// - Suppresses a range selection by dragging or Shift-up/down, which does not really work due +// to the need to maintain a consistent selection. + +class ObjectInspectorTreeView : public QTreeView { +public: + ObjectInspectorTreeView(QWidget *parent = 0) : QTreeView(parent) {} + +protected: + virtual void mouseMoveEvent (QMouseEvent * event); + virtual void keyPressEvent(QKeyEvent *event); + +}; + +void ObjectInspectorTreeView::mouseMoveEvent(QMouseEvent *event) +{ + event->ignore(); // suppress a range selection by dragging +} + +void ObjectInspectorTreeView::keyPressEvent(QKeyEvent *event) +{ + bool handled = false; + switch (event->key()) { + case Qt::Key_Up: + case Qt::Key_Down: // suppress shift-up/down range selection + if (event->modifiers() & Qt::ShiftModifier) { + event->ignore(); + handled = true; + } + break; + case Qt::Key_Space: { // Space pressed: Start editing + const QModelIndex index = currentIndex(); + if (index.isValid() && index.column() == 0 && !model()->hasChildren(index) && model()->flags(index) & Qt::ItemIsEditable) { + event->accept(); + handled = true; + edit(index); + } + } + break; + default: + break; + } + if (!handled) + QTreeView::keyPressEvent(event); +} + +// ------------ ObjectInspectorPrivate + +class ObjectInspector::ObjectInspectorPrivate { +public: + ObjectInspectorPrivate(QDesignerFormEditorInterface *core); + ~ObjectInspectorPrivate(); + + QTreeView *treeView() const { return m_treeView; } + ItemViewFindWidget *findWidget() const { return m_findWidget; } + QDesignerFormEditorInterface *core() const { return m_core; } + const QPointer<FormWindowBase> &formWindow() const { return m_formWindow; } + + void clear(); + void setFormWindow(QDesignerFormWindowInterface *fwi); + + QWidget *managedWidgetAt(const QPoint &global_mouse_pos); + + void restoreDropHighlighting(); + void handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter); + void dropEvent (QDropEvent * event); + + void clearSelection(); + bool selectObject(QObject *o); + void slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected); + void getSelection(Selection &s) const; + + void slotHeaderDoubleClicked(int column) { m_treeView->resizeColumnToContents(column); } + void slotPopupContextMenu(QWidget *parent, const QPoint &pos); + +private: + void setFormWindowBlocked(QDesignerFormWindowInterface *fwi); + void applyCursorSelection(); + void synchronizeSelection(const QItemSelection & selected, const QItemSelection &deselected); + bool checkManagedWidgetSelection(const QModelIndexList &selection); + void showContainersCurrentPage(QWidget *widget); + + enum SelectionFlags { AddToSelection = 1, MakeCurrent = 2}; + void selectIndexRange(const QModelIndexList &indexes, unsigned flags); + + QDesignerFormEditorInterface *m_core; + QTreeView *m_treeView; + ObjectInspectorModel *m_model; + ItemViewFindWidget *m_findWidget; + QPointer<FormWindowBase> m_formWindow; + QPointer<QWidget> m_formFakeDropTarget; + bool m_withinClearSelection; +}; + +ObjectInspector::ObjectInspectorPrivate::ObjectInspectorPrivate(QDesignerFormEditorInterface *core) : + m_core(core), + m_treeView(new ObjectInspectorTreeView), + m_model(new ObjectInspectorModel(m_treeView)), + m_findWidget(new ItemViewFindWidget( + ItemViewFindWidget::NarrowLayout | ItemViewFindWidget::NoWholeWords)), + m_withinClearSelection(false) +{ + m_treeView->setModel(m_model); + m_treeView->setItemDelegate(new ObjectInspectorDelegate); + m_treeView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_treeView->header()->setResizeMode(1, QHeaderView::Stretch); + m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_treeView->setAlternatingRowColors(true); + m_treeView->setTextElideMode (Qt::ElideMiddle); + + m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); +} + +ObjectInspector::ObjectInspectorPrivate::~ObjectInspectorPrivate() +{ + delete m_treeView->itemDelegate(); +} + +void ObjectInspector::ObjectInspectorPrivate::clearSelection() +{ + m_withinClearSelection = true; + m_treeView->clearSelection(); + m_withinClearSelection = false; +} + +QWidget *ObjectInspector::ObjectInspectorPrivate::managedWidgetAt(const QPoint &global_mouse_pos) +{ + if (!m_formWindow) + return 0; + + const QPoint pos = m_treeView->viewport()->mapFromGlobal(global_mouse_pos); + QObject *o = m_model->objectAt(m_treeView->indexAt(pos)); + + if (!o || !o->isWidgetType()) + return 0; + + QWidget *rc = qobject_cast<QWidget *>(o); + if (!m_formWindow->isManaged(rc)) + return 0; + return rc; +} + +void ObjectInspector::ObjectInspectorPrivate::showContainersCurrentPage(QWidget *widget) +{ + if (!widget) + return; + + FormWindow *fw = FormWindow::findFormWindow(widget); + if (!fw) + return; + + QWidget *w = widget->parentWidget(); + bool macroStarted = false; + // Find a multipage container (tab widgets, etc.) in the hierarchy and set the right page. + while (w != 0) { + if (fw->isManaged(w)) { // Rule out unmanaged internal scroll areas, for example, on QToolBoxes. + if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), w)) { + const int count = c->count(); + if (count > 1 && !c->widget(c->currentIndex())->isAncestorOf(widget)) { + for (int i = 0; i < count; i++) + if (c->widget(i)->isAncestorOf(widget)) { + if (macroStarted == false) { + macroStarted = true; + fw->beginCommand(tr("Change Current Page")); + } + ChangeCurrentPageCommand *cmd = new ChangeCurrentPageCommand(fw); + cmd->init(w, i); + fw->commandHistory()->push(cmd); + break; + } + } + } + } + w = w->parentWidget(); + } + if (macroStarted == true) + fw->endCommand(); +} + +void ObjectInspector::ObjectInspectorPrivate::restoreDropHighlighting() +{ + if (m_formFakeDropTarget) { + if (m_formWindow) { + m_formWindow->highlightWidget(m_formFakeDropTarget, QPoint(5, 5), FormWindow::Restore); + } + m_formFakeDropTarget = 0; + } +} + +void ObjectInspector::ObjectInspectorPrivate::handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter) +{ + if (!m_formWindow) { + event->ignore(); + return; + } + + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(event->mimeData()); + if (!mimeData) { + event->ignore(); + return; + } + + QWidget *dropTarget = 0; + QPoint fakeDropTargetOffset = QPoint(0, 0); + if (QWidget *managedWidget = managedWidgetAt(objectInspectorWidget->mapToGlobal(event->pos()))) { + fakeDropTargetOffset = dropPointOffset(m_formWindow, managedWidget); + // pretend we drag over the managed widget on the form + const QPoint fakeFormPos = m_formWindow->mapFromGlobal(managedWidget->mapToGlobal(fakeDropTargetOffset)); + const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; + dropTarget = m_formWindow->widgetUnderMouse(fakeFormPos, wum); + } + + if (m_formFakeDropTarget && dropTarget != m_formFakeDropTarget) + m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Restore); + + m_formFakeDropTarget = dropTarget; + if (m_formFakeDropTarget) + m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Highlight); + + // Do not refuse drag enter even if the area is not droppable + if (isDragEnter || m_formFakeDropTarget) + mimeData->acceptEvent(event); + else + event->ignore(); +} +void ObjectInspector::ObjectInspectorPrivate::dropEvent (QDropEvent * event) +{ + if (!m_formWindow || !m_formFakeDropTarget) { + event->ignore(); + return; + } + + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(event->mimeData()); + if (!mimeData) { + event->ignore(); + return; + } + const QPoint fakeGlobalDropFormPos = m_formFakeDropTarget->mapToGlobal(dropPointOffset(m_formWindow , m_formFakeDropTarget)); + mimeData->moveDecoration(fakeGlobalDropFormPos + mimeData->hotSpot()); + if (!m_formWindow->dropWidgets(mimeData->items(), m_formFakeDropTarget, fakeGlobalDropFormPos)) { + event->ignore(); + return; + } + mimeData->acceptEvent(event); +} + +bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) +{ + if (!m_core->metaDataBase()->item(o)) + return false; + + typedef QSet<QModelIndex> ModelIndexSet; + + const QModelIndexList objectIndexes = m_model->indexesOf(o); + if (objectIndexes.empty()) + return false; + + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const ModelIndexSet currentSelectedItems = selectionModel->selectedRows(0).toSet(); + + // Change in selection? + if (!currentSelectedItems.empty() && currentSelectedItems == objectIndexes.toSet()) + return true; + + // do select and update + selectIndexRange(objectIndexes, MakeCurrent); + return true; +} + +void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndexList &indexes, unsigned flags) +{ + if (indexes.empty()) + return; + + QItemSelectionModel::SelectionFlags selectFlags = QItemSelectionModel::Select|QItemSelectionModel::Rows; + if (!(flags & AddToSelection)) + selectFlags |= QItemSelectionModel::Clear; + if (flags & MakeCurrent) + selectFlags |= QItemSelectionModel::Current; + + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const QModelIndexList::const_iterator cend = indexes.constEnd(); + for (QModelIndexList::const_iterator it = indexes.constBegin(); it != cend; ++it) + if (it->column() == 0) { + selectionModel->select(*it, selectFlags); + selectFlags &= ~(QItemSelectionModel::Clear|QItemSelectionModel::Current); + } + if (flags & MakeCurrent) + m_treeView->scrollTo(indexes.front(), QAbstractItemView::EnsureVisible); +} + +void ObjectInspector::ObjectInspectorPrivate::clear() +{ + m_formFakeDropTarget = 0; + m_formWindow = 0; +} + +// Form window cursor is in state 'main container only' +static inline bool mainContainerIsCurrent(const QDesignerFormWindowInterface *fw) +{ + const QDesignerFormWindowCursorInterface *cursor = fw->cursor(); + if (cursor->selectedWidgetCount() > 1) + return false; + const QWidget *current = cursor->current(); + return current == fw || current == fw->mainContainer(); +} + +void ObjectInspector::ObjectInspectorPrivate::setFormWindow(QDesignerFormWindowInterface *fwi) +{ + const bool blocked = m_treeView->selectionModel()->blockSignals(true); + { + UpdateBlocker ub(m_treeView); + setFormWindowBlocked(fwi); + } + + m_treeView->update(); + m_treeView->selectionModel()->blockSignals(blocked); +} + +void ObjectInspector::ObjectInspectorPrivate::setFormWindowBlocked(QDesignerFormWindowInterface *fwi) +{ + FormWindowBase *fw = qobject_cast<FormWindowBase *>(fwi); + const bool formWindowChanged = m_formWindow != fw; + + m_formWindow = fw; + + const int oldWidth = m_treeView->columnWidth(0); + const int xoffset = m_treeView->horizontalScrollBar()->value(); + const int yoffset = m_treeView->verticalScrollBar()->value(); + + if (formWindowChanged) + m_formFakeDropTarget = 0; + + switch (m_model->update(m_formWindow)) { + case ObjectInspectorModel::NoForm: + clear(); + return; + case ObjectInspectorModel::Rebuilt: // Complete rebuild: Just apply cursor selection + applyCursorSelection(); + m_treeView->expandAll(); + if (formWindowChanged) { + m_treeView->resizeColumnToContents(0); + } else { + m_treeView->setColumnWidth(0, oldWidth); + m_treeView->horizontalScrollBar()->setValue(xoffset); + m_treeView->verticalScrollBar()->setValue(yoffset); + } + break; + case ObjectInspectorModel::Updated: { + // Same structure (property changed or click on the form) + // We maintain a selection of unmanaged objects + // only if the cursor is in state "mainContainer() == current". + // and we have a non-managed selection. + // Else we take over the cursor selection. + bool applySelection = !mainContainerIsCurrent(m_formWindow); + if (!applySelection) { + const QModelIndexList currentIndexes = m_treeView->selectionModel()->selectedRows(0); + if (currentIndexes.empty()) { + applySelection = true; + } else { + applySelection = selectionType(m_formWindow, m_model->objectAt(currentIndexes.front())) == ManagedWidgetSelection; + } + } + if (applySelection) + applyCursorSelection(); + } + break; + } +} + +// Apply selection of form window cursor to object inspector, set current +void ObjectInspector::ObjectInspectorPrivate::applyCursorSelection() +{ + const QDesignerFormWindowCursorInterface *cursor = m_formWindow->cursor(); + const int count = cursor->selectedWidgetCount(); + if (!count) + return; + + // Set the current widget first which also clears the selection + QWidget *currentWidget = cursor->current(); + if (currentWidget) + selectIndexRange(m_model->indexesOf(currentWidget), MakeCurrent); + else + m_treeView->selectionModel()->clearSelection(); + + for (int i = 0;i < count; i++) { + QWidget *widget = cursor->selectedWidget(i); + if (widget != currentWidget) + selectIndexRange(m_model->indexesOf(widget), AddToSelection); + } +} + +// Synchronize managed widget in the form (select in cursor). Block updates +static int selectInCursor(FormWindowBase *fw, const QObjectVector &objects, bool value) +{ + int rc = 0; + const bool blocked = fw->blockSelectionChanged(true); + const QObjectVector::const_iterator ocend = objects.constEnd(); + for (QObjectVector::const_iterator it = objects.constBegin(); it != ocend; ++it) + if (selectionType(fw, *it) == ManagedWidgetSelection) { + fw->selectWidget(static_cast<QWidget *>(*it), value); + rc++; + } + fw->blockSelectionChanged(blocked); + return rc; +} + +void ObjectInspector::ObjectInspectorPrivate::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) +{ + if (m_formWindow) { + synchronizeSelection(selected, deselected); + QMetaObject::invokeMethod(m_core->formWindowManager(), "slotUpdateActions"); + } +} + +// Convert indexes to object vectors taking into account that +// some index lists are multicolumn ranges +static inline QObjectVector indexesToObjects(const ObjectInspectorModel *model, const QModelIndexList &indexes) +{ + if (indexes.empty()) + return QObjectVector(); + QObjectVector rc; + rc.reserve(indexes.size()); + const QModelIndexList::const_iterator icend = indexes.constEnd(); + for (QModelIndexList::const_iterator it = indexes.constBegin(); it != icend; ++it) + if (it->column() == 0) + rc.push_back(model->objectAt(*it)); + return rc; +} + +// Check if any managed widgets are selected. If so, iterate over +// selection and deselect all unmanaged objects +bool ObjectInspector::ObjectInspectorPrivate::checkManagedWidgetSelection(const QModelIndexList &rowSelection) +{ + bool isManagedWidgetSelection = false; + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const QModelIndexList::const_iterator cscend = rowSelection.constEnd(); + for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { + QObject *object = m_model->objectAt(*it); + if (selectionType(m_formWindow, object) == ManagedWidgetSelection) { + isManagedWidgetSelection = true; + break; + } + } + + if (!isManagedWidgetSelection) + return false; + // Need to unselect unmanaged ones + const bool blocked = selectionModel->blockSignals(true); + for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { + QObject *object = m_model->objectAt(*it); + if (selectionType(m_formWindow, object) != ManagedWidgetSelection) + selectionModel->select(*it, QItemSelectionModel::Deselect|QItemSelectionModel::Rows); + } + selectionModel->blockSignals(blocked); + return true; +} + +void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSelection & selectedSelection, const QItemSelection &deselectedSelection) +{ + // Synchronize form window cursor. + const QObjectVector deselected = indexesToObjects(m_model, deselectedSelection.indexes()); + const QObjectVector newlySelected = indexesToObjects(m_model, selectedSelection.indexes()); + + const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); + + int deselectedManagedWidgetCount = 0; + if (!deselected.empty()) + deselectedManagedWidgetCount = selectInCursor(m_formWindow, deselected, false); + + if (newlySelected.empty()) { // Nothing selected + if (currentSelectedIndexes.empty()) // Do not allow a null-selection, reset to main container + m_formWindow->clearSelection(!m_withinClearSelection); + return; + } + + const int selectManagedWidgetCount = selectInCursor(m_formWindow, newlySelected, true); + // Check consistency: Make sure either managed widgets or unmanaged objects are selected. + // No newly-selected managed widgets: Unless there are ones in the (old) current selection, + // select the unmanaged object + if (selectManagedWidgetCount == 0) { + if (checkManagedWidgetSelection(currentSelectedIndexes)) { + // Managed selection exists, refuse and update if necessary + if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) + m_formWindow->emitSelectionChanged(); + return; + } + // And now for the unmanaged selection + m_formWindow->clearSelection(false); + QObject *unmanagedObject = newlySelected.front(); + m_core->propertyEditor()->setObject(unmanagedObject); + m_core->propertyEditor()->setEnabled(true); + // open container page if it is a single widget + if (newlySelected.size() == 1 && unmanagedObject->isWidgetType()) + showContainersCurrentPage(static_cast<QWidget*>(unmanagedObject)); + return; + } + // Open container page if it is a single widget + if (newlySelected.size() == 1) { + QObject *object = newlySelected.back(); + if (object->isWidgetType()) + showContainersCurrentPage(static_cast<QWidget*>(object)); + } + + // A managed widget was newly selected. Make sure there are no unmanaged objects + // in the whole unless just single selection + if (currentSelectedIndexes.size() > selectManagedWidgetCount) + checkManagedWidgetSelection(currentSelectedIndexes); + // Update form + if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) + m_formWindow->emitSelectionChanged(); +} + + +void ObjectInspector::ObjectInspectorPrivate::getSelection(Selection &s) const +{ + s.clear(); + + if (!m_formWindow) + return; + + const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); + if (currentSelectedIndexes.empty()) + return; + + // sort objects + foreach (const QModelIndex &index, currentSelectedIndexes) + if (QObject *object = m_model->objectAt(index)) + switch (selectionType(m_formWindow, object)) { + case NoSelection: + break; + case QObjectSelection: + // It is actually possible to select an action twice if it is in a menu bar + // and in a tool bar. + if (!s.objects.contains(object)) + s.objects.push_back(object); + break; + case UnmanagedWidgetSelection: + s.unmanaged.push_back(qobject_cast<QWidget *>(object)); + break; + case ManagedWidgetSelection: + s.managed.push_back(qobject_cast<QWidget *>(object)); + break; + } +} + +// Utility to create a task menu +static inline QMenu *createTaskMenu(QObject *object, QDesignerFormWindowInterface *fw) +{ + // 1) Objects + if (!object->isWidgetType()) + return FormWindowBase::createExtensionTaskMenu(fw, object, false); + // 2) Unmanaged widgets + QWidget *w = static_cast<QWidget *>(object); + if (!fw->isManaged(w)) + return FormWindowBase::createExtensionTaskMenu(fw, w, false); + // 3) Mananaged widgets + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase*>(fw)) + return fwb->initializePopupMenu(w); + return 0; +} + +void ObjectInspector::ObjectInspectorPrivate::slotPopupContextMenu(QWidget * /*parent*/, const QPoint &pos) +{ + if (m_formWindow == 0 || m_formWindow->currentTool() != 0) + return; + + const QModelIndex index = m_treeView->indexAt (pos); + if (QObject *object = m_model->objectAt(m_treeView->indexAt(pos))) + if (QMenu *menu = createTaskMenu(object, m_formWindow)) { + menu->exec(m_treeView->viewport()->mapToGlobal(pos)); + delete menu; + } +} + +// ------------ ObjectInspector +ObjectInspector::ObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent) : + QDesignerObjectInspector(parent), + m_impl(new ObjectInspectorPrivate(core)) +{ + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setMargin(0); + + QTreeView *treeView = m_impl->treeView(); + vbox->addWidget(treeView); + + connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotPopupContextMenu(QPoint))); + + connect(treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + + connect(treeView->header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(slotHeaderDoubleClicked(int))); + setAcceptDrops(true); + + ItemViewFindWidget *findWidget = m_impl->findWidget(); + vbox->addWidget(findWidget); + + findWidget->setItemView(treeView); + QAction *findAction = new QAction( + ItemViewFindWidget::findIconSet(), + tr("&Find in Text..."), + this); + findAction->setShortcut(QKeySequence::Find); + findAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + addAction(findAction); + connect(findAction, SIGNAL(triggered(bool)), findWidget, SLOT(activate())); +} + +ObjectInspector::~ObjectInspector() +{ + delete m_impl; +} + +QDesignerFormEditorInterface *ObjectInspector::core() const +{ + return m_impl->core(); +} + +void ObjectInspector::slotPopupContextMenu(const QPoint &pos) +{ + m_impl->slotPopupContextMenu(this, pos); +} + +void ObjectInspector::setFormWindow(QDesignerFormWindowInterface *fwi) +{ + m_impl->setFormWindow(fwi); +} + +void ObjectInspector::slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected) +{ + m_impl->slotSelectionChanged(selected, deselected); +} + +void ObjectInspector::getSelection(Selection &s) const +{ + m_impl->getSelection(s); +} + +bool ObjectInspector::selectObject(QObject *o) +{ + return m_impl->selectObject(o); +} + +void ObjectInspector::clearSelection() +{ + m_impl->clearSelection(); +} + +void ObjectInspector::slotHeaderDoubleClicked(int column) +{ + m_impl->slotHeaderDoubleClicked(column); +} + +void ObjectInspector::mainContainerChanged() +{ + // Invalidate references to objects kept in items + if (sender() == m_impl->formWindow()) + setFormWindow(0); +} + +void ObjectInspector::dragEnterEvent (QDragEnterEvent * event) +{ + m_impl->handleDragEnterMoveEvent(this, event, true); +} + +void ObjectInspector::dragMoveEvent(QDragMoveEvent * event) +{ + m_impl->handleDragEnterMoveEvent(this, event, false); +} + +void ObjectInspector::dragLeaveEvent(QDragLeaveEvent * /* event*/) +{ + m_impl->restoreDropHighlighting(); +} + +void ObjectInspector::dropEvent (QDropEvent * event) +{ + m_impl->dropEvent(event); + +QT_END_NAMESPACE +} +} diff --git a/tools/designer/src/components/objectinspector/objectinspector.h b/tools/designer/src/components/objectinspector/objectinspector.h new file mode 100644 index 0000000..6b3b3d0 --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspector.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECTINSPECTOR_H +#define OBJECTINSPECTOR_H + +#include "objectinspector_global.h" +#include "qdesigner_objectinspector_p.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class QItemSelection; + +namespace qdesigner_internal { + +class QT_OBJECTINSPECTOR_EXPORT ObjectInspector: public QDesignerObjectInspector +{ + Q_OBJECT +public: + explicit ObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent = 0); + virtual ~ObjectInspector(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual void getSelection(Selection &s) const; + virtual bool selectObject(QObject *o); + virtual void clearSelection(); + + void setFormWindow(QDesignerFormWindowInterface *formWindow); + +public slots: + virtual void mainContainerChanged(); + +private slots: + void slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + void slotPopupContextMenu(const QPoint &pos); + void slotHeaderDoubleClicked(int column); + +protected: + virtual void dragEnterEvent (QDragEnterEvent * event); + virtual void dragMoveEvent(QDragMoveEvent * event); + virtual void dragLeaveEvent(QDragLeaveEvent * event); + virtual void dropEvent (QDropEvent * event); + +private: + class ObjectInspectorPrivate; + ObjectInspectorPrivate *m_impl; +}; + +} // namespace qdesigner_internal + +#endif // OBJECTINSPECTOR_H + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/objectinspector/objectinspector.pri b/tools/designer/src/components/objectinspector/objectinspector.pri new file mode 100644 index 0000000..280a1dc --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspector.pri @@ -0,0 +1,10 @@ +include($$QT_SOURCE_TREE/tools/shared/findwidget/findwidget.pri) + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/objectinspector.h \ + $$PWD/objectinspectormodel_p.h \ + $$PWD/objectinspector_global.h + +SOURCES += $$PWD/objectinspector.cpp \ + $$PWD/objectinspectormodel.cpp diff --git a/tools/designer/src/components/objectinspector/objectinspector_global.h b/tools/designer/src/components/objectinspector/objectinspector_global.h new file mode 100644 index 0000000..b1aedc0 --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspector_global.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECTINSPECTOR_GLOBAL_H +#define OBJECTINSPECTOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +#ifdef QT_OBJECTINSPECTOR_LIBRARY +# define QT_OBJECTINSPECTOR_EXPORT +#else +# define QT_OBJECTINSPECTOR_EXPORT +#endif +#else +#define QT_OBJECTINSPECTOR_EXPORT +#endif + +#endif // OBJECTINSPECTOR_GLOBAL_H + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/objectinspector/objectinspectormodel.cpp b/tools/designer/src/components/objectinspector/objectinspectormodel.cpp new file mode 100644 index 0000000..3effa60 --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspectormodel.cpp @@ -0,0 +1,517 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ObjectInspector +*/ + +#include "objectinspectormodel_p.h" + +#include <qlayout_widget_p.h> +#include <layout_p.h> +#include <qdesigner_propertycommand_p.h> +#include <qdesigner_utils_p.h> +#include <iconloader_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QExtensionManager> +#include <QtGui/QLayout> +#include <QtGui/QAction> +#include <QtGui/QLayoutItem> +#include <QtGui/QMenu> +#include <QtGui/QButtonGroup> +#include <QtCore/QSet> +#include <QtCore/QDebug> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +namespace { + enum { DataRole = 1000 }; +} + +static inline QObject *objectOfItem(const QStandardItem *item) { + return qvariant_cast<QObject *>(item->data(DataRole)); +} + +static bool sortEntry(const QObject *a, const QObject *b) +{ + return a->objectName() < b->objectName(); +} + +static bool sameIcon(const QIcon &i1, const QIcon &i2) +{ + if (i1.isNull() && i2.isNull()) + return true; + if (i1.isNull() != i2.isNull()) + return false; + return i1.serialNumber() == i2.serialNumber(); +} + +static inline bool isNameColumnEditable(const QObject *) +{ + return true; +} + +static qdesigner_internal::ObjectData::StandardItemList createModelRow(const QObject *o) +{ + qdesigner_internal::ObjectData::StandardItemList rc; + const Qt::ItemFlags baseFlags = Qt::ItemIsSelectable|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled; + for (int i = 0; i < qdesigner_internal::ObjectInspectorModel::NumColumns; i++) { + QStandardItem *item = new QStandardItem; + Qt::ItemFlags flags = baseFlags; + if (i == qdesigner_internal::ObjectInspectorModel::ObjectNameColumn && isNameColumnEditable(o)) + flags |= Qt::ItemIsEditable; + item->setFlags(flags); + rc += item; + } + return rc; +} + +static inline bool isQLayoutWidget(const QObject *o) +{ + return o->metaObject() == &QLayoutWidget::staticMetaObject; +} + +namespace qdesigner_internal { + + // context kept while building a model, just there to reduce string allocations + struct ModelRecursionContext { + explicit ModelRecursionContext(QDesignerFormEditorInterface *core, const QString &sepName); + + const QString designerPrefix; + const QString separator; + + QDesignerFormEditorInterface *core; + const QDesignerWidgetDataBaseInterface *db; + const QDesignerMetaDataBaseInterface *mdb; + }; + + ModelRecursionContext::ModelRecursionContext(QDesignerFormEditorInterface *c, const QString &sepName) : + designerPrefix(QLatin1String("QDesigner")), + separator(sepName), + core(c), + db(c->widgetDataBase()), + mdb(c->metaDataBase()) + { + } + + // ------------ ObjectData/ ObjectModel: + // Whenever the selection changes, ObjectInspector::setFormWindow is + // called. To avoid rebuilding the tree every time (loosing expanded state) + // a model is first built from the object tree by recursion. + // As a tree is difficult to represent, a flat list of entries (ObjectData) + // containing object and parent object is used. + // ObjectData has an overloaded operator== that compares the object pointers. + // Structural changes which cause a rebuild can be detected by + // comparing the lists of ObjectData. If it is the same, only the item data (class name [changed by promotion], + // object name and icon) are checked and the existing items are updated. + + ObjectData::ObjectData() : + m_parent(0), + m_object(0), + m_type(Object), + m_managedLayoutType(LayoutInfo::NoLayout) + { + } + + ObjectData::ObjectData(QObject *parent, QObject *object, const ModelRecursionContext &ctx) : + m_parent(parent), + m_object(object), + m_type(Object), + m_className(QLatin1String(object->metaObject()->className())), + m_objectName(object->objectName()), + m_managedLayoutType(LayoutInfo::NoLayout) + { + + // 1) set entry + if (object->isWidgetType()) { + initWidget(static_cast<QWidget*>(object), ctx); + } else { + initObject(ctx); + } + if (m_className.startsWith(ctx.designerPrefix)) + m_className.remove(1, ctx.designerPrefix.size() - 1); + } + + void ObjectData::initObject(const ModelRecursionContext &ctx) + { + // Check objects: Action? + if (const QAction *act = qobject_cast<const QAction*>(m_object)) { + if (act->isSeparator()) { // separator is reserved + m_objectName = ctx.separator; + m_type = SeparatorAction; + } else { + m_type = Action; + } + m_classIcon = act->icon(); + } else { + m_type = Object; + } + } + + void ObjectData::initWidget(QWidget *w, const ModelRecursionContext &ctx) + { + // Check for extension container, QLayoutwidget, or normal container + bool isContainer = false; + if (const QDesignerWidgetDataBaseItemInterface *widgetItem = ctx.db->item(ctx.db->indexOfObject(w, true))) { + m_classIcon = widgetItem->icon(); + m_className = widgetItem->name(); + isContainer = widgetItem->isContainer(); + } + + if (isQLayoutWidget(w)) { + m_type = LayoutWidget; + const QLayout *layout = w->layout(); + m_managedLayoutType = LayoutInfo::layoutType(ctx.core, layout); + m_className = QLatin1String(layout->metaObject()->className()); + m_objectName = layout->objectName(); + return; + } + + if (qt_extension<QDesignerContainerExtension*>(ctx.core->extensionManager(), w)) { + m_type = ExtensionContainer; + return; + } + if (isContainer) { + m_type = LayoutableContainer; + m_managedLayoutType = LayoutInfo::managedLayoutType(ctx.core, w); + return; + } + m_type = ChildWidget; + } + + bool ObjectData::equals(const ObjectData & me) const + { + return m_parent == me.m_parent && m_object == me.m_object; + } + + unsigned ObjectData::compare(const ObjectData & rhs) const + { + unsigned rc = 0; + if (m_className != rhs.m_className) + rc |= ClassNameChanged; + if (m_objectName != rhs.m_objectName) + rc |= ObjectNameChanged; + if (!sameIcon(m_classIcon, rhs.m_classIcon)) + rc |= ClassIconChanged; + if (m_type != rhs.m_type) + rc |= TypeChanged; + if (m_managedLayoutType != rhs.m_managedLayoutType) + rc |= LayoutTypeChanged; + return rc; + } + + void ObjectData::setItemsDisplayData(const StandardItemList &row, const ObjectInspectorIcons &icons, unsigned mask) const + { + if (mask & ObjectNameChanged) + row[ObjectInspectorModel::ObjectNameColumn]->setText(m_objectName); + if (mask & ClassNameChanged) { + row[ObjectInspectorModel::ClassNameColumn]->setText(m_className); + row[ObjectInspectorModel::ClassNameColumn]->setToolTip(m_className); + } + // Set a layout icon only for containers. Note that QLayoutWidget don't have + // real class icons + if (mask & (ClassIconChanged|TypeChanged|LayoutTypeChanged)) { + switch (m_type) { + case LayoutWidget: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + break; + case LayoutableContainer: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(m_classIcon); + break; + default: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(QIcon()); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(m_classIcon); + break; + } + } + } + + void ObjectData::setItems(const StandardItemList &row, const ObjectInspectorIcons &icons) const + { + const QVariant object = qVariantFromValue(m_object); + row[ObjectInspectorModel::ObjectNameColumn]->setData(object, DataRole); + row[ObjectInspectorModel::ClassNameColumn]->setData(object, DataRole); + setItemsDisplayData(row, icons, ClassNameChanged|ObjectNameChanged|ClassIconChanged|TypeChanged|LayoutTypeChanged); + } + + typedef QList<ObjectData> ObjectModel; + + // Recursive routine that creates the model by traversing the form window object tree. + void createModelRecursion(const QDesignerFormWindowInterface *fwi, + QObject *parent, + QObject *object, + ObjectModel &model, + const ModelRecursionContext &ctx) + { + typedef QList<QButtonGroup *> ButtonGroupList; + typedef QList<QAction *> ActionList; + + // 1) Create entry + const ObjectData entry(parent, object, ctx); + model.push_back(entry); + + // 2) recurse over widget children via container extension or children list + const QDesignerContainerExtension *containerExtension = 0; + if (entry.type() == ObjectData::ExtensionContainer) { + containerExtension = qt_extension<QDesignerContainerExtension*>(fwi->core()->extensionManager(), object); + Q_ASSERT(containerExtension); + const int count = containerExtension->count(); + for (int i=0; i < count; ++i) { + QObject *page = containerExtension->widget(i); + Q_ASSERT(page != 0); + createModelRecursion(fwi, object, page, model, ctx); + } + } + + QObjectList children = object->children(); + if (!children.empty()) { + ButtonGroupList buttonGroups; + qSort(children.begin(), children.end(), sortEntry); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + // Managed child widgets unless we had a container extension + if ((*it)->isWidgetType()) { + if (!containerExtension) { + QWidget *widget = qobject_cast<QWidget*>(*it); + if (fwi->isManaged(widget)) + createModelRecursion(fwi, object, widget, model, ctx); + } + } else { + if (ctx.mdb->item(*it)) { + if (QButtonGroup *bg = qobject_cast<QButtonGroup*>(*it)) + buttonGroups.push_back(bg); + } // Has MetaDataBase entry + } + } + // Add button groups + if (!buttonGroups.empty()) { + const ButtonGroupList::const_iterator bgcend = buttonGroups.constEnd(); + for (ButtonGroupList::const_iterator bgit = buttonGroups.constBegin(); bgit != bgcend; ++bgit) + createModelRecursion(fwi, object, *bgit, model, ctx); + } + } // has children + if (object->isWidgetType()) { + // Add actions + const ActionList actions = static_cast<QWidget*>(object)->actions(); + if (!actions.empty()) { + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) + if (ctx.mdb->item(*it)) { + QAction *action = *it; + QObject *obj = action; + if (action->menu()) + obj = action->menu(); + createModelRecursion(fwi, object, obj, model, ctx); + } + } + } + } + + // ------------ ObjectInspectorModel + ObjectInspectorModel::ObjectInspectorModel(QObject *parent) : + QStandardItemModel(0, NumColumns, parent) + { + QStringList headers; + headers += QCoreApplication::translate("ObjectInspectorModel", "Object"); + headers += QCoreApplication::translate("ObjectInspectorModel", "Class"); + Q_ASSERT(headers.size() == NumColumns); + setColumnCount(NumColumns); + setHorizontalHeaderLabels(headers); + // Icons + m_icons.layoutIcons[LayoutInfo::NoLayout] = createIconSet(QLatin1String("editbreaklayout.png")); + m_icons.layoutIcons[LayoutInfo::HSplitter] = createIconSet(QLatin1String("edithlayoutsplit.png")); + m_icons.layoutIcons[LayoutInfo::VSplitter] = createIconSet(QLatin1String("editvlayoutsplit.png")); + m_icons.layoutIcons[LayoutInfo::HBox] = createIconSet(QLatin1String("edithlayout.png")); + m_icons.layoutIcons[LayoutInfo::VBox] = createIconSet(QLatin1String("editvlayout.png")); + m_icons.layoutIcons[LayoutInfo::Grid] = createIconSet(QLatin1String("editgrid.png")); + m_icons.layoutIcons[LayoutInfo::Form] = createIconSet(QLatin1String("editform.png")); + } + + void ObjectInspectorModel::clearItems() + { + m_objectIndexMultiMap.clear(); + m_model.clear(); + reset(); // force editors to be closed in views + removeRow(0); + } + + ObjectInspectorModel::UpdateResult ObjectInspectorModel::update(QDesignerFormWindowInterface *fw) + { + QWidget *mainContainer = fw ? fw->mainContainer() : static_cast<QWidget*>(0); + if (!mainContainer) { + clearItems(); + m_formWindow = 0; + return NoForm; + } + m_formWindow = fw; + // Build new model and compare to previous one. If the structure is + // identical, just update, else rebuild + ObjectModel newModel; + + static const QString separator = QCoreApplication::translate("ObjectInspectorModel", "separator"); + const ModelRecursionContext ctx(fw->core(), separator); + createModelRecursion(fw, 0, mainContainer, newModel, ctx); + + if (newModel == m_model) { + updateItemContents(m_model, newModel); + return Updated; + } + + rebuild(newModel); + m_model = newModel; + return Rebuilt; + } + + QObject *ObjectInspectorModel::objectAt(const QModelIndex &index) const + { + if (index.isValid()) + if (const QStandardItem *item = itemFromIndex(index)) + return objectOfItem(item); + return 0; + } + + // Missing Qt API: get a row + ObjectInspectorModel::StandardItemList ObjectInspectorModel::rowAt(QModelIndex index) const + { + StandardItemList rc; + while (true) { + rc += itemFromIndex(index); + const int nextColumn = index.column() + 1; + if (nextColumn >= NumColumns) + break; + index = index.sibling(index.row(), nextColumn); + } + return rc; + } + + // Rebuild the tree in case the model has completely changed. + void ObjectInspectorModel::rebuild(const ObjectModel &newModel) + { + clearItems(); + if (newModel.empty()) + return; + + const ObjectModel::const_iterator mcend = newModel.constEnd(); + ObjectModel::const_iterator it = newModel.constBegin(); + // Set up root element + StandardItemList rootRow = createModelRow(it->object()); + it->setItems(rootRow, m_icons); + appendRow(rootRow); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(rootRow.front())); + for (++it; it != mcend; ++it) { + // Add to parent item, found via map + const QModelIndex parentIndex = m_objectIndexMultiMap.value(it->parent(), QModelIndex()); + Q_ASSERT(parentIndex.isValid()); + QStandardItem *parentItem = itemFromIndex(parentIndex); + StandardItemList row = createModelRow(it->object()); + it->setItems(row, m_icons); + parentItem->appendRow(row); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(row.front())); + } + } + + // Update item data in case the model has the same structure + void ObjectInspectorModel::updateItemContents(ObjectModel &oldModel, const ObjectModel &newModel) + { + // Change text and icon. Keep a set of changed object + // as for example actions might occur several times in the tree. + typedef QSet<QObject *> QObjectSet; + + QObjectSet changedObjects; + + const int size = newModel.size(); + Q_ASSERT(oldModel.size() == size); + for (int i = 0; i < size; i++) { + const ObjectData &newEntry = newModel[i]; + ObjectData &entry = oldModel[i]; + // Has some data changed? + if (const unsigned changedMask = entry.compare(newEntry)) { + entry = newEntry; + QObject * o = entry.object(); + if (!changedObjects.contains(o)) { + changedObjects.insert(o); + const QModelIndexList indexes = m_objectIndexMultiMap.values(o); + foreach (const QModelIndex &index, indexes) + entry.setItemsDisplayData(rowAt(index), m_icons, changedMask); + } + } + } + } + + QVariant ObjectInspectorModel::data(const QModelIndex &index, int role) const + { + const QVariant rc = QStandardItemModel::data(index, role); + // Return <noname> if the string is empty for the display role + // only (else, editing starts with <noname>). + if (role == Qt::DisplayRole && rc.type() == QVariant::String) { + const QString s = rc.toString(); + if (s.isEmpty()) { + static const QString noName = QCoreApplication::translate("ObjectInspectorModel", "<noname>"); + return QVariant(noName); + } + } + return rc; + } + + bool ObjectInspectorModel::setData(const QModelIndex &index, const QVariant &value, int role) + { + if (role != Qt::EditRole || !m_formWindow) + return false; + + QObject *object = objectAt(index); + if (!object) + return false; + // Is this a layout widget? + const QString nameProperty = isQLayoutWidget(object) ? QLatin1String("layoutName") : QLatin1String("objectName"); + m_formWindow->commandHistory()->push(createTextPropertyCommand(nameProperty, value.toString(), object, m_formWindow)); + return true; + } +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/objectinspector/objectinspectormodel_p.h b/tools/designer/src/components/objectinspector/objectinspectormodel_p.h new file mode 100644 index 0000000..63bc025 --- /dev/null +++ b/tools/designer/src/components/objectinspector/objectinspectormodel_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef OBJECTINSPECTORMODEL_H +#define OBJECTINSPECTORMODEL_H + +#include <layoutinfo_p.h> + +#include <QtGui/QStandardItemModel> +#include <QtGui/QIcon> +#include <QtCore/QModelIndex> +#include <QtCore/QString> +#include <QtCore/QList> +#include <QtCore/QMultiMap> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + // Data structure containing the fixed item type icons + struct ObjectInspectorIcons { + QIcon layoutIcons[LayoutInfo::UnknownLayout + 1]; + }; + + struct ModelRecursionContext; + + // Data structure representing one item of the object inspector. + class ObjectData { + public: + enum Type { + Object, + Action, + SeparatorAction, + ChildWidget, // A child widget + LayoutableContainer, // A container that can be laid out + LayoutWidget, // A QLayoutWidget + ExtensionContainer // QTabWidget and the like, container extension + }; + + typedef QList<QStandardItem *> StandardItemList; + + explicit ObjectData(QObject *parent, QObject *object, const ModelRecursionContext &ctx); + ObjectData(); + + inline Type type() const { return m_type; } + inline QObject *object() const { return m_object; } + inline QObject *parent() const { return m_parent; } + inline QString objectName() const { return m_objectName; } + + bool equals(const ObjectData & me) const; + + enum ChangedMask { ClassNameChanged = 1, ObjectNameChanged = 2, + ClassIconChanged = 4, TypeChanged = 8, + LayoutTypeChanged = 16}; + + unsigned compare(const ObjectData & me) const; + + // Initially set up a row + void setItems(const StandardItemList &row, const ObjectInspectorIcons &icons) const; + // Update row data according to change mask + void setItemsDisplayData(const StandardItemList &row, const ObjectInspectorIcons &icons, unsigned mask) const; + + private: + void initObject(const ModelRecursionContext &ctx); + void initWidget(QWidget *w, const ModelRecursionContext &ctx); + + QObject *m_parent; + QObject *m_object; + Type m_type; + QString m_className; + QString m_objectName; + QIcon m_classIcon; + LayoutInfo::Type m_managedLayoutType; + }; + + inline bool operator==(const ObjectData &e1, const ObjectData &e2) { return e1.equals(e2); } + inline bool operator!=(const ObjectData &e1, const ObjectData &e2) { return !e1.equals(e2); } + + typedef QList<ObjectData> ObjectModel; + + // QStandardItemModel for ObjectInspector. Uses ObjectData/ObjectModel + // internally for its updates. + class ObjectInspectorModel : public QStandardItemModel { + public: + typedef QList<QStandardItem *> StandardItemList; + enum { ObjectNameColumn, ClassNameColumn, NumColumns }; + + explicit ObjectInspectorModel(QObject *parent); + + enum UpdateResult { NoForm, Rebuilt, Updated }; + UpdateResult update(QDesignerFormWindowInterface *fw); + + const QModelIndexList indexesOf(QObject *o) const { return m_objectIndexMultiMap.values(o); } + QObject *objectAt(const QModelIndex &index) const; + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + private: + typedef QMultiMap<QObject *,QModelIndex> ObjectIndexMultiMap; + + void rebuild(const ObjectModel &newModel); + void updateItemContents(ObjectModel &oldModel, const ObjectModel &newModel); + void clearItems(); + StandardItemList rowAt(QModelIndex index) const; + + ObjectInspectorIcons m_icons; + ObjectIndexMultiMap m_objectIndexMultiMap; + ObjectModel m_model; + QPointer<QDesignerFormWindowInterface> m_formWindow; + }; +} // namespace qdesigner_internal + +#endif // OBJECTINSPECTORMODEL_H + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp b/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp new file mode 100644 index 0000000..2a63ba6 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "brushpropertymanager.h" +#include "qtpropertymanager.h" +#include "qtvariantproperty.h" +#include "qtpropertybrowserutils_p.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QVariant> +#include <QtCore/QString> + +static const char *brushStyles[] = { +QT_TRANSLATE_NOOP("BrushPropertyManager", "No brush"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Solid"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 1"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 2"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 3"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 4"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 5"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 6"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 7"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Horizontal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Vertical"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Cross"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Backward diagonal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Forward diagonal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Crossing diagonal"), +}; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +BrushPropertyManager::BrushPropertyManager() +{ +} + +int BrushPropertyManager::brushStyleToIndex(Qt::BrushStyle st) +{ + switch (st) { + case Qt::NoBrush: return 0; + case Qt::SolidPattern: return 1; + case Qt::Dense1Pattern: return 2; + case Qt::Dense2Pattern: return 3; + case Qt::Dense3Pattern: return 4; + case Qt::Dense4Pattern: return 5; + case Qt::Dense5Pattern: return 6; + case Qt::Dense6Pattern: return 7; + case Qt::Dense7Pattern: return 8; + case Qt::HorPattern: return 9; + case Qt::VerPattern: return 10; + case Qt::CrossPattern: return 11; + case Qt::BDiagPattern: return 12; + case Qt::FDiagPattern: return 13; + case Qt::DiagCrossPattern: return 14; + default: break; + } + return 0; +} + +Qt::BrushStyle BrushPropertyManager::brushStyleIndexToStyle(int brushStyleIndex) +{ + switch (brushStyleIndex) { + case 0: return Qt::NoBrush; + case 1: return Qt::SolidPattern; + case 2: return Qt::Dense1Pattern; + case 3: return Qt::Dense2Pattern; + case 4: return Qt::Dense3Pattern; + case 5: return Qt::Dense4Pattern; + case 6: return Qt::Dense5Pattern; + case 7: return Qt::Dense6Pattern; + case 8: return Qt::Dense7Pattern; + case 9: return Qt::HorPattern; + case 10: return Qt::VerPattern; + case 11: return Qt::CrossPattern; + case 12: return Qt::BDiagPattern; + case 13: return Qt::FDiagPattern; + case 14: return Qt::DiagCrossPattern; + } + return Qt::NoBrush; +} + +const BrushPropertyManager::EnumIndexIconMap &BrushPropertyManager::brushStyleIcons() +{ + // Create a map of icons for the brush style editor + static EnumIndexIconMap rc; + if (rc.empty()) { + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + QBrush brush(Qt::black); + const QIcon solidIcon = QtPropertyBrowserUtils::brushValueIcon(brush); + for (int i = 0; i < brushStyleCount; i++) { + const Qt::BrushStyle style = brushStyleIndexToStyle(i); + brush.setStyle(style); + rc.insert(i, QtPropertyBrowserUtils::brushValueIcon(brush)); + } + } + return rc; +} + +QString BrushPropertyManager::brushStyleIndexToString(int brushStyleIndex) +{ + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + return brushStyleIndex < brushStyleCount ? QCoreApplication::translate("BrushPropertyManager", brushStyles[brushStyleIndex]) : QString(); +} + +void BrushPropertyManager::initializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int enumTypeId) +{ + m_brushValues.insert(property, QBrush()); + // style + QtVariantProperty *styleSubProperty = vm->addProperty(enumTypeId, QCoreApplication::translate("BrushPropertyManager", "Style")); + property->addSubProperty(styleSubProperty); + QStringList styles; + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + for (int i = 0; i < brushStyleCount; i++) + styles.push_back(QCoreApplication::translate("BrushPropertyManager", brushStyles[i])); + styleSubProperty->setAttribute(QLatin1String("enumNames"), styles); + styleSubProperty->setAttribute(QLatin1String("enumIcons"), qVariantFromValue(brushStyleIcons())); + m_brushPropertyToStyleSubProperty.insert(property, styleSubProperty); + m_brushStyleSubPropertyToProperty.insert(styleSubProperty, property); + // color + QtVariantProperty *colorSubProperty = vm->addProperty(QVariant::Color, QCoreApplication::translate("BrushPropertyManager", "Color")); + property->addSubProperty(colorSubProperty); + m_brushPropertyToColorSubProperty.insert(property, colorSubProperty); + m_brushColorSubPropertyToProperty.insert(colorSubProperty, property); +} + +bool BrushPropertyManager::uninitializeProperty(QtProperty *property) +{ + const PropertyBrushMap::iterator brit = m_brushValues.find(property); // Brushes + if (brit == m_brushValues.end()) + return false; + m_brushValues.erase(brit); + // style + PropertyToPropertyMap::iterator subit = m_brushPropertyToStyleSubProperty.find(property); + if (subit != m_brushPropertyToStyleSubProperty.end()) { + QtProperty *styleProp = subit.value(); + m_brushStyleSubPropertyToProperty.remove(styleProp); + m_brushPropertyToStyleSubProperty.erase(subit); + delete styleProp; + } + // color + subit = m_brushPropertyToColorSubProperty.find(property); + if (subit != m_brushPropertyToColorSubProperty.end()) { + QtProperty *colorProp = subit.value(); + m_brushColorSubPropertyToProperty.remove(colorProp); + m_brushPropertyToColorSubProperty.erase(subit); + delete colorProp; + } + return true; +} + +void BrushPropertyManager::slotPropertyDestroyed(QtProperty *property) +{ + PropertyToPropertyMap::iterator subit = m_brushStyleSubPropertyToProperty.find(property); + if (subit != m_brushStyleSubPropertyToProperty.end()) { + m_brushPropertyToStyleSubProperty[subit.value()] = 0; + m_brushStyleSubPropertyToProperty.erase(subit); + } + subit = m_brushColorSubPropertyToProperty.find(property); + if (subit != m_brushColorSubPropertyToProperty.end()) { + m_brushPropertyToColorSubProperty[subit.value()] = 0; + m_brushColorSubPropertyToProperty.erase(subit); + } +} + + +BrushPropertyManager::ValueChangedResult BrushPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) +{ + switch (value.type()) { + case QVariant::Int: // Style subproperty? + if (QtProperty *brushProperty = m_brushStyleSubPropertyToProperty.value(property, 0)) { + const QBrush oldValue = m_brushValues.value(brushProperty); + QBrush newBrush = oldValue; + const int index = value.toInt(); + newBrush.setStyle(brushStyleIndexToStyle(index)); + if (newBrush == oldValue) + return Unchanged; + vm->variantProperty(brushProperty)->setValue(newBrush); + return Changed; + } + break; + case QVariant::Color: // Color subproperty? + if (QtProperty *brushProperty = m_brushColorSubPropertyToProperty.value(property, 0)) { + const QBrush oldValue = m_brushValues.value(brushProperty); + QBrush newBrush = oldValue; + newBrush.setColor(qvariant_cast<QColor>(value)); + if (newBrush == oldValue) + return Unchanged; + vm->variantProperty(brushProperty)->setValue(newBrush); + return Changed; + } + break; + default: + break; + } + return NoMatch; +} + +BrushPropertyManager::ValueChangedResult BrushPropertyManager::setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) +{ + if (value.type() != QVariant::Brush) + return NoMatch; + const PropertyBrushMap::iterator brit = m_brushValues.find(property); + if (brit == m_brushValues.end()) + return NoMatch; + + const QBrush newBrush = qvariant_cast<QBrush>(value); + if (newBrush == brit.value()) + return Unchanged; + brit.value() = newBrush; + if (QtProperty *styleProperty = m_brushPropertyToStyleSubProperty.value(property)) + vm->variantProperty(styleProperty)->setValue(brushStyleToIndex(newBrush.style())); + if (QtProperty *colorProperty = m_brushPropertyToColorSubProperty.value(property)) + vm->variantProperty(colorProperty)->setValue(newBrush.color()); + + return Changed; +} + +bool BrushPropertyManager::valueText(const QtProperty *property, QString *text) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast<QtProperty *>(property)); + if (brit == m_brushValues.constEnd()) + return false; + const QBrush &brush = brit.value(); + const QString styleName = brushStyleIndexToString(brushStyleToIndex(brush.style())); + *text = QCoreApplication::translate("BrushPropertyManager", "[%1, %2]").arg(styleName).arg(QtPropertyBrowserUtils::colorValueText(brush.color())); + return true; +} + +bool BrushPropertyManager::valueIcon(const QtProperty *property, QIcon *icon) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast<QtProperty *>(property)); + if (brit == m_brushValues.constEnd()) + return false; + *icon = QtPropertyBrowserUtils::brushValueIcon(brit.value()); + return true; +} + +bool BrushPropertyManager::value(const QtProperty *property, QVariant *v) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast<QtProperty *>(property)); + if (brit == m_brushValues.constEnd()) + return false; + qVariantSetValue(*v, brit.value()); + return true; +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/brushpropertymanager.h b/tools/designer/src/components/propertyeditor/brushpropertymanager.h new file mode 100644 index 0000000..2bb4933 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/brushpropertymanager.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BRUSHPROPERTYMANAGER_H +#define BRUSHPROPERTYMANAGER_H + +#include <QtCore/QMap> +#include <QtGui/QBrush> +#include <QtGui/QIcon> + +QT_BEGIN_NAMESPACE + +class QtProperty; +class QtVariantPropertyManager; + +class QString; +class QVariant; + +namespace qdesigner_internal { + +// BrushPropertyManager: A mixin for DesignerPropertyManager that manages brush properties. + +class BrushPropertyManager { + BrushPropertyManager(const BrushPropertyManager&); + BrushPropertyManager &operator=(const BrushPropertyManager&); + +public: + BrushPropertyManager(); + + void initializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int enumTypeId); + bool uninitializeProperty(QtProperty *property); + + // Call from slotValueChanged(). + enum ValueChangedResult { NoMatch, Unchanged, Changed }; + ValueChangedResult valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + ValueChangedResult setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + bool valueText(const QtProperty *property, QString *text) const; + bool valueIcon(const QtProperty *property, QIcon *icon) const; + bool value(const QtProperty *property, QVariant *v) const; + + // Call from QtPropertyManager's propertyDestroyed signal + void slotPropertyDestroyed(QtProperty *property); + +private: + static int brushStyleToIndex(Qt::BrushStyle st); + static Qt::BrushStyle brushStyleIndexToStyle(int brushStyleIndex); + static QString brushStyleIndexToString(int brushStyleIndex); + + typedef QMap<int, QIcon> EnumIndexIconMap; + static const EnumIndexIconMap &brushStyleIcons(); + + typedef QMap<QtProperty *, QtProperty *> PropertyToPropertyMap; + PropertyToPropertyMap m_brushPropertyToStyleSubProperty; + PropertyToPropertyMap m_brushPropertyToColorSubProperty; + PropertyToPropertyMap m_brushStyleSubPropertyToProperty; + PropertyToPropertyMap m_brushColorSubPropertyToProperty; + + typedef QMap<QtProperty *, QBrush> PropertyBrushMap; + PropertyBrushMap m_brushValues; +}; + +} + +QT_END_NAMESPACE + +#endif // BRUSHPROPERTYMANAGER_H diff --git a/tools/designer/src/components/propertyeditor/defs.cpp b/tools/designer/src/components/propertyeditor/defs.cpp new file mode 100644 index 0000000..ebee40a --- /dev/null +++ b/tools/designer/src/components/propertyeditor/defs.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "defs.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +int size_type_to_int( QSizePolicy::Policy t ) +{ + if ( t == QSizePolicy::Fixed ) + return 0; + if ( t == QSizePolicy::Minimum ) + return 1; + if ( t == QSizePolicy::Maximum ) + return 2; + if ( t == QSizePolicy::Preferred ) + return 3; + if ( t == QSizePolicy::MinimumExpanding ) + return 4; + if ( t == QSizePolicy::Expanding ) + return 5; + if ( t == QSizePolicy::Ignored ) + return 6; + return 0; +} + +QString size_type_to_string( QSizePolicy::Policy t ) +{ + if ( t == QSizePolicy::Fixed ) + return QString::fromUtf8("Fixed"); + if ( t == QSizePolicy::Minimum ) + return QString::fromUtf8("Minimum"); + if ( t == QSizePolicy::Maximum ) + return QString::fromUtf8("Maximum"); + if ( t == QSizePolicy::Preferred ) + return QString::fromUtf8("Preferred"); + if ( t == QSizePolicy::MinimumExpanding ) + return QString::fromUtf8("MinimumExpanding"); + if ( t == QSizePolicy::Expanding ) + return QString::fromUtf8("Expanding"); + if ( t == QSizePolicy::Ignored ) + return QString::fromUtf8("Ignored"); + return QString(); +} + +QSizePolicy::Policy int_to_size_type( int i ) +{ + if ( i == 0 ) + return QSizePolicy::Fixed; + if ( i == 1 ) + return QSizePolicy::Minimum; + if ( i == 2 ) + return QSizePolicy::Maximum; + if ( i == 3 ) + return QSizePolicy::Preferred; + if ( i == 4 ) + return QSizePolicy::MinimumExpanding; + if ( i == 5 ) + return QSizePolicy::Expanding; + if ( i == 6 ) + return QSizePolicy::Ignored; + return QSizePolicy::Preferred; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/defs.h b/tools/designer/src/components/propertyeditor/defs.h new file mode 100644 index 0000000..e7a48d6 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/defs.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFS_H +#define DEFS_H + +#include <QtGui/QSizePolicy> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +int size_type_to_int(QSizePolicy::Policy t); +QString size_type_to_string(QSizePolicy::Policy t); +QSizePolicy::Policy int_to_size_type(int i); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFS_H diff --git a/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp b/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp new file mode 100644 index 0000000..1b267aa --- /dev/null +++ b/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp @@ -0,0 +1,2604 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "designerpropertymanager.h" +#include "qtpropertymanager.h" +#include "paletteeditorbutton.h" +#include "qlonglongvalidator.h" +#include "stringlisteditorbutton.h" +#include "qtresourceview_p.h" +#include "qtpropertybrowserutils_p.h" + +#include <formwindowbase_p.h> +#include <textpropertyeditor_p.h> +#include <stylesheeteditor_p.h> +#include <richtexteditor_p.h> +#include <plaintexteditor_p.h> +#include <iconloader_p.h> +#include <iconselector_p.h> +#include <abstractdialoggui_p.h> + +#include <QtDesigner/QDesignerIconCacheInterface> + +#include <QtGui/QLabel> +#include <QtGui/QToolButton> +#include <QtGui/QHBoxLayout> +#include <QtCore/QFileInfo> +#include <QtGui/QClipboard> +#include <QtGui/QLineEdit> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QPushButton> +#include <QtGui/QFileDialog> +#include <QtGui/QAction> +#include <QtGui/QMenu> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QApplication> +#include <QtCore/QUrl> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +static const char *resettableAttributeC = "resettable"; +static const char *flagsAttributeC = "flags"; +static const char *validationModesAttributeC = "validationMode"; +static const char *superPaletteAttributeC = "superPalette"; +static const char *defaultResourceAttributeC = "defaultResource"; +static const char *fontAttributeC = "font"; + +class DesignerFlagPropertyType +{ +}; + + +class DesignerAlignmentPropertyType +{ +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(DesignerFlagPropertyType) +Q_DECLARE_METATYPE(DesignerAlignmentPropertyType) + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ TextEditor +class TextEditor : public QWidget +{ + Q_OBJECT +public: + TextEditor(QDesignerFormEditorInterface *core, QWidget *parent); + + TextPropertyValidationMode textPropertyValidationMode() const; + void setTextPropertyValidationMode(TextPropertyValidationMode vm); + + void setRichTextDefaultFont(const QFont &font) { m_richTextDefaultFont = font; } + QFont richTextDefaultFont() const { return m_richTextDefaultFont; } + + void setSpacing(int spacing); + + TextPropertyEditor::UpdateMode updateMode() const { return m_editor->updateMode(); } + void setUpdateMode(TextPropertyEditor::UpdateMode um) { m_editor->setUpdateMode(um); } + +public slots: + void setText(const QString &text); + +signals: + void textChanged(const QString &text); + +private slots: + void buttonClicked(); + void resourceActionActivated(); + void fileActionActivated(); +private: + TextPropertyEditor *m_editor; + QFont m_richTextDefaultFont; + QToolButton *m_button; + QMenu *m_menu; + QAction *m_resourceAction; + QAction *m_fileAction; + QHBoxLayout *m_layout; + QDesignerFormEditorInterface *m_core; +}; + +TextEditor::TextEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_editor(new TextPropertyEditor(this)), + m_richTextDefaultFont(QApplication::font()), + m_button(new QToolButton(this)), + m_menu(new QMenu(this)), + m_resourceAction(new QAction(tr("Choose Resource..."), this)), + m_fileAction(new QAction(tr("Choose File..."), this)), + m_layout(new QHBoxLayout(this)), + m_core(core) +{ + m_layout->addWidget(m_editor); + m_button->setText(tr("...")); + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(20); + m_layout->addWidget(m_button); + m_layout->setMargin(0); + m_layout->setSpacing(0); + + connect(m_resourceAction, SIGNAL(triggered()), this, SLOT(resourceActionActivated())); + connect(m_fileAction, SIGNAL(triggered()), this, SLOT(fileActionActivated())); + connect(m_editor, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString))); + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + m_button->setVisible(false); + setFocusProxy(m_editor); + + m_menu->addAction(m_resourceAction); + m_menu->addAction(m_fileAction); +} + +void TextEditor::setSpacing(int spacing) +{ + m_layout->setSpacing(spacing); +} + +TextPropertyValidationMode TextEditor::textPropertyValidationMode() const +{ + return m_editor->textPropertyValidationMode(); +} + +void TextEditor::setTextPropertyValidationMode(TextPropertyValidationMode vm) +{ + m_editor->setTextPropertyValidationMode(vm); + if (vm == ValidationURL) { + m_button->setMenu(m_menu); + m_button->setFixedWidth(30); + m_button->setPopupMode(QToolButton::MenuButtonPopup); + } else { + m_button->setMenu(0); + m_button->setFixedWidth(20); + m_button->setPopupMode(QToolButton::DelayedPopup); + } + m_button->setVisible(vm == ValidationStyleSheet || vm == ValidationRichText || vm == ValidationMultiLine || vm == ValidationURL); +} + +void TextEditor::setText(const QString &text) +{ + m_editor->setText(text); +} + +void TextEditor::buttonClicked() +{ + const QString oldText = m_editor->text(); + QString newText; + switch (textPropertyValidationMode()) { + case ValidationStyleSheet: { + StyleSheetEditorDialog dlg(m_core, this); + dlg.setText(oldText); + if (dlg.exec() != QDialog::Accepted) + return; + newText = dlg.text(); + } + break; + case ValidationRichText: { + RichTextEditorDialog dlg(m_core, this); + dlg.setDefaultFont(m_richTextDefaultFont); + dlg.setText(oldText); + if (dlg.showDialog() != QDialog::Accepted) + return; + newText = dlg.text(Qt::AutoText); + } + break; + case ValidationMultiLine: { + PlainTextEditorDialog dlg(m_core, this); + dlg.setDefaultFont(m_richTextDefaultFont); + dlg.setText(oldText); + if (dlg.showDialog() != QDialog::Accepted) + return; + newText = dlg.text(); + } + break; + case ValidationURL: { + QString oldPath = oldText; + if (oldPath.isEmpty() || oldPath.startsWith(QLatin1String("qrc:"))) + resourceActionActivated(); + else + fileActionActivated(); + } + return; + default: + return; + } + if (newText != oldText) { + m_editor->setText(newText); + emit textChanged(newText); + } +} + +void TextEditor::resourceActionActivated() +{ + QString oldPath = m_editor->text(); + if (oldPath.startsWith(QLatin1String("qrc:"))) + oldPath = oldPath.mid(4); + const QString newPath = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), oldPath, this); + if (newPath.isEmpty() || newPath == oldPath) + return; + const QString newText = QLatin1String("qrc:") + newPath; + m_editor->setText(newText); + emit textChanged(newText); +} + +void TextEditor::fileActionActivated() +{ + QString oldPath = m_editor->text(); + if (oldPath.startsWith(QLatin1String("file:"))) + oldPath = oldPath.mid(5); + const QString newPath = m_core->dialogGui()->getOpenFileName(this, tr("Choose a File"), oldPath); + if (newPath.isEmpty() || newPath == oldPath) + return; + const QString newText = QLatin1String("file:") + newPath; + m_editor->setText(newText); + emit textChanged(newText); +} + +// ------------ PixmapEditor +class PixmapEditor : public QWidget +{ + Q_OBJECT +public: + PixmapEditor(QDesignerFormEditorInterface *core, QWidget *parent); + + void setSpacing(int spacing); + void setPixmapCache(DesignerPixmapCache *cache); +public slots: + void setPath(const QString &path); + void setDefaultPixmap(const QPixmap &pixmap); + +signals: + void pathChanged(const QString &path); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +private slots: + void defaultActionActivated(); + void resourceActionActivated(); + void fileActionActivated(); + void copyActionActivated(); + void pasteActionActivated(); + void clipboardDataChanged(); +private: + QDesignerFormEditorInterface *m_core; + QLabel *m_pixmapLabel; + QLabel *m_pathLabel; + QToolButton *m_button; + QAction *m_resourceAction; + QAction *m_fileAction; + QAction *m_copyAction; + QAction *m_pasteAction; + QHBoxLayout *m_layout; + QPixmap m_defaultPixmap; + QString m_path; + DesignerPixmapCache *m_pixmapCache; +}; + +PixmapEditor::PixmapEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_core(core), + m_pixmapLabel(new QLabel(this)), + m_pathLabel(new QLabel(this)), + m_button(new QToolButton(this)), + m_resourceAction(new QAction(tr("Choose Resource..."), this)), + m_fileAction(new QAction(tr("Choose File..."), this)), + m_copyAction(new QAction(createIconSet(QLatin1String("editcopy.png")), tr("Copy Path"), this)), + m_pasteAction(new QAction(createIconSet(QLatin1String("editpaste.png")), tr("Paste Path"), this)), + m_layout(new QHBoxLayout(this)), + m_pixmapCache(0) +{ + m_layout->addWidget(m_pixmapLabel); + m_layout->addWidget(m_pathLabel); + m_button->setText(tr("...")); + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(30); + m_button->setPopupMode(QToolButton::MenuButtonPopup); + m_layout->addWidget(m_button); + m_layout->setMargin(0); + m_layout->setSpacing(0); + m_pixmapLabel->setFixedWidth(16); + m_pixmapLabel->setAlignment(Qt::AlignCenter); + m_pathLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); + + QMenu *menu = new QMenu(this); + menu->addAction(m_resourceAction); + menu->addAction(m_fileAction); + + m_button->setMenu(menu); + m_button->setText(tr("...")); + + connect(m_button, SIGNAL(clicked()), this, SLOT(defaultActionActivated())); + connect(m_resourceAction, SIGNAL(triggered()), this, SLOT(resourceActionActivated())); + connect(m_fileAction, SIGNAL(triggered()), this, SLOT(fileActionActivated())); + connect(m_copyAction, SIGNAL(triggered()), this, SLOT(copyActionActivated())); + connect(m_pasteAction, SIGNAL(triggered()), this, SLOT(pasteActionActivated())); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored)); + setFocusProxy(m_button); + + connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); + clipboardDataChanged(); +} + +void PixmapEditor::setPixmapCache(DesignerPixmapCache *cache) +{ + m_pixmapCache = cache; +} + +void PixmapEditor::setSpacing(int spacing) +{ + m_layout->setSpacing(spacing); +} + +void PixmapEditor::setPath(const QString &path) +{ + m_path = path; + if (m_path.isEmpty()) { + m_pathLabel->setText(path); + m_pixmapLabel->setPixmap(m_defaultPixmap); + m_copyAction->setEnabled(false); + } else { + m_pathLabel->setText(QFileInfo(m_path).fileName()); + if (m_pixmapCache) + m_pixmapLabel->setPixmap(QIcon(m_pixmapCache->pixmap(PropertySheetPixmapValue(path))).pixmap(16, 16)); + m_copyAction->setEnabled(true); + } +} + +void PixmapEditor::setDefaultPixmap(const QPixmap &pixmap) +{ + m_defaultPixmap = QIcon(pixmap).pixmap(16, 16); + if (m_path.isEmpty()) + m_pixmapLabel->setPixmap(m_defaultPixmap); +} + +void PixmapEditor::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu(this); + menu.addAction(m_copyAction); + menu.addAction(m_pasteAction); + menu.exec(event->globalPos()); + event->accept(); +} + +void PixmapEditor::defaultActionActivated() +{ + // Default to resource + const PropertySheetPixmapValue::PixmapSource ps = m_path.isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : PropertySheetPixmapValue::getPixmapSource(m_core, m_path); + switch (ps) { + case PropertySheetPixmapValue::LanguageResourcePixmap: + case PropertySheetPixmapValue::ResourcePixmap: + resourceActionActivated(); + break; + case PropertySheetPixmapValue::FilePixmap: + fileActionActivated(); + break; + } +} + +void PixmapEditor::resourceActionActivated() +{ + const QString oldPath = m_path; + const QString newPath = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), oldPath, this); + if (!newPath.isEmpty() && newPath != oldPath) { + setPath(newPath); + emit pathChanged(newPath); + } +} + +void PixmapEditor::fileActionActivated() +{ + const QString newPath = IconSelector::choosePixmapFile(m_path, m_core->dialogGui(), this); + if (!newPath.isEmpty() && newPath != m_path) { + setPath(newPath); + emit pathChanged(newPath); + } +} + +void PixmapEditor::copyActionActivated() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(m_path); +} + +void PixmapEditor::pasteActionActivated() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString subtype = QLatin1String("plain"); + QString text = clipboard->text(subtype); + if (!text.isNull()) { + QStringList list = text.split(QLatin1Char('\n')); + if (list.size() > 0) { + text = list.at(0); + setPath(text); + emit pathChanged(text); + } + } +} + +void PixmapEditor::clipboardDataChanged() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString subtype = QLatin1String("plain"); + const QString text = clipboard->text(subtype); + m_pasteAction->setEnabled(!text.isNull()); +} + +// --------------- ResetWidget +class ResetWidget : public QWidget +{ + Q_OBJECT +public: + ResetWidget(QtProperty *property, QWidget *parent = 0); + + void setWidget(QWidget *widget); + void setResetEnabled(bool enabled); + void setValueText(const QString &text); + void setValueIcon(const QIcon &icon); + void setSpacing(int spacing); +signals: + void resetProperty(QtProperty *property); +private slots: + void slotClicked(); +private: + QtProperty *m_property; + QLabel *m_textLabel; + QLabel *m_iconLabel; + QToolButton *m_button; + int m_spacing; +}; + +ResetWidget::ResetWidget(QtProperty *property, QWidget *parent) : + QWidget(parent), + m_property(property), + m_textLabel(new QLabel(this)), + m_iconLabel(new QLabel(this)), + m_button(new QToolButton(this)), + m_spacing(-1) +{ + m_textLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); + m_iconLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + m_button->setToolButtonStyle(Qt::ToolButtonIconOnly); + m_button->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + m_button->setIconSize(QSize(8,8)); + m_button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); + connect(m_button, SIGNAL(clicked()), this, SLOT(slotClicked())); + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(m_spacing); + layout->addWidget(m_iconLabel); + layout->addWidget(m_textLabel); + layout->addWidget(m_button); + setFocusProxy(m_textLabel); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); +} + +void ResetWidget::setSpacing(int spacing) +{ + m_spacing = spacing; + layout()->setSpacing(m_spacing); +} + +void ResetWidget::setWidget(QWidget *widget) +{ + if (m_textLabel) { + delete m_textLabel; + m_textLabel = 0; + } + if (m_iconLabel) { + delete m_iconLabel; + m_iconLabel = 0; + } + delete layout(); + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(m_spacing); + layout->addWidget(widget); + layout->addWidget(m_button); + setFocusProxy(widget); +} + +void ResetWidget::setResetEnabled(bool enabled) +{ + m_button->setEnabled(enabled); +} + +void ResetWidget::setValueText(const QString &text) +{ + if (m_textLabel) + m_textLabel->setText(text); +} + +void ResetWidget::setValueIcon(const QIcon &icon) +{ + QPixmap pix = icon.pixmap(QSize(16, 16)); + if (m_iconLabel) { + m_iconLabel->setVisible(!pix.isNull()); + m_iconLabel->setPixmap(pix); + } +} + +void ResetWidget::slotClicked() +{ + emit resetProperty(m_property); +} + + +// ------------ DesignerPropertyManager: + +DesignerPropertyManager::DesignerPropertyManager(QDesignerFormEditorInterface *core, QObject *parent) : + QtVariantPropertyManager(parent), + m_changingSubValue(false), + m_core(core), + m_sourceOfChange(0) +{ + connect(this, SIGNAL(valueChanged(QtProperty*,QVariant)), this, SLOT(slotValueChanged(QtProperty*, QVariant))); + connect(this, SIGNAL(propertyDestroyed(QtProperty*)), this, SLOT(slotPropertyDestroyed(QtProperty*))); +} + +DesignerPropertyManager::~DesignerPropertyManager() +{ + clear(); +} + +int DesignerPropertyManager::bitCount(int mask) const +{ + int count = 0; + for (; mask; count++) + mask &= mask - 1; // clear the least significant bit set + return count; +} + +int DesignerPropertyManager::alignToIndexH(uint align) const +{ + if (align & Qt::AlignLeft) + return 0; + if (align & Qt::AlignHCenter) + return 1; + if (align & Qt::AlignRight) + return 2; + if (align & Qt::AlignJustify) + return 3; + return 0; +} + +int DesignerPropertyManager::alignToIndexV(uint align) const +{ + if (align & Qt::AlignTop) + return 0; + if (align & Qt::AlignVCenter) + return 1; + if (align & Qt::AlignBottom) + return 2; + return 1; +} + +uint DesignerPropertyManager::indexHToAlign(int idx) const +{ + switch (idx) { + case 0: return Qt::AlignLeft; + case 1: return Qt::AlignHCenter; + case 2: return Qt::AlignRight; + case 3: return Qt::AlignJustify; + default: break; + } + return Qt::AlignLeft; +} + +uint DesignerPropertyManager::indexVToAlign(int idx) const +{ + switch (idx) { + case 0: return Qt::AlignTop; + case 1: return Qt::AlignVCenter; + case 2: return Qt::AlignBottom; + default: break; + } + return Qt::AlignVCenter; +} + +QString DesignerPropertyManager::indexHToString(int idx) const +{ + switch (idx) { + case 0: return tr("AlignLeft"); + case 1: return tr("AlignHCenter"); + case 2: return tr("AlignRight"); + case 3: return tr("AlignJustify"); + default: break; + } + return tr("AlignLeft"); +} + +QString DesignerPropertyManager::indexVToString(int idx) const +{ + switch (idx) { + case 0: return tr("AlignTop"); + case 1: return tr("AlignVCenter"); + case 2: return tr("AlignBottom"); + default: break; + } + return tr("AlignVCenter"); +} + +void DesignerPropertyManager::slotValueChanged(QtProperty *property, const QVariant &value) +{ + if (m_changingSubValue) + return; + bool enableSubPropertyHandling = true; + + if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { + const QList<QtProperty *> subFlags = m_propertyToFlags.value(flagProperty); + const int subFlagCount = subFlags.count(); + // flag changed + const bool subValue = variantProperty(property)->value().toBool(); + const int subIndex = subFlags.indexOf(property); + if (subIndex < 0) + return; + + uint newValue = 0; + + m_changingSubValue = true; + + FlagData data = m_flagValues.value(flagProperty); + const QList<uint> values = data.values; + // Compute new value, without including (additional) supermasks + if (values.at(subIndex) == 0) { + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + subFlag->setValue(i == subIndex); + } + } else { + if (subValue) + newValue = values.at(subIndex); // value mask of subValue + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + if (subFlag->value().toBool() && bitCount(values.at(i)) == 1) + newValue |= values.at(i); + } + if (newValue == 0) { + // Uncheck all items except 0-mask + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + subFlag->setValue(values.at(i) == 0); + } + } else if (newValue == data.val) { + if (!subValue && bitCount(values.at(subIndex)) > 1) { + // We unchecked something, but the original value still holds + variantProperty(property)->setValue(true); + } + } else { + // Make sure 0-mask is not selected + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + if (values.at(i) == 0) + subFlag->setValue(false); + } + // Check/uncheck proper masks + if (subValue) { + // Make sure submasks and supermasks are selected + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint vi = values.at(i); + if ((vi != 0) && ((vi & newValue) == vi) && !subFlag->value().toBool()) + subFlag->setValue(true); + } + } else { + // Make sure supermasks are not selected if they're no longer valid + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint vi = values.at(i); + if (subFlag->value().toBool() && ((vi & newValue) != vi)) + subFlag->setValue(false); + } + } + } + } + m_changingSubValue = false; + data.val = newValue; + QVariant v; + qVariantSetValue(v, data.val); + variantProperty(flagProperty)->setValue(v); + } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) { + const uint v = m_alignValues.value(alignProperty); + const uint newValue = indexHToAlign(value.toInt()) | indexVToAlign(alignToIndexV(v)); + if (v == newValue) + return; + + variantProperty(alignProperty)->setValue(newValue); + } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) { + const uint v = m_alignValues.value(alignProperty); + const uint newValue = indexVToAlign(value.toInt()) | indexHToAlign(alignToIndexH(v)); + if (v == newValue) + return; + + variantProperty(alignProperty)->setValue(newValue); + } else if (QtProperty *stringProperty = m_commentToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setComment(value.toString()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *stringProperty = m_translatableToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setTranslatable(value.toBool()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *stringProperty = m_disambiguationToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setDisambiguation(value.toString()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_commentToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setComment(value.toString()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_translatableToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setTranslatable(value.toBool()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_disambiguationToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setDisambiguation(value.toString()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(qVariantFromValue(newValue)); + } else if (QtProperty *iProperty = m_iconSubPropertyToProperty.value(property, 0)) { + QtVariantProperty *iconProperty = variantProperty(iProperty); + PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(iconProperty->value()); + QPair<QIcon::Mode, QIcon::State> pair = m_iconSubPropertyToState.value(property); + icon.setPixmap(pair.first, pair.second, qVariantValue<PropertySheetPixmapValue>(value)); + QtProperty *origSourceOfChange = m_sourceOfChange; + if (!origSourceOfChange) + m_sourceOfChange = property; + iconProperty->setValue(qVariantFromValue(icon)); + if (!origSourceOfChange) + m_sourceOfChange = origSourceOfChange; + } else if (m_iconValues.contains(property)) { + enableSubPropertyHandling = m_sourceOfChange; + } else { + if (m_brushManager.valueChanged(this, property, value) == BrushPropertyManager::Unchanged) + return; + if (m_fontManager.valueChanged(this, property, value) == FontPropertyManager::Unchanged) + return; + } + + emit valueChanged(property, value, enableSubPropertyHandling); +} + +void DesignerPropertyManager::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { + PropertyToPropertyListMap::iterator it = m_propertyToFlags.find(flagProperty); + QList<QtProperty *> &propertyList = it.value(); + propertyList.replace(propertyList.indexOf(property), 0); + m_flagToProperty.remove(property); + } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) { + m_propertyToAlignH.remove(alignProperty); + m_alignHToProperty.remove(property); + } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) { + m_propertyToAlignV.remove(alignProperty); + m_alignVToProperty.remove(property); + } else if (QtProperty *stringCommentProperty = m_commentToString.value(property, 0)) { + m_stringToComment.remove(stringCommentProperty); + m_commentToString.remove(property); + } else if (QtProperty *stringTranslatableProperty = m_translatableToString.value(property, 0)) { + m_stringToTranslatable.remove(stringTranslatableProperty); + m_translatableToString.remove(property); + } else if (QtProperty *stringDisambiguationProperty = m_disambiguationToString.value(property, 0)) { + m_stringToDisambiguation.remove(stringDisambiguationProperty); + m_disambiguationToString.remove(property); + } else if (QtProperty *keySequenceCommentProperty = m_commentToKeySequence.value(property, 0)) { + m_keySequenceToComment.remove(keySequenceCommentProperty); + m_commentToKeySequence.remove(property); + } else if (QtProperty *keySequenceTranslatableProperty = m_translatableToKeySequence.value(property, 0)) { + m_keySequenceToTranslatable.remove(keySequenceTranslatableProperty); + m_translatableToKeySequence.remove(property); + } else if (QtProperty *keySequenceDisambiguationProperty = m_disambiguationToKeySequence.value(property, 0)) { + m_keySequenceToDisambiguation.remove(keySequenceDisambiguationProperty); + m_disambiguationToKeySequence.remove(property); + } else if (QtProperty *iconProperty = m_iconSubPropertyToProperty.value(property, 0)) { + QMap<QtProperty *, QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> >::iterator it = + m_propertyToIconSubProperties.find(iconProperty); + QPair<QIcon::Mode, QIcon::State> state = m_iconSubPropertyToState.value(property); + QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> &propertyList = it.value(); + propertyList.remove(state); + m_iconSubPropertyToState.remove(property); + m_iconSubPropertyToProperty.remove(property); + } else { + m_fontManager.slotPropertyDestroyed(property); + m_brushManager.slotPropertyDestroyed(property); + } +} + +QStringList DesignerPropertyManager::attributes(int propertyType) const +{ + if (!isPropertyTypeSupported(propertyType)) + return QStringList(); + + QStringList list = QtVariantPropertyManager::attributes(propertyType); + if (propertyType == designerFlagTypeId()) { + list.append(QLatin1String(flagsAttributeC)); + } else if (propertyType == designerPixmapTypeId()) { + list.append(QLatin1String(defaultResourceAttributeC)); + } else if (propertyType == designerIconTypeId()) { + list.append(QLatin1String(defaultResourceAttributeC)); + } else if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + list.append(QLatin1String(validationModesAttributeC)); + list.append(QLatin1String(fontAttributeC)); + } else if (propertyType == QVariant::Palette) { + list.append(QLatin1String(superPaletteAttributeC)); + } + list.append(QLatin1String(resettableAttributeC)); + return list; +} + +int DesignerPropertyManager::attributeType(int propertyType, const QString &attribute) const +{ + if (!isPropertyTypeSupported(propertyType)) + return 0; + + if (propertyType == designerFlagTypeId() && attribute == QLatin1String(flagsAttributeC)) + return designerFlagListTypeId(); + if (propertyType == designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) + return QVariant::Pixmap; + if (propertyType == designerIconTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) + return QVariant::Icon; + if (attribute == QLatin1String(resettableAttributeC)) + return QVariant::Bool; + if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + if (attribute == QLatin1String(validationModesAttributeC)) + return QVariant::Int; + if (attribute == QLatin1String(fontAttributeC)) + return QVariant::Font; + } + if (propertyType == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) + return QVariant::Palette; + + return QtVariantPropertyManager::attributeType(propertyType, attribute); +} + +QVariant DesignerPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const +{ + QtProperty *prop = const_cast<QtProperty *>(property); + + if (attribute == QLatin1String(resettableAttributeC)) { + const PropertyBoolMap::const_iterator it = m_resetMap.constFind(prop); + if (it != m_resetMap.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(flagsAttributeC)) { + PropertyFlagDataMap::const_iterator it = m_flagValues.constFind(prop); + if (it != m_flagValues.constEnd()) { + QVariant v; + qVariantSetValue(v, it.value().flags); + return v; + } + } + if (attribute == QLatin1String(validationModesAttributeC)) { + const PropertyIntMap::const_iterator it = m_stringAttributes.constFind(prop); + if (it != m_stringAttributes.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(fontAttributeC)) { + const PropertyFontMap::const_iterator it = m_stringFontAttributes.constFind(prop); + if (it != m_stringFontAttributes.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(superPaletteAttributeC)) { + PropertyPaletteDataMap::const_iterator it = m_paletteValues.constFind(prop); + if (it != m_paletteValues.constEnd()) + return it.value().superPalette; + } + + if (attribute == QLatin1String(defaultResourceAttributeC)) { + QMap<QtProperty *, QPixmap>::const_iterator itPix = m_defaultPixmaps.constFind(prop); + if (itPix != m_defaultPixmaps.constEnd()) + return itPix.value(); + + QMap<QtProperty *, QIcon>::const_iterator itIcon = m_defaultIcons.constFind(prop); + if (itIcon != m_defaultIcons.constEnd()) + return itIcon.value(); + } + + return QtVariantPropertyManager::attributeValue(property, attribute); +} + +void DesignerPropertyManager::setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value) +{ + if (attribute == QLatin1String(resettableAttributeC) && m_resetMap.contains(property)) { + if (value.userType() != QVariant::Bool) + return; + const bool val = value.toBool(); + const PropertyBoolMap::iterator it = m_resetMap.find(property); + if (it.value() == val) + return; + it.value() = val; + emit attributeChanged(variantProperty(property), attribute, value); + return; + } else if (attribute == QLatin1String(flagsAttributeC) && m_flagValues.contains(property)) { + if (value.userType() != designerFlagListTypeId()) + return; + + const DesignerFlagList flags = qVariantValue<DesignerFlagList>(value); + PropertyFlagDataMap::iterator fit = m_flagValues.find(property); + FlagData data = fit.value(); + if (data.flags == flags) + return; + + PropertyToPropertyListMap::iterator pfit = m_propertyToFlags.find(property); + QListIterator<QtProperty *> itProp(pfit.value()); + while (itProp.hasNext()) { + if (QtProperty *prop = itProp.next()) { + delete prop; + m_flagToProperty.remove(prop); + } + } + pfit.value().clear(); + + QList<uint> values; + + QListIterator<QPair<QString, uint> > itFlag(flags); + while (itFlag.hasNext()) { + const QPair<QString, uint> pair = itFlag.next(); + const QString flagName = pair.first; + QtProperty *prop = addProperty(QVariant::Bool); + prop->setPropertyName(flagName); + property->addSubProperty(prop); + m_propertyToFlags[property].append(prop); + m_flagToProperty[prop] = property; + values.append(pair.second); + } + + data.val = 0; + data.flags = flags; + data.values = values; + + fit.value() = data; + + QVariant v; + qVariantSetValue(v, flags); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, data.val); + } else if (attribute == QLatin1String(validationModesAttributeC) && m_stringAttributes.contains(property)) { + if (value.userType() != QVariant::Int) + return; + + const PropertyIntMap::iterator it = m_stringAttributes.find(property); + const int oldValue = it.value(); + + const int newValue = value.toInt(); + + if (oldValue == newValue) + return; + + it.value() = newValue; + + emit attributeChanged(property, attribute, newValue); + } else if (attribute == QLatin1String(fontAttributeC) && m_stringFontAttributes.contains(property)) { + if (value.userType() != QVariant::Font) + return; + + const PropertyFontMap::iterator it = m_stringFontAttributes.find(property); + const QFont oldValue = it.value(); + + const QFont newValue = qvariant_cast<QFont>(value); + + if (oldValue == newValue) + return; + + it.value() = newValue; + + emit attributeChanged(property, attribute, newValue); + } else if (attribute == QLatin1String(superPaletteAttributeC) && m_paletteValues.contains(property)) { + if (value.userType() != QVariant::Palette) + return; + + QPalette superPalette = qVariantValue<QPalette>(value); + + const PropertyPaletteDataMap::iterator it = m_paletteValues.find(property); + PaletteData data = it.value(); + if (data.superPalette == superPalette) + return; + + data.superPalette = superPalette; + // resolve here + const uint mask = data.val.resolve(); + data.val = data.val.resolve(superPalette); + data.val.resolve(mask); + + it.value() = data; + + QVariant v; + qVariantSetValue(v, superPalette); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, data.val); // if resolve was done, this is also for consistency + } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultPixmaps.contains(property)) { + if (value.userType() != QVariant::Pixmap) + return; + + QPixmap defaultPixmap = qVariantValue<QPixmap>(value); + + const QMap<QtProperty *, QPixmap>::iterator it = m_defaultPixmaps.find(property); + QPixmap oldDefaultPixmap = it.value(); + if (defaultPixmap.cacheKey() == oldDefaultPixmap.cacheKey()) + return; + + it.value() = defaultPixmap; + + QVariant v = qVariantFromValue(defaultPixmap); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultIcons.contains(property)) { + if (value.userType() != QVariant::Icon) + return; + + QIcon defaultIcon = qVariantValue<QIcon>(value); + + const QMap<QtProperty *, QIcon>::iterator it = m_defaultIcons.find(property); + QIcon oldDefaultIcon = it.value(); + if (defaultIcon.cacheKey() == oldDefaultIcon.cacheKey()) + return; + + it.value() = defaultIcon; + + qdesigner_internal::PropertySheetIconValue icon = m_iconValues.value(property); + if (icon.paths().isEmpty()) { + QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> subIconProperties = m_propertyToIconSubProperties.value(property); + QMapIterator<QPair<QIcon::Mode, QIcon::State>, QtProperty *> itSub(subIconProperties); + while (itSub.hasNext()) { + QPair<QIcon::Mode, QIcon::State> pair = itSub.next().key(); + QtProperty *subProp = itSub.value(); + setAttribute(subProp, QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + } + + QVariant v = qVariantFromValue(defaultIcon); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + } + QtVariantPropertyManager::setAttribute(property, attribute, value); +} + +int DesignerPropertyManager::designerFlagTypeId() +{ + static const int rc = qMetaTypeId<DesignerFlagPropertyType>(); + return rc; +} + +int DesignerPropertyManager::designerFlagListTypeId() +{ + static const int rc = qMetaTypeId<DesignerFlagList>(); + return rc; +} + +int DesignerPropertyManager::designerAlignmentTypeId() +{ + static const int rc = qMetaTypeId<DesignerAlignmentPropertyType>(); + return rc; +} + +int DesignerPropertyManager::designerPixmapTypeId() +{ + return qMetaTypeId<PropertySheetPixmapValue>(); +} + +int DesignerPropertyManager::designerIconTypeId() +{ + return qMetaTypeId<PropertySheetIconValue>(); +} + +int DesignerPropertyManager::designerStringTypeId() +{ + return qMetaTypeId<PropertySheetStringValue>(); +} + +int DesignerPropertyManager::designerKeySequenceTypeId() +{ + return qMetaTypeId<PropertySheetKeySequenceValue>(); +} + +bool DesignerPropertyManager::isPropertyTypeSupported(int propertyType) const +{ + switch (propertyType) { + case QVariant::Palette: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Url: + case QVariant::ByteArray: + case QVariant::StringList: + case QVariant::Brush: + return true; + default: + break; + } + + if (propertyType == designerFlagTypeId()) + return true; + if (propertyType == designerAlignmentTypeId()) + return true; + if (propertyType == designerPixmapTypeId()) + return true; + if (propertyType == designerIconTypeId()) + return true; + if (propertyType == designerStringTypeId()) + return true; + if (propertyType == designerKeySequenceTypeId()) + return true; + return QtVariantPropertyManager::isPropertyTypeSupported(propertyType); +} + +QString DesignerPropertyManager::valueText(const QtProperty *property) const +{ + if (m_flagValues.contains(const_cast<QtProperty *>(property))) { + const FlagData data = m_flagValues.value(const_cast<QtProperty *>(property)); + const uint v = data.val; + const QChar bar = QLatin1Char('|'); + QString valueStr; + const QList<QPair<QString, uint> > flags = data.flags; + const QList<QPair<QString, uint> >::const_iterator fcend = flags.constEnd(); + for (QList<QPair<QString, uint> >::const_iterator it = flags.constBegin(); it != fcend; ++it) { + const uint val = it->second; + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + if (checked) { + if (!valueStr.isEmpty()) + valueStr += bar; + valueStr += it->first; + } + } + return valueStr; + } + if (m_alignValues.contains(const_cast<QtProperty *>(property))) { + const uint v = m_alignValues.value(const_cast<QtProperty *>(property)); + return tr("%1, %2").arg(indexHToString(alignToIndexH(v))).arg(indexVToString(alignToIndexV(v))); + } + if (m_paletteValues.contains(const_cast<QtProperty *>(property))) { + const PaletteData data = m_paletteValues.value(const_cast<QtProperty *>(property)); + const uint mask = data.val.resolve(); + if (mask) + return tr("Customized (%n roles)", 0, bitCount(mask)); + static const QString inherited = tr("Inherited"); + return inherited; + } + if (m_iconValues.contains(const_cast<QtProperty *>(property))) { + const PropertySheetIconValue::ModeStateToPixmapMap paths = m_iconValues.value(const_cast<QtProperty *>(property)).paths(); + const PropertySheetIconValue::ModeStateToPixmapMap::const_iterator it = paths.constFind(qMakePair(QIcon::Normal, QIcon::Off)); + if (it == paths.constEnd()) + return QString(); + return QFileInfo(it.value().path()).fileName(); + } + if (m_pixmapValues.contains(const_cast<QtProperty *>(property))) { + const QString path = m_pixmapValues.value(const_cast<QtProperty *>(property)).path(); + if (path.isEmpty()) + return QString(); + return QFileInfo(path).fileName(); + } + if (m_uintValues.contains(const_cast<QtProperty *>(property))) { + return QString::number(m_uintValues.value(const_cast<QtProperty *>(property))); + } + if (m_longLongValues.contains(const_cast<QtProperty *>(property))) { + return QString::number(m_longLongValues.value(const_cast<QtProperty *>(property))); + } + if (m_uLongLongValues.contains(const_cast<QtProperty *>(property))) { + return QString::number(m_uLongLongValues.value(const_cast<QtProperty *>(property))); + } + if (m_urlValues.contains(const_cast<QtProperty *>(property))) { + return m_urlValues.value(const_cast<QtProperty *>(property)).toString(); + } + if (m_byteArrayValues.contains(const_cast<QtProperty *>(property))) { + return QString::fromUtf8(m_byteArrayValues.value(const_cast<QtProperty *>(property))); + } + if (m_stringListValues.contains(const_cast<QtProperty *>(property))) { + return m_stringListValues.value(const_cast<QtProperty *>(property)).join(QLatin1String("; ")); + } + if (QtVariantPropertyManager::valueType(property) == QVariant::String || QtVariantPropertyManager::valueType(property) == designerStringTypeId()) { + const QString str = (QtVariantPropertyManager::valueType(property) == QVariant::String) ? value(property).toString() : qVariantValue<PropertySheetStringValue>(value(property)).value(); + const int validationMode = attributeValue(property, QLatin1String(validationModesAttributeC)).toInt(); + return TextPropertyEditor::stringToEditorString(str, static_cast<TextPropertyValidationMode>(validationMode)); + } + if (QtVariantPropertyManager::valueType(property) == designerKeySequenceTypeId()) { + return qVariantValue<PropertySheetKeySequenceValue>(value(property)).value(); + } + if (QtVariantPropertyManager::valueType(property) == QVariant::Bool) { + return QString(); + } + + QString rc; + if (m_brushManager.valueText(property, &rc)) + return rc; + return QtVariantPropertyManager::valueText(property); +} + +void DesignerPropertyManager::reloadResourceProperties() +{ + DesignerIconCache *iconCache = 0; + QMapIterator<QtProperty *, qdesigner_internal::PropertySheetIconValue> itIcon(m_iconValues); + while (itIcon.hasNext()) { + QtProperty *property = itIcon.next().key(); + PropertySheetIconValue icon = itIcon.value(); + + QIcon defaultIcon = m_defaultIcons.value(property); + if (!icon.paths().isEmpty()) { + if (!iconCache) { + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow); + iconCache = fwb->iconCache(); + } + if (iconCache) + defaultIcon = iconCache->icon(icon); + } + + QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> iconPaths = icon.paths(); + + QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> subProperties = m_propertyToIconSubProperties.value(property); + QMapIterator<QPair<QIcon::Mode, QIcon::State>, QtProperty *> itSub(subProperties); + while (itSub.hasNext()) { + const QPair<QIcon::Mode, QIcon::State> pair = itSub.next().key(); + QtVariantProperty *subProperty = variantProperty(itSub.value()); + subProperty->setAttribute(QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(itIcon.value())); + } + QMapIterator<QtProperty *, qdesigner_internal::PropertySheetPixmapValue> itPix(m_pixmapValues); + while (itPix.hasNext()) { + QtProperty *property = itPix.next().key(); + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(itPix.value())); + } +} + +QIcon DesignerPropertyManager::valueIcon(const QtProperty *property) const +{ + if (m_iconValues.contains(const_cast<QtProperty *>(property))) { + if (!property->isModified()) + return m_defaultIcons.value(const_cast<QtProperty *>(property)).pixmap(16, 16); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow); + if (fwb) + return fwb->iconCache()->icon(m_iconValues.value(const_cast<QtProperty *>(property))).pixmap(16, 16); + } else if (m_pixmapValues.contains(const_cast<QtProperty *>(property))) { + if (!property->isModified()) + return m_defaultPixmaps.value(const_cast<QtProperty *>(property)); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow); + if (fwb) + return fwb->pixmapCache()->pixmap(m_pixmapValues.value(const_cast<QtProperty *>(property))); + } else { + QIcon rc; + if (m_brushManager.valueIcon(property, &rc)) + return rc; + } + + return QtVariantPropertyManager::valueIcon(property); +} + +QVariant DesignerPropertyManager::value(const QtProperty *property) const +{ + if (m_flagValues.contains(const_cast<QtProperty *>(property))) + return m_flagValues.value(const_cast<QtProperty *>(property)).val; + if (m_alignValues.contains(const_cast<QtProperty *>(property))) + return m_alignValues.value(const_cast<QtProperty *>(property)); + if (m_paletteValues.contains(const_cast<QtProperty *>(property))) + return m_paletteValues.value(const_cast<QtProperty *>(property)).val; + if (m_iconValues.contains(const_cast<QtProperty *>(property))) + return qVariantFromValue(m_iconValues.value(const_cast<QtProperty *>(property))); + if (m_pixmapValues.contains(const_cast<QtProperty *>(property))) + return qVariantFromValue(m_pixmapValues.value(const_cast<QtProperty *>(property))); + if (m_stringValues.contains(const_cast<QtProperty *>(property))) + return qVariantFromValue(m_stringValues.value(const_cast<QtProperty *>(property))); + if (m_keySequenceValues.contains(const_cast<QtProperty *>(property))) + return qVariantFromValue(m_keySequenceValues.value(const_cast<QtProperty *>(property))); + if (m_uintValues.contains(const_cast<QtProperty *>(property))) + return m_uintValues.value(const_cast<QtProperty *>(property)); + if (m_longLongValues.contains(const_cast<QtProperty *>(property))) + return m_longLongValues.value(const_cast<QtProperty *>(property)); + if (m_uLongLongValues.contains(const_cast<QtProperty *>(property))) + return m_uLongLongValues.value(const_cast<QtProperty *>(property)); + if (m_urlValues.contains(const_cast<QtProperty *>(property))) + return m_urlValues.value(const_cast<QtProperty *>(property)); + if (m_byteArrayValues.contains(const_cast<QtProperty *>(property))) + return m_byteArrayValues.value(const_cast<QtProperty *>(property)); + if (m_stringListValues.contains(const_cast<QtProperty *>(property))) + return m_stringListValues.value(const_cast<QtProperty *>(property)); + + QVariant rc; + if (m_brushManager.value(property, &rc)) + return rc; + return QtVariantPropertyManager::value(property); +} + +int DesignerPropertyManager::valueType(int propertyType) const +{ + switch (propertyType) { + case QVariant::Palette: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Url: + case QVariant::ByteArray: + case QVariant::StringList: + case QVariant::Brush: + return propertyType; + default: + break; + } + if (propertyType == designerFlagTypeId()) + return QVariant::UInt; + if (propertyType == designerAlignmentTypeId()) + return QVariant::UInt; + if (propertyType == designerPixmapTypeId()) + return propertyType; + if (propertyType == designerIconTypeId()) + return propertyType; + if (propertyType == designerStringTypeId()) + return propertyType; + if (propertyType == designerKeySequenceTypeId()) + return propertyType; + return QtVariantPropertyManager::valueType(propertyType); +} + +void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &value) +{ + const PropertyFlagDataMap::iterator fit = m_flagValues.find(property); + + if (fit != m_flagValues.end()) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(); + + FlagData data = fit.value(); + if (data.val == v) + return; + + // set Value + + const QList<uint> values = data.values; + const QList<QtProperty *> subFlags = m_propertyToFlags.value(property); + const int subFlagCount = subFlags.count(); + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint val = values.at(i); + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + subFlag->setValue(checked); + } + + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint val = values.at(i); + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + bool enabled = true; + if (val == 0) { + if (checked) + enabled = false; + } else if (bitCount(val) > 1) { + // Disabled if all flags contained in the mask are checked + uint currentMask = 0; + for (int j = 0; j < subFlagCount; ++j) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(j)); + if (bitCount(values.at(j)) == 1) + currentMask |= subFlag->value().toBool() ? values.at(j) : 0; + } + if ((currentMask & values.at(i)) == values.at(i)) + enabled = false; + } + subFlag->setEnabled(enabled); + } + + data.val = v; + fit.value() = data; + + emit QtVariantPropertyManager::valueChanged(property, data.val); + emit propertyChanged(property); + + return; + } else if (m_alignValues.contains(property)) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(); + + uint val = m_alignValues.value(property); + + if (val == v) + return; + + QtVariantProperty *alignH = variantProperty(m_propertyToAlignH.value(property)); + QtVariantProperty *alignV = variantProperty(m_propertyToAlignV.value(property)); + + if (alignH) + alignH->setValue(alignToIndexH(v)); + if (alignV) + alignV->setValue(alignToIndexV(v)); + + m_alignValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_stringValues.contains(property)) { + if (value.userType() != designerStringTypeId()) + return; + + const PropertySheetStringValue v = qVariantValue<PropertySheetStringValue>(value); + + const PropertySheetStringValue val = m_stringValues.value(property); + + if (val == v) + return; + + QtVariantProperty *comment = variantProperty(m_stringToComment.value(property)); + QtVariantProperty *translatable = variantProperty(m_stringToTranslatable.value(property)); + QtVariantProperty *disambiguation = variantProperty(m_stringToDisambiguation.value(property)); + + if (comment) + comment->setValue(v.comment()); + if (translatable) + translatable->setValue(v.translatable()); + if (disambiguation) + disambiguation->setValue(v.disambiguation()); + + m_stringValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(v)); + emit propertyChanged(property); + + return; + } else if (m_keySequenceValues.contains(property)) { + if (value.userType() != designerKeySequenceTypeId()) + return; + + const PropertySheetKeySequenceValue v = qVariantValue<PropertySheetKeySequenceValue>(value); + + const PropertySheetKeySequenceValue val = m_keySequenceValues.value(property); + + if (val == v) + return; + + QtVariantProperty *comment = variantProperty(m_keySequenceToComment.value(property)); + QtVariantProperty *translatable = variantProperty(m_keySequenceToTranslatable.value(property)); + QtVariantProperty *disambiguation = variantProperty(m_keySequenceToDisambiguation.value(property)); + + if (comment) + comment->setValue(v.comment()); + if (translatable) + translatable->setValue(v.translatable()); + if (disambiguation) + disambiguation->setValue(v.disambiguation()); + + m_keySequenceValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(v)); + emit propertyChanged(property); + + return; + } else if (m_paletteValues.contains(property)) { + if (value.type() != QVariant::Palette && !value.canConvert(QVariant::Palette)) + return; + + QPalette p = qVariantValue<QPalette>(value); + + PaletteData data = m_paletteValues.value(property); + + const uint mask = p.resolve(); + p = p.resolve(data.superPalette); + p.resolve(mask); + + if (data.val == p && data.val.resolve() == p.resolve()) + return; + + data.val = p; + m_paletteValues[property] = data; + + emit QtVariantPropertyManager::valueChanged(property, data.val); + emit propertyChanged(property); + + return; + } else if (m_iconValues.contains(property)) { + if (value.userType() != designerIconTypeId()) + return; + + const PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(value); + + const PropertySheetIconValue oldIcon = m_iconValues.value(property); + if (icon == oldIcon) + return; + + m_iconValues[property] = icon; + + QIcon defaultIcon = m_defaultIcons.value(property); + if (!icon.paths().isEmpty()) { + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow); + if (fwb) + defaultIcon = fwb->iconCache()->icon(icon); + } + + QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> iconPaths = icon.paths(); + + QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> subProperties = m_propertyToIconSubProperties.value(property); + QMapIterator<QPair<QIcon::Mode, QIcon::State>, QtProperty *> itSub(subProperties); + while (itSub.hasNext()) { + const QPair<QIcon::Mode, QIcon::State> pair = itSub.next().key(); + QtVariantProperty *subProperty = variantProperty(itSub.value()); + bool hasPath = iconPaths.contains(pair); + subProperty->setModified(hasPath); + subProperty->setValue(qVariantFromValue(iconPaths.value(pair))); + subProperty->setAttribute(QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(icon)); + emit propertyChanged(property); + + QString toolTip; + const QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue>::ConstIterator itNormalOff = + iconPaths.constFind(qMakePair(QIcon::Normal, QIcon::Off)); + if (itNormalOff != iconPaths.constEnd()) + toolTip = itNormalOff.value().path(); + property->setToolTip(toolTip); + + return; + } else if (m_pixmapValues.contains(property)) { + if (value.userType() != designerPixmapTypeId()) + return; + + const PropertySheetPixmapValue pixmap = qVariantValue<PropertySheetPixmapValue>(value); + + const PropertySheetPixmapValue oldPixmap = m_pixmapValues.value(property); + if (pixmap == oldPixmap) + return; + + m_pixmapValues[property] = pixmap; + + emit QtVariantPropertyManager::valueChanged(property, qVariantFromValue(pixmap)); + emit propertyChanged(property); + + property->setToolTip(pixmap.path()); + + return; + } else if (m_uintValues.contains(property)) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(0); + + const uint oldValue = m_uintValues.value(property); + if (v == oldValue) + return; + + m_uintValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_longLongValues.contains(property)) { + if (value.type() != QVariant::LongLong && !value.canConvert(QVariant::LongLong)) + return; + + const qlonglong v = value.toLongLong(0); + + const qlonglong oldValue = m_longLongValues.value(property); + if (v == oldValue) + return; + + m_longLongValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_uLongLongValues.contains(property)) { + if (value.type() != QVariant::ULongLong && !value.canConvert(QVariant::ULongLong)) + return; + + qulonglong v = value.toULongLong(0); + + qulonglong oldValue = m_uLongLongValues.value(property); + if (v == oldValue) + return; + + m_uLongLongValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_urlValues.contains(property)) { + if (value.type() != QVariant::Url && !value.canConvert(QVariant::Url)) + return; + + const QUrl v = value.toUrl(); + + const QUrl oldValue = m_urlValues.value(property); + if (v == oldValue) + return; + + m_urlValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_byteArrayValues.contains(property)) { + if (value.type() != QVariant::ByteArray && !value.canConvert(QVariant::ByteArray)) + return; + + const QByteArray v = value.toByteArray(); + + const QByteArray oldValue = m_byteArrayValues.value(property); + if (v == oldValue) + return; + + m_byteArrayValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_stringListValues.contains(property)) { + if (value.type() != QVariant::StringList && !value.canConvert(QVariant::StringList)) + return; + + const QStringList v = value.toStringList(); + + const QStringList oldValue = m_stringListValues.value(property); + if (v == oldValue) + return; + + m_stringListValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } + switch (m_brushManager.setValue(this, property, value)) { + case BrushPropertyManager::Unchanged: + return; + case BrushPropertyManager::Changed: + emit QtVariantPropertyManager::valueChanged(property, value); + emit propertyChanged(property); + return; + default: + break; + } + m_fontManager.setValue(this, property, value); + QtVariantPropertyManager::setValue(property, value); + if (QtVariantPropertyManager::valueType(property) == QVariant::String) + property->setToolTip(DesignerPropertyManager::value(property).toString()); + else if (QtVariantPropertyManager::valueType(property) == designerStringTypeId()) + property->setToolTip(qVariantValue<PropertySheetStringValue>(DesignerPropertyManager::value(property)).value()); + else if (QtVariantPropertyManager::valueType(property) == designerKeySequenceTypeId()) + property->setToolTip(qVariantValue<PropertySheetKeySequenceValue>(DesignerPropertyManager::value(property)).value()); + else if (QtVariantPropertyManager::valueType(property) == QVariant::Bool) + property->setToolTip(QtVariantPropertyManager::valueText(property)); +} + +void DesignerPropertyManager::initializeProperty(QtProperty *property) +{ + m_resetMap[property] = false; + + const int type = propertyType(property); + m_fontManager.preInitializeProperty(property, type, m_resetMap); + switch (type) { + case QVariant::Palette: + m_paletteValues[property] = PaletteData(); + break; + case QVariant::String: + m_stringAttributes[property] = ValidationSingleLine; + m_stringFontAttributes[property] = QApplication::font(); + break; + case QVariant::UInt: + m_uintValues[property] = 0; + break; + case QVariant::LongLong: + m_longLongValues[property] = 0; + break; + case QVariant::ULongLong: + m_uLongLongValues[property] = 0; + break; + case QVariant::Url: + m_urlValues[property] = QUrl(); + break; + case QVariant::ByteArray: + m_byteArrayValues[property] = 0; + break; + case QVariant::StringList: + m_stringListValues[property] = QStringList(); + break; + case QVariant::Brush: + m_brushManager.initializeProperty(this, property, enumTypeId()); + break; + default: + if (type == designerFlagTypeId()) { + m_flagValues[property] = FlagData(); + m_propertyToFlags[property] = QList<QtProperty *>(); + } else if (type == designerAlignmentTypeId()) { + const uint align = Qt::AlignLeft | Qt::AlignVCenter; + m_alignValues[property] = align; + + QtVariantProperty *alignH = addProperty(enumTypeId(), tr("Horizontal")); + QStringList namesH; + namesH << indexHToString(0) << indexHToString(1) << indexHToString(2) << indexHToString(3); + alignH->setAttribute(QLatin1String("enumNames"), namesH); + alignH->setValue(alignToIndexH(align)); + m_propertyToAlignH[property] = alignH; + m_alignHToProperty[alignH] = property; + property->addSubProperty(alignH); + + QtVariantProperty *alignV = addProperty(enumTypeId(), tr("Vertical")); + QStringList namesV; + namesV << indexVToString(0) << indexVToString(1) << indexVToString(2); + alignV->setAttribute(QLatin1String("enumNames"), namesV); + alignV->setValue(alignToIndexV(align)); + m_propertyToAlignV[property] = alignV; + m_alignVToProperty[alignV] = property; + property->addSubProperty(alignV); + } else if (type == designerPixmapTypeId()) { + m_pixmapValues[property] = PropertySheetPixmapValue(); + m_defaultPixmaps[property] = QPixmap(); + } else if (type == designerIconTypeId()) { + m_iconValues[property] = PropertySheetIconValue(); + m_defaultIcons[property] = QIcon(); + + createIconSubProperty(property, QIcon::Normal, QIcon::Off, tr("Normal Off")); + createIconSubProperty(property, QIcon::Normal, QIcon::On, tr("Normal On")); + createIconSubProperty(property, QIcon::Disabled, QIcon::Off, tr("Disabled Off")); + createIconSubProperty(property, QIcon::Disabled, QIcon::On, tr("Disabled On")); + createIconSubProperty(property, QIcon::Active, QIcon::Off, tr("Active Off")); + createIconSubProperty(property, QIcon::Active, QIcon::On, tr("Active On")); + createIconSubProperty(property, QIcon::Selected, QIcon::Off, tr("Selected Off")); + createIconSubProperty(property, QIcon::Selected, QIcon::On, tr("Selected On")); + } else if (type == designerStringTypeId()) { + PropertySheetStringValue val; + m_stringValues[property] = val; + m_stringAttributes[property] = ValidationMultiLine; + m_stringFontAttributes[property] = QApplication::font(); + + QtVariantProperty *translatable = addProperty(QVariant::Bool, tr("translatable")); + translatable->setValue(val.translatable()); + m_stringToTranslatable[property] = translatable; + m_translatableToString[translatable] = property; + property->addSubProperty(translatable); + + QtVariantProperty *disambiguation = addProperty(QVariant::String, tr("disambiguation")); + disambiguation->setValue(val.disambiguation()); + m_stringToDisambiguation[property] = disambiguation; + m_disambiguationToString[disambiguation] = property; + property->addSubProperty(disambiguation); + + QtVariantProperty *comment = addProperty(QVariant::String, tr("comment")); + comment->setValue(val.comment()); + m_stringToComment[property] = comment; + m_commentToString[comment] = property; + property->addSubProperty(comment); + } else if (type == designerKeySequenceTypeId()) { + PropertySheetKeySequenceValue val; + m_keySequenceValues[property] = val; + + QtVariantProperty *translatable = addProperty(QVariant::Bool, tr("translatable")); + translatable->setValue(val.translatable()); + m_keySequenceToTranslatable[property] = translatable; + m_translatableToKeySequence[translatable] = property; + property->addSubProperty(translatable); + + QtVariantProperty *disambiguation = addProperty(QVariant::String, tr("disambiguation")); + disambiguation->setValue(val.disambiguation()); + m_keySequenceToDisambiguation[property] = disambiguation; + m_disambiguationToKeySequence[disambiguation] = property; + property->addSubProperty(disambiguation); + + QtVariantProperty *comment = addProperty(QVariant::String, tr("comment")); + comment->setValue(val.comment()); + m_keySequenceToComment[property] = comment; + m_commentToKeySequence[comment] = property; + property->addSubProperty(comment); + } + } + + QtVariantPropertyManager::initializeProperty(property); + m_fontManager.postInitializeProperty(this, property, type, DesignerPropertyManager::enumTypeId()); + if (type == QVariant::Double) + setAttribute(property, QLatin1String("decimals"), 6); +} + +void DesignerPropertyManager::createIconSubProperty(QtProperty *iconProperty, QIcon::Mode mode, QIcon::State state, const QString &subName) +{ + QPair<QIcon::Mode, QIcon::State> pair = qMakePair(mode, state); + QtVariantProperty *subProp = addProperty(DesignerPropertyManager::designerPixmapTypeId(), subName); + m_propertyToIconSubProperties[iconProperty][pair] = subProp; + m_iconSubPropertyToState[subProp] = pair; + m_iconSubPropertyToProperty[subProp] = iconProperty; + m_resetMap[subProp] = true; + iconProperty->addSubProperty(subProp); +} + +void DesignerPropertyManager::uninitializeProperty(QtProperty *property) +{ + m_resetMap.remove(property); + + QListIterator<QtProperty *> itProp(m_propertyToFlags[property]); + while (itProp.hasNext()) { + QtProperty *prop = itProp.next(); + if (prop) { + delete prop; + m_flagToProperty.remove(prop); + } + } + m_propertyToFlags.remove(property); + m_flagValues.remove(property); + + QtProperty *alignH = m_propertyToAlignH.value(property); + if (alignH) { + delete alignH; + m_alignHToProperty.remove(alignH); + } + QtProperty *alignV = m_propertyToAlignV.value(property); + if (alignV) { + delete alignV; + m_alignVToProperty.remove(alignV); + } + + QtProperty *stringComment = m_stringToComment.value(property); + if (stringComment) { + delete stringComment; + m_stringToComment.remove(stringComment); + } + + QtProperty *stringTranslatable = m_stringToTranslatable.value(property); + if (stringTranslatable) { + delete stringTranslatable; + m_stringToTranslatable.remove(stringTranslatable); + } + + QtProperty *stringDisambiguation = m_stringToDisambiguation.value(property); + if (stringDisambiguation) { + delete stringDisambiguation; + m_stringToDisambiguation.remove(stringDisambiguation); + } + + QtProperty *keySequenceComment = m_keySequenceToComment.value(property); + if (keySequenceComment) { + delete keySequenceComment; + m_keySequenceToComment.remove(keySequenceComment); + } + + QtProperty *keySequenceTranslatable = m_keySequenceToTranslatable.value(property); + if (keySequenceTranslatable) { + delete keySequenceTranslatable; + m_keySequenceToTranslatable.remove(keySequenceTranslatable); + } + + QtProperty *keySequenceDisambiguation = m_keySequenceToDisambiguation.value(property); + if (keySequenceDisambiguation) { + delete keySequenceDisambiguation; + m_keySequenceToDisambiguation.remove(keySequenceDisambiguation); + } + + m_propertyToAlignH.remove(property); + m_propertyToAlignV.remove(property); + + m_stringToComment.remove(property); + m_stringToTranslatable.remove(property); + m_stringToDisambiguation.remove(property); + m_stringValues.remove(property); + m_stringAttributes.remove(property); + m_stringFontAttributes.remove(property); + + m_keySequenceToComment.remove(property); + m_keySequenceToTranslatable.remove(property); + m_keySequenceToDisambiguation.remove(property); + m_keySequenceValues.remove(property); + + m_paletteValues.remove(property); + + m_iconValues.remove(property); + m_defaultIcons.remove(property); + + m_pixmapValues.remove(property); + m_defaultPixmaps.remove(property); + + QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> iconSubProperties = m_propertyToIconSubProperties.value(property); + QMapIterator<QPair<QIcon::Mode, QIcon::State>, QtProperty *> itIcon(iconSubProperties); + while (itIcon.hasNext()) { + QtProperty *subIcon = itIcon.next().value(); + delete subIcon; + m_iconSubPropertyToState.remove(subIcon); + m_iconSubPropertyToProperty.remove(subIcon); + } + m_propertyToIconSubProperties.remove(property); + m_iconSubPropertyToState.remove(property); + m_iconSubPropertyToProperty.remove(property); + + m_uintValues.remove(property); + m_longLongValues.remove(property); + m_uLongLongValues.remove(property); + m_urlValues.remove(property); + m_byteArrayValues.remove(property); + m_stringListValues.remove(property); + + m_fontManager.uninitializeProperty(property); + m_brushManager.uninitializeProperty(property); + + QtVariantPropertyManager::uninitializeProperty(property); +} + + +bool DesignerPropertyManager::resetFontSubProperty(QtProperty *property) +{ + return m_fontManager.resetFontSubProperty(this, property); +} + +bool DesignerPropertyManager::resetIconSubProperty(QtProperty *property) +{ + if (!m_iconSubPropertyToProperty.contains(property)) + return false; + + if (!m_pixmapValues.contains(property)) + return false; + + QtVariantProperty *pixmapProperty = variantProperty(property); + pixmapProperty->setValue(qVariantFromValue(PropertySheetPixmapValue())); + return true; +} + +// -------- DesignerEditorFactory +DesignerEditorFactory::DesignerEditorFactory(QDesignerFormEditorInterface *core, QObject *parent) : + QtVariantEditorFactory(parent), + m_resetDecorator(new ResetDecorator(this)), + m_changingPropertyValue(false), + m_core(core), + m_spacing(-1) +{ + connect(m_resetDecorator, SIGNAL(resetProperty(QtProperty*)), this, SIGNAL(resetProperty(QtProperty*))); +} + +DesignerEditorFactory::~DesignerEditorFactory() +{ +} + +void DesignerEditorFactory::setSpacing(int spacing) +{ + m_spacing = spacing; + m_resetDecorator->setSpacing(spacing); +} + +void DesignerEditorFactory::setFormWindowBase(qdesigner_internal::FormWindowBase *fwb) +{ + m_fwb = fwb; + DesignerPixmapCache *cache = 0; + if (fwb) + cache = fwb->pixmapCache(); + QMapIterator<PixmapEditor *, QtProperty *> itPixmapEditor(m_editorToPixmapProperty); + while (itPixmapEditor.hasNext()) { + PixmapEditor *pe = itPixmapEditor.next().key(); + pe->setPixmapCache(cache); + } + QMapIterator<PixmapEditor *, QtProperty *> itIconEditor(m_editorToIconProperty); + while (itIconEditor.hasNext()) { + PixmapEditor *pe = itIconEditor.next().key(); + pe->setPixmapCache(cache); + } +} + +void DesignerEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager) +{ + m_resetDecorator->connectPropertyManager(manager); + connect(manager, SIGNAL(attributeChanged(QtProperty*,QString,QVariant)), + this, SLOT(slotAttributeChanged(QtProperty*,QString,QVariant))); + connect(manager, SIGNAL(valueChanged(QtProperty*,QVariant)), + this, SLOT(slotValueChanged(QtProperty*,QVariant))); + connect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); + QtVariantEditorFactory::connectPropertyManager(manager); +} + +void DesignerEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager) +{ + m_resetDecorator->disconnectPropertyManager(manager); + disconnect(manager, SIGNAL(attributeChanged(QtProperty*,QString,QVariant)), + this, SLOT(slotAttributeChanged(QtProperty*,QString,QVariant))); + disconnect(manager, SIGNAL(valueChanged(QtProperty*,QVariant)), + this, SLOT(slotValueChanged(QtProperty*,QVariant))); + disconnect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); + QtVariantEditorFactory::disconnectPropertyManager(manager); +} + +// A helper that calls a setter with a value on a pointer list of editor objects. +// Could use QList<Editor*> instead of EditorContainer/Editor, but that crashes VS 6. +template <class EditorContainer, class Editor, class SetterParameter, class Value> +static inline void applyToEditors(const EditorContainer &list, void (Editor::*setter)(SetterParameter), const Value &value) +{ + typedef Q_TYPENAME EditorContainer::const_iterator ListIterator; + if (list.empty()) { + return; + } + const ListIterator end = list.constEnd(); + for (ListIterator it = list.constBegin(); it != end; ++it) { + Editor &editor = *(*it); + (editor.*setter)(value); + } +} + +void DesignerEditorFactory::slotAttributeChanged(QtProperty *property, const QString &attribute, const QVariant &value) +{ + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + if (type == DesignerPropertyManager::designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) { + const QPixmap pixmap = qvariant_cast<QPixmap>(value); + applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setDefaultPixmap, pixmap); + } else if (type == DesignerPropertyManager::designerStringTypeId() || type == QVariant::String) { + if (attribute == QLatin1String(validationModesAttributeC)) { + const TextPropertyValidationMode validationMode = static_cast<TextPropertyValidationMode>(value.toInt()); + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setTextPropertyValidationMode, validationMode); + } + if (attribute == QLatin1String(fontAttributeC)) { + const QFont font = qvariant_cast<QFont>(value); + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setRichTextDefaultFont, font); + } + } else if (type == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) { + const QPalette palette = qvariant_cast<QPalette>(value); + applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setSuperPalette, palette); + } +} + +void DesignerEditorFactory::slotPropertyChanged(QtProperty *property) +{ + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + if (type == DesignerPropertyManager::designerIconTypeId()) { + QPixmap defaultPixmap; + if (!property->isModified()) + defaultPixmap = qvariant_cast<QIcon>(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC))).pixmap(16, 16); + else if (m_fwb) + defaultPixmap = m_fwb->iconCache()->icon(qVariantValue<PropertySheetIconValue>(manager->value(property))).pixmap(16, 16); + QList<PixmapEditor *> editors = m_iconPropertyToEditors.value(property); + QListIterator<PixmapEditor *> it(editors); + while (it.hasNext()) { + PixmapEditor *editor = it.next(); + editor->setDefaultPixmap(defaultPixmap); + } + } +} + +void DesignerEditorFactory::slotValueChanged(QtProperty *property, const QVariant &value) +{ + if (m_changingPropertyValue) + return; + + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + switch (type) { + case QVariant::String: + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, value.toString()); + break; + case QVariant::Palette: + applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setPalette, qvariant_cast<QPalette>(value)); + break; + case QVariant::UInt: + applyToEditors(m_uintPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toUInt())); + break; + case QVariant::LongLong: + applyToEditors(m_longLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toLongLong())); + break; + case QVariant::ULongLong: + applyToEditors(m_uLongLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toULongLong())); + break; + case QVariant::Url: + applyToEditors(m_urlPropertyToEditors.value(property), &TextEditor::setText, value.toUrl().toString()); + break; + case QVariant::ByteArray: + applyToEditors(m_byteArrayPropertyToEditors.value(property), &TextEditor::setText, QString::fromUtf8(value.toByteArray())); + break; + case QVariant::StringList: + applyToEditors(m_stringListPropertyToEditors.value(property), &StringListEditorButton::setStringList, value.toStringList()); + break; + default: + if (type == DesignerPropertyManager::designerIconTypeId()) + applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setPath, qVariantValue<PropertySheetIconValue>(value).pixmap(QIcon::Normal, QIcon::Off).path()); + else if (type == DesignerPropertyManager::designerPixmapTypeId()) + applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setPath, qVariantValue<PropertySheetPixmapValue>(value).path()); + else if (type == DesignerPropertyManager::designerStringTypeId()) + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, qVariantValue<PropertySheetStringValue>(value).value()); + else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) + applyToEditors(m_keySequencePropertyToEditors.value(property), &QtKeySequenceEdit::setKeySequence, qVariantValue<PropertySheetKeySequenceValue>(value).value()); + break; + } +} + +TextEditor *DesignerEditorFactory::createTextEditor(QWidget *parent, TextPropertyValidationMode vm, const QString &value) +{ + TextEditor *rc = new TextEditor(m_core, parent); + rc->setText(value); + rc->setSpacing(m_spacing); + rc->setTextPropertyValidationMode(vm); + connect(rc, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + return rc; +} + +QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QWidget *editor = 0; + const int type = manager->propertyType(property); + switch (type) { + case QVariant::Bool: { + editor = QtVariantEditorFactory::createEditor(manager, property, parent); + QtBoolEdit *boolEdit = qobject_cast<QtBoolEdit *>(editor); + if (boolEdit) + boolEdit->setTextVisible(false); + } + break; + case QVariant::String: { + const TextPropertyValidationMode tvm = static_cast<TextPropertyValidationMode>(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); + TextEditor *ed = createTextEditor(parent, tvm, manager->value(property).toString()); + const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); + if (richTextDefaultFont.type() == QVariant::Font) + ed->setRichTextDefaultFont(qvariant_cast<QFont>(richTextDefaultFont)); + m_stringPropertyToEditors[property].append(ed); + m_editorToStringProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotStringTextChanged(QString))); + editor = ed; + } + break; + case QVariant::Palette: { + PaletteEditorButton *ed = new PaletteEditorButton(m_core, qvariant_cast<QPalette>(manager->value(property)), parent); + ed->setSuperPalette(qvariant_cast<QPalette>(manager->attributeValue(property, QLatin1String(superPaletteAttributeC)))); + m_palettePropertyToEditors[property].append(ed); + m_editorToPaletteProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(paletteChanged(QPalette)), this, SLOT(slotPaletteChanged(QPalette))); + editor = ed; + } + break; + case QVariant::UInt: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QULongLongValidator(0, UINT_MAX, ed)); + ed->setText(QString::number(manager->value(property).toUInt())); + m_uintPropertyToEditors[property].append(ed); + m_editorToUintProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotUintChanged(QString))); + editor = ed; + } + break; + case QVariant::LongLong: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QLongLongValidator(ed)); + ed->setText(QString::number(manager->value(property).toLongLong())); + m_longLongPropertyToEditors[property].append(ed); + m_editorToLongLongProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotLongLongChanged(QString))); + editor = ed; + } + break; + case QVariant::ULongLong: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QULongLongValidator(ed)); + ed->setText(QString::number(manager->value(property).toULongLong())); + m_uLongLongPropertyToEditors[property].append(ed); + m_editorToULongLongProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotULongLongChanged(QString))); + editor = ed; + } + break; + case QVariant::Url: { + TextEditor *ed = createTextEditor(parent, ValidationURL, manager->value(property).toUrl().toString()); + ed->setUpdateMode(TextPropertyEditor::UpdateOnFinished); + m_urlPropertyToEditors[property].append(ed); + m_editorToUrlProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotUrlChanged(QString))); + editor = ed; + } + break; + case QVariant::ByteArray: { + TextEditor *ed = createTextEditor(parent, ValidationMultiLine, QString::fromUtf8(manager->value(property).toByteArray())); + m_byteArrayPropertyToEditors[property].append(ed); + m_editorToByteArrayProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotByteArrayChanged(QString))); + editor = ed; + } + break; + case QVariant::StringList: { + StringListEditorButton *ed = new StringListEditorButton(manager->value(property).toStringList(), parent); + m_stringListPropertyToEditors[property].append(ed); + m_editorToStringListProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(stringListChanged(QStringList)), this, SLOT(slotStringListChanged(QStringList))); + editor = ed; + } + break; + default: + if (type == DesignerPropertyManager::designerPixmapTypeId()) { + PixmapEditor *ed = new PixmapEditor(m_core, parent); + ed->setPixmapCache(m_fwb->pixmapCache()); + ed->setPath(qvariant_cast<PropertySheetPixmapValue>(manager->value(property)).path()); + ed->setDefaultPixmap(qvariant_cast<QPixmap>(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC)))); + ed->setSpacing(m_spacing); + m_pixmapPropertyToEditors[property].append(ed); + m_editorToPixmapProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + connect(ed, SIGNAL(pathChanged(const QString &)), this, SLOT(slotPixmapChanged(const QString &))); + editor = ed; + } else if (type == DesignerPropertyManager::designerIconTypeId()) { + PixmapEditor *ed = new PixmapEditor(m_core, parent); + ed->setPixmapCache(m_fwb->pixmapCache()); + PropertySheetIconValue value = qvariant_cast<PropertySheetIconValue>(manager->value(property)); + ed->setPath(value.pixmap(QIcon::Normal, QIcon::Off).path()); + QPixmap defaultPixmap; + if (!property->isModified()) + defaultPixmap = qvariant_cast<QIcon>(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC))).pixmap(16, 16); + else if (m_fwb) + defaultPixmap = m_fwb->iconCache()->icon(value).pixmap(16, 16); + ed->setDefaultPixmap(defaultPixmap); + ed->setSpacing(m_spacing); + m_iconPropertyToEditors[property].append(ed); + m_editorToIconProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + connect(ed, SIGNAL(pathChanged(const QString &)), this, SLOT(slotIconChanged(const QString &))); + editor = ed; + } else if (type == DesignerPropertyManager::designerStringTypeId()) { + const TextPropertyValidationMode tvm = static_cast<TextPropertyValidationMode>(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); + TextEditor *ed = createTextEditor(parent, tvm, qVariantValue<PropertySheetStringValue>(manager->value(property)).value()); + const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); + if (richTextDefaultFont.type() == QVariant::Font) + ed->setRichTextDefaultFont(qvariant_cast<QFont>(richTextDefaultFont)); + m_stringPropertyToEditors[property].append(ed); + m_editorToStringProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotStringTextChanged(QString))); + editor = ed; + } else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) { + QtKeySequenceEdit *ed = new QtKeySequenceEdit(parent); + ed->setKeySequence(qVariantValue<PropertySheetKeySequenceValue>(manager->value(property)).value()); + m_keySequencePropertyToEditors[property].append(ed); + m_editorToKeySequenceProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); + connect(ed, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(slotKeySequenceChanged(QKeySequence))); + editor = ed; + } else { + editor = QtVariantEditorFactory::createEditor(manager, property, parent); + } + break; + } + return m_resetDecorator->editor(editor, + manager->variantProperty(property)->attributeValue(QLatin1String(resettableAttributeC)).toBool(), + manager, property, parent); +} + +template <class Editor> +bool removeEditor(QObject *object, + QMap<QtProperty *, QList<Editor> > *propertyToEditors, + QMap<Editor, QtProperty *> *editorToProperty) +{ + if (!propertyToEditors) + return false; + if (!editorToProperty) + return false; + QMapIterator<Editor, QtProperty *> it(*editorToProperty); + while (it.hasNext()) { + Editor editor = it.next().key(); + if (editor == object) { + QtProperty *prop = it.value(); + (*propertyToEditors)[prop].removeAll(editor); + if ((*propertyToEditors)[prop].count() == 0) + propertyToEditors->remove(prop); + editorToProperty->remove(editor); + return true; + } + } + return false; +} + +void DesignerEditorFactory::slotEditorDestroyed(QObject *object) +{ + if (removeEditor(object, &m_stringPropertyToEditors, &m_editorToStringProperty)) + return; + if (removeEditor(object, &m_keySequencePropertyToEditors, &m_editorToKeySequenceProperty)) + return; + if (removeEditor(object, &m_palettePropertyToEditors, &m_editorToPaletteProperty)) + return; + if (removeEditor(object, &m_pixmapPropertyToEditors, &m_editorToPixmapProperty)) + return; + if (removeEditor(object, &m_iconPropertyToEditors, &m_editorToIconProperty)) + return; + if (removeEditor(object, &m_uintPropertyToEditors, &m_editorToUintProperty)) + return; + if (removeEditor(object, &m_longLongPropertyToEditors, &m_editorToLongLongProperty)) + return; + if (removeEditor(object, &m_uLongLongPropertyToEditors, &m_editorToULongLongProperty)) + return; + if (removeEditor(object, &m_urlPropertyToEditors, &m_editorToUrlProperty)) + return; + if (removeEditor(object, &m_byteArrayPropertyToEditors, &m_editorToByteArrayProperty)) + return; + if (removeEditor(object, &m_stringListPropertyToEditors, &m_editorToStringListProperty)) + return; +} + +template<class Editor> +bool updateManager(QtVariantEditorFactory *factory, bool *changingPropertyValue, + const QMap<Editor, QtProperty *> &editorToProperty, QWidget *editor, const QVariant &value) +{ + if (!editor) + return false; + QMapIterator<Editor, QtProperty *> it(editorToProperty); + while (it.hasNext()) { + if (it.next().key() == editor) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = factory->propertyManager(prop); + *changingPropertyValue = true; + manager->variantProperty(prop)->setValue(value); + *changingPropertyValue = false; + return true; + } + } + return false; +} + +void DesignerEditorFactory::slotUintChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToUintProperty, qobject_cast<QWidget *>(sender()), value.toUInt()); +} + +void DesignerEditorFactory::slotLongLongChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToLongLongProperty, qobject_cast<QWidget *>(sender()), value.toLongLong()); +} + +void DesignerEditorFactory::slotULongLongChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToULongLongProperty, qobject_cast<QWidget *>(sender()), value.toULongLong()); +} + +void DesignerEditorFactory::slotUrlChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToUrlProperty, qobject_cast<QWidget *>(sender()), QUrl(value)); +} + +void DesignerEditorFactory::slotByteArrayChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToByteArrayProperty, qobject_cast<QWidget *>(sender()), value.toUtf8()); +} + +void DesignerEditorFactory::slotStringTextChanged(const QString &value) +{ + QMapIterator<TextEditor *, QtProperty *> it(m_editorToStringProperty); + while (it.hasNext()) { + if (it.next().key() == sender()) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = propertyManager(prop); + QtVariantProperty *varProp = manager->variantProperty(prop); + QVariant val = varProp->value(); + if (val.userType() == DesignerPropertyManager::designerStringTypeId()) { + PropertySheetStringValue strVal = qVariantValue<PropertySheetStringValue>(val); + strVal.setValue(value); + val = qVariantFromValue(strVal); + } else { + val = QVariant(value); + } + m_changingPropertyValue = true; + manager->variantProperty(prop)->setValue(val); + m_changingPropertyValue = false; + } + } +} + +void DesignerEditorFactory::slotKeySequenceChanged(const QKeySequence &value) +{ + QMapIterator<QtKeySequenceEdit *, QtProperty *> it(m_editorToKeySequenceProperty); + while (it.hasNext()) { + if (it.next().key() == sender()) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = propertyManager(prop); + QtVariantProperty *varProp = manager->variantProperty(prop); + QVariant val = varProp->value(); + if (val.userType() == DesignerPropertyManager::designerKeySequenceTypeId()) { + PropertySheetKeySequenceValue keyVal = qVariantValue<PropertySheetKeySequenceValue>(val); + keyVal.setValue(value); + val = qVariantFromValue(keyVal); + } else { + val = qVariantFromValue(value); + } + m_changingPropertyValue = true; + manager->variantProperty(prop)->setValue(val); + m_changingPropertyValue = false; + } + } +} + +void DesignerEditorFactory::slotPaletteChanged(const QPalette &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToPaletteProperty, qobject_cast<QWidget *>(sender()), qVariantFromValue(value)); +} + +void DesignerEditorFactory::slotPixmapChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToPixmapProperty, qobject_cast<QWidget *>(sender()), + qVariantFromValue(PropertySheetPixmapValue(value))); +} + +void DesignerEditorFactory::slotIconChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToIconProperty, qobject_cast<QWidget *>(sender()), + qVariantFromValue(PropertySheetIconValue(PropertySheetPixmapValue(value)))); +} + +void DesignerEditorFactory::slotStringListChanged(const QStringList &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToStringListProperty, qobject_cast<QWidget *>(sender()), qVariantFromValue(value)); +} + +ResetDecorator::~ResetDecorator() +{ + QList<ResetWidget *> editors = m_resetWidgetToProperty.keys(); + QListIterator<ResetWidget *> it(editors); + while (it.hasNext()) + delete it.next(); +} + +void ResetDecorator::connectPropertyManager(QtAbstractPropertyManager *manager) +{ + connect(manager, SIGNAL(propertyChanged(QtProperty *)), + this, SLOT(slotPropertyChanged(QtProperty *))); +} + +void ResetDecorator::disconnectPropertyManager(QtAbstractPropertyManager *manager) +{ + disconnect(manager, SIGNAL(propertyChanged(QtProperty *)), + this, SLOT(slotPropertyChanged(QtProperty *))); +} + +void ResetDecorator::setSpacing(int spacing) +{ + m_spacing = spacing; +} + +QWidget *ResetDecorator::editor(QWidget *subEditor, bool resettable, QtAbstractPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + Q_UNUSED(manager) + + ResetWidget *resetWidget = 0; + if (resettable) { + resetWidget = new ResetWidget(property, parent); + resetWidget->setSpacing(m_spacing); + resetWidget->setResetEnabled(property->isModified()); + resetWidget->setValueText(property->valueText()); + resetWidget->setValueIcon(property->valueIcon()); + resetWidget->setAutoFillBackground(true); + connect(resetWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(resetWidget, SIGNAL(resetProperty(QtProperty *)), this, SIGNAL(resetProperty(QtProperty *))); + m_createdResetWidgets[property].append(resetWidget); + m_resetWidgetToProperty[resetWidget] = property; + } + if (subEditor) { + if (resetWidget) { + subEditor->setParent(resetWidget); + resetWidget->setWidget(subEditor); + } + } + if (resetWidget) + return resetWidget; + return subEditor; +} + +void ResetDecorator::slotPropertyChanged(QtProperty *property) +{ + QMap<QtProperty *, QList<ResetWidget *> >::ConstIterator prIt = m_createdResetWidgets.constFind(property); + if (prIt == m_createdResetWidgets.constEnd()) + return; + + const QList<ResetWidget *> editors = prIt.value(); + const QList<ResetWidget *>::ConstIterator cend = editors.constEnd(); + for (QList<ResetWidget *>::ConstIterator itEditor = editors.constBegin(); itEditor != cend; ++itEditor) { + ResetWidget *widget = *itEditor; + widget->setResetEnabled(property->isModified()); + widget->setValueText(property->valueText()); + widget->setValueIcon(property->valueIcon()); + } +} + +void ResetDecorator::slotEditorDestroyed(QObject *object) +{ + const QMap<ResetWidget *, QtProperty *>::ConstIterator rcend = m_resetWidgetToProperty.constEnd(); + for (QMap<ResetWidget *, QtProperty *>::ConstIterator itEditor = m_resetWidgetToProperty.constBegin(); itEditor != rcend; ++itEditor) { + if (itEditor.key() == object) { + ResetWidget *editor = itEditor.key(); + QtProperty *property = itEditor.value(); + m_resetWidgetToProperty.remove(editor); + m_createdResetWidgets[property].removeAll(editor); + if (m_createdResetWidgets[property].isEmpty()) + m_createdResetWidgets.remove(property); + return; + } + } +} + +} + +QT_END_NAMESPACE + +#include "designerpropertymanager.moc" diff --git a/tools/designer/src/components/propertyeditor/designerpropertymanager.h b/tools/designer/src/components/propertyeditor/designerpropertymanager.h new file mode 100644 index 0000000..78ab8e6 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/designerpropertymanager.h @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERPROPERTYMANAGER_H +#define DESIGNERPROPERTYMANAGER_H + +#include "qtvariantproperty.h" +#include "brushpropertymanager.h" +#include "fontpropertymanager.h" + +#include <qdesigner_utils_p.h> +#include <shared_enums_p.h> + +#include <QtCore/QUrl> +#include <QtCore/QMap> +#include <QtGui/QFont> +#include <QtGui/QIcon> + +QT_BEGIN_NAMESPACE + +typedef QPair<QString, uint> DesignerIntPair; +typedef QList<DesignerIntPair> DesignerFlagList; + +class QDesignerFormEditorInterface; +class QLineEdit; +class QUrl; +class QtKeySequenceEdit; + +namespace qdesigner_internal +{ + +class ResetWidget; + +class TextEditor; +class PaletteEditorButton; +class PixmapEditor; +class StringListEditorButton; +class FormWindowBase; + +class ResetDecorator : public QObject +{ + Q_OBJECT +public: + ResetDecorator(QObject *parent = 0) : QObject(parent), m_spacing(-1) {} + ~ResetDecorator(); + + void connectPropertyManager(QtAbstractPropertyManager *manager); + QWidget *editor(QWidget *subEditor, bool resettable, QtAbstractPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtAbstractPropertyManager *manager); + void setSpacing(int spacing); +signals: + void resetProperty(QtProperty *property); +private slots: + void slotPropertyChanged(QtProperty *property); + void slotEditorDestroyed(QObject *object); +private: + QMap<QtProperty *, QList<ResetWidget *> > m_createdResetWidgets; + QMap<ResetWidget *, QtProperty *> m_resetWidgetToProperty; + int m_spacing; +}; + +class DesignerPropertyManager : public QtVariantPropertyManager +{ + Q_OBJECT +public: + DesignerPropertyManager(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~DesignerPropertyManager(); + + virtual QStringList attributes(int propertyType) const; + virtual int attributeType(int propertyType, const QString &attribute) const; + + virtual QVariant attributeValue(const QtProperty *property, const QString &attribute) const; + virtual bool isPropertyTypeSupported(int propertyType) const; + virtual QVariant value(const QtProperty *property) const; + virtual int valueType(int propertyType) const; + virtual QString valueText(const QtProperty *property) const; + virtual QIcon valueIcon(const QtProperty *property) const; + + bool resetFontSubProperty(QtProperty *property); + bool resetIconSubProperty(QtProperty *subProperty); + + void reloadResourceProperties(); + + static int designerFlagTypeId(); + static int designerFlagListTypeId(); + static int designerAlignmentTypeId(); + static int designerPixmapTypeId(); + static int designerIconTypeId(); + static int designerStringTypeId(); + static int designerKeySequenceTypeId(); + + void setObject(QObject *object) { m_object = object; } + +public Q_SLOTS: + virtual void setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value); + virtual void setValue(QtProperty *property, const QVariant &value); +Q_SIGNALS: + // sourceOfChange - a subproperty (or just property) which caused a change + //void valueChanged(QtProperty *property, const QVariant &value, QtProperty *sourceOfChange); + void valueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling); +protected: + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private Q_SLOTS: + void slotValueChanged(QtProperty *property, const QVariant &value); + void slotPropertyDestroyed(QtProperty *property); +private: + void createIconSubProperty(QtProperty *iconProperty, QIcon::Mode mode, QIcon::State state, const QString &subName); + + typedef QMap<QtProperty *, bool> PropertyBoolMap; + PropertyBoolMap m_resetMap; + + int bitCount(int mask) const; + struct FlagData + { + FlagData() : val(0) {} + uint val; + DesignerFlagList flags; + QList<uint> values; + }; + typedef QMap<QtProperty *, FlagData> PropertyFlagDataMap; + PropertyFlagDataMap m_flagValues; + typedef QMap<QtProperty *, QList<QtProperty *> > PropertyToPropertyListMap; + PropertyToPropertyListMap m_propertyToFlags; + QMap<QtProperty *, QtProperty *> m_flagToProperty; + + int alignToIndexH(uint align) const; + int alignToIndexV(uint align) const; + uint indexHToAlign(int idx) const; + uint indexVToAlign(int idx) const; + QString indexHToString(int idx) const; + QString indexVToString(int idx) const; + QMap<QtProperty *, uint> m_alignValues; + typedef QMap<QtProperty *, QtProperty *> PropertyToPropertyMap; + PropertyToPropertyMap m_propertyToAlignH; + PropertyToPropertyMap m_propertyToAlignV; + PropertyToPropertyMap m_alignHToProperty; + PropertyToPropertyMap m_alignVToProperty; + + QMap<QtProperty *, QMap<QPair<QIcon::Mode, QIcon::State>, QtProperty *> > m_propertyToIconSubProperties; + QMap<QtProperty *, QPair<QIcon::Mode, QIcon::State> > m_iconSubPropertyToState; + PropertyToPropertyMap m_iconSubPropertyToProperty; + + QMap<QtProperty *, qdesigner_internal::PropertySheetStringValue> m_stringValues; + QMap<QtProperty *, QtProperty *> m_stringToComment; + QMap<QtProperty *, QtProperty *> m_stringToTranslatable; + QMap<QtProperty *, QtProperty *> m_stringToDisambiguation; + + QMap<QtProperty *, QtProperty *> m_commentToString; + QMap<QtProperty *, QtProperty *> m_translatableToString; + QMap<QtProperty *, QtProperty *> m_disambiguationToString; + + QMap<QtProperty *, qdesigner_internal::PropertySheetKeySequenceValue> m_keySequenceValues; + QMap<QtProperty *, QtProperty *> m_keySequenceToComment; + QMap<QtProperty *, QtProperty *> m_keySequenceToTranslatable; + QMap<QtProperty *, QtProperty *> m_keySequenceToDisambiguation; + + QMap<QtProperty *, QtProperty *> m_commentToKeySequence; + QMap<QtProperty *, QtProperty *> m_translatableToKeySequence; + QMap<QtProperty *, QtProperty *> m_disambiguationToKeySequence; + + struct PaletteData + { + QPalette val; + QPalette superPalette; + }; + typedef QMap<QtProperty *, PaletteData> PropertyPaletteDataMap; + PropertyPaletteDataMap m_paletteValues; + + QMap<QtProperty *, qdesigner_internal::PropertySheetPixmapValue> m_pixmapValues; + QMap<QtProperty *, qdesigner_internal::PropertySheetIconValue> m_iconValues; + + QMap<QtProperty *, uint> m_uintValues; + QMap<QtProperty *, qlonglong> m_longLongValues; + QMap<QtProperty *, qulonglong> m_uLongLongValues; + QMap<QtProperty *, QUrl> m_urlValues; + QMap<QtProperty *, QByteArray> m_byteArrayValues; + QMap<QtProperty *, QStringList> m_stringListValues; + + typedef QMap<QtProperty *, int> PropertyIntMap; + PropertyIntMap m_stringAttributes; + typedef QMap<QtProperty *, QFont> PropertyFontMap; + PropertyFontMap m_stringFontAttributes; + + BrushPropertyManager m_brushManager; + FontPropertyManager m_fontManager; + + QMap<QtProperty *, QPixmap> m_defaultPixmaps; + QMap<QtProperty *, QIcon> m_defaultIcons; + + bool m_changingSubValue; + QDesignerFormEditorInterface *m_core; + + QObject *m_object; + + QtProperty *m_sourceOfChange; +}; + +class DesignerEditorFactory : public QtVariantEditorFactory +{ + Q_OBJECT +public: + explicit DesignerEditorFactory(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~DesignerEditorFactory(); + void setSpacing(int spacing); + void setFormWindowBase(FormWindowBase *fwb); +signals: + void resetProperty(QtProperty *property); +protected: + void connectPropertyManager(QtVariantPropertyManager *manager); + QWidget *createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtVariantPropertyManager *manager); +private slots: + void slotEditorDestroyed(QObject *object); + void slotAttributeChanged(QtProperty *property, const QString &attribute, const QVariant &value); + void slotPropertyChanged(QtProperty *property); + void slotValueChanged(QtProperty *property, const QVariant &value); + void slotStringTextChanged(const QString &value); + void slotKeySequenceChanged(const QKeySequence &value); + void slotPaletteChanged(const QPalette &value); + void slotPixmapChanged(const QString &value); + void slotIconChanged(const QString &value); + void slotUintChanged(const QString &value); + void slotLongLongChanged(const QString &value); + void slotULongLongChanged(const QString &value); + void slotUrlChanged(const QString &value); + void slotByteArrayChanged(const QString &value); + void slotStringListChanged(const QStringList &value); +private: + TextEditor *createTextEditor(QWidget *parent, TextPropertyValidationMode vm, const QString &value); + + ResetDecorator *m_resetDecorator; + bool m_changingPropertyValue; + QDesignerFormEditorInterface *m_core; + FormWindowBase *m_fwb; + + int m_spacing; + + QMap<QtProperty *, QList<TextEditor *> > m_stringPropertyToEditors; + QMap<TextEditor *, QtProperty *> m_editorToStringProperty; + QMap<QtProperty *, QList<QtKeySequenceEdit *> > m_keySequencePropertyToEditors; + QMap<QtKeySequenceEdit *, QtProperty *> m_editorToKeySequenceProperty; + QMap<QtProperty *, QList<PaletteEditorButton *> > m_palettePropertyToEditors; + QMap<PaletteEditorButton *, QtProperty *> m_editorToPaletteProperty; + QMap<QtProperty *, QList<PixmapEditor *> > m_pixmapPropertyToEditors; + QMap<PixmapEditor *, QtProperty *> m_editorToPixmapProperty; + QMap<QtProperty *, QList<PixmapEditor *> > m_iconPropertyToEditors; + QMap<PixmapEditor *, QtProperty *> m_editorToIconProperty; + QMap<QtProperty *, QList<QLineEdit *> > m_uintPropertyToEditors; + QMap<QLineEdit *, QtProperty *> m_editorToUintProperty; + QMap<QtProperty *, QList<QLineEdit *> > m_longLongPropertyToEditors; + QMap<QLineEdit *, QtProperty *> m_editorToLongLongProperty; + QMap<QtProperty *, QList<QLineEdit *> > m_uLongLongPropertyToEditors; + QMap<QLineEdit *, QtProperty *> m_editorToULongLongProperty; + QMap<QtProperty *, QList<TextEditor *> > m_urlPropertyToEditors; + QMap<TextEditor *, QtProperty *> m_editorToUrlProperty; + QMap<QtProperty *, QList<TextEditor *> > m_byteArrayPropertyToEditors; + QMap<TextEditor *, QtProperty *> m_editorToByteArrayProperty; + QMap<QtProperty *, QList<StringListEditorButton *> > m_stringListPropertyToEditors; + QMap<StringListEditorButton *, QtProperty *> m_editorToStringListProperty; +}; + +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(DesignerIntPair) +Q_DECLARE_METATYPE(DesignerFlagList) + +#endif + diff --git a/tools/designer/src/components/propertyeditor/fontmapping.xml b/tools/designer/src/components/propertyeditor/fontmapping.xml new file mode 100644 index 0000000..c19f7a3 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/fontmapping.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!--************************************************************************ +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +**************************************************************************--> + +<!DOCTYPE fontmapping +[ +<!ENTITY ce "Windows CE" > +<!ENTITY qe "Qt Embedded" > +]> + +<fontmappings> +<mapping><family>DejaVu Sans</family><display>DejaVu Sans [&qe;]</display></mapping> +<mapping><family>DejaVu Sans</family><display>DejaVu Sans [&qe;]</display></mapping> +<mapping><family>DejaVu Sans</family><display>DejaVu Sans [&qe;]</display></mapping> +<mapping><family>DejaVu Sans</family><display>DejaVu Sans [&qe;]</display></mapping> +<mapping><family>DejaVu Sans Mono</family><display>DejaVu Sans Mono [&qe;]</display></mapping> +<mapping><family>DejaVu Sans Mono</family><display>DejaVu Sans Mono [&qe;]</display></mapping> +<mapping><family>DejaVu Sans Mono</family><display>DejaVu Sans Mono [&qe;]</display></mapping> +<mapping><family>DejaVu Sans Mono</family><display>DejaVu Sans Mono [&qe;]</display></mapping> +<mapping><family>DejaVu Serif</family><display>DejaVu Serif [&qe;]</display></mapping> +<mapping><family>DejaVu Serif</family><display>DejaVu Serif [&qe;]</display></mapping> +<mapping><family>DejaVu Serif</family><display>DejaVu Serif [&qe;]</display></mapping> +<mapping><family>DejaVu Serif</family><display>DejaVu Serif [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans</family><display>Bitstream Vera Sans [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans</family><display>Bitstream Vera Sans [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans</family><display>Bitstream Vera Sans [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans</family><display>Bitstream Vera Sans [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans Mono</family><display>Bitstream Vera Sans Mono [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans Mono</family><display>Bitstream Vera Sans Mono [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans Mono</family><display>Bitstream Vera Sans Mono [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Sans Mono</family><display>Bitstream Vera Sans Mono [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Serif</family><display>Bitstream Vera Serif [&qe;]</display></mapping> +<mapping><family>Bitstream Vera Serif</family><display>Bitstream Vera Serif [&qe;]</display></mapping> +</fontmappings> diff --git a/tools/designer/src/components/propertyeditor/fontpropertymanager.cpp b/tools/designer/src/components/propertyeditor/fontpropertymanager.cpp new file mode 100644 index 0000000..ab980aa --- /dev/null +++ b/tools/designer/src/components/propertyeditor/fontpropertymanager.cpp @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fontpropertymanager.h" +#include "qtpropertymanager.h" +#include "qtvariantproperty.h" +#include "qtpropertybrowserutils_p.h" + +#include <qdesigner_utils_p.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QVariant> +#include <QtCore/QString> +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QTextStream> +#include <QtXml/QXmlStreamReader> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + + static const char *aliasingC[] = { + QT_TRANSLATE_NOOP("FontPropertyManager", "PreferDefault"), + QT_TRANSLATE_NOOP("FontPropertyManager", "NoAntialias"), + QT_TRANSLATE_NOOP("FontPropertyManager", "PreferAntialias") + }; + + FontPropertyManager::FontPropertyManager() : + m_createdFontProperty(0) + { + const int nameCount = sizeof(aliasingC)/sizeof(const char *); + for (int i = 0; i < nameCount; i++) + m_aliasingEnumNames.push_back(QCoreApplication::translate("FontPropertyManager", aliasingC[i])); + + QString errorMessage; + if (!readFamilyMapping(&m_familyMappings, &errorMessage)) { + designerWarning(errorMessage); + } + + } + + void FontPropertyManager::preInitializeProperty(QtProperty *property, + int type, + ResetMap &resetMap) + { + if (m_createdFontProperty) { + PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(m_createdFontProperty); + if (it == m_propertyToFontSubProperties.end()) + it = m_propertyToFontSubProperties.insert(m_createdFontProperty, PropertyList()); + const int index = it.value().size(); + m_fontSubPropertyToFlag.insert(property, index); + it.value().push_back(property); + m_fontSubPropertyToProperty[property] = m_createdFontProperty; + resetMap[property] = true; + } + + if (type == QVariant::Font) + m_createdFontProperty = property; + } + + // Map the font family names to display names retrieved from the XML configuration + static QStringList designerFamilyNames(QStringList families, const FontPropertyManager::NameMap &nm) + { + if (nm.empty()) + return families; + + const FontPropertyManager::NameMap::const_iterator ncend = nm.constEnd(); + const QStringList::iterator end = families.end(); + for (QStringList::iterator it = families.begin(); it != end; ++it) { + const FontPropertyManager::NameMap::const_iterator nit = nm.constFind(*it); + if (nit != ncend) + *it = nit.value(); + } + return families; + } + + void FontPropertyManager::postInitializeProperty(QtVariantPropertyManager *vm, + QtProperty *property, + int type, + int enumTypeId) + { + if (type != QVariant::Font) + return; + + // This will cause a recursion + QtVariantProperty *antialiasing = vm->addProperty(enumTypeId, QCoreApplication::translate("FontPropertyManager", "Antialiasing")); + const QFont font = qVariantValue<QFont>(vm->variantProperty(property)->value()); + + antialiasing->setAttribute(QLatin1String("enumNames"), m_aliasingEnumNames); + antialiasing->setValue(antialiasingToIndex(font.styleStrategy())); + property->addSubProperty(antialiasing); + + m_propertyToAntialiasing[property] = antialiasing; + m_antialiasingToProperty[antialiasing] = property; + // Fiddle family names + if (!m_familyMappings.empty()) { + const PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(m_createdFontProperty); + QtVariantProperty *familyProperty = vm->variantProperty(it.value().front()); + const QString enumNamesAttribute = QLatin1String("enumNames"); + QStringList plainFamilyNames = familyProperty->attributeValue(enumNamesAttribute).toStringList(); + // Did someone load fonts or something? + if (m_designerFamilyNames.size() != plainFamilyNames.size()) + m_designerFamilyNames = designerFamilyNames(plainFamilyNames, m_familyMappings); + familyProperty->setAttribute(enumNamesAttribute, m_designerFamilyNames); + } + // Next + m_createdFontProperty = 0; + } + + bool FontPropertyManager::uninitializeProperty(QtProperty *property) + { + const PropertyToPropertyMap::iterator ait = m_propertyToAntialiasing.find(property); + if (ait != m_propertyToAntialiasing.end()) { + QtProperty *antialiasing = ait.value(); + m_antialiasingToProperty.remove(antialiasing); + m_propertyToAntialiasing.erase(ait); + delete antialiasing; + } + + PropertyToSubPropertiesMap::iterator sit = m_propertyToFontSubProperties.find(property); + if (sit == m_propertyToFontSubProperties.end()) + return false; + + m_propertyToFontSubProperties.erase(sit); + m_fontSubPropertyToFlag.remove(property); + m_fontSubPropertyToProperty.remove(property); + + return true; + } + + void FontPropertyManager::slotPropertyDestroyed(QtProperty *property) + { + removeAntialiasingProperty(property); + } + + void FontPropertyManager::removeAntialiasingProperty(QtProperty *property) + { + const PropertyToPropertyMap::iterator ait = m_antialiasingToProperty.find(property); + if (ait == m_antialiasingToProperty.end()) + return; + m_propertyToAntialiasing[ait.value()] = 0; + m_antialiasingToProperty.erase(ait); + } + + bool FontPropertyManager::resetFontSubProperty(QtVariantPropertyManager *vm, QtProperty *property) + { + const PropertyToPropertyMap::iterator it = m_fontSubPropertyToProperty.find(property); + if (it == m_fontSubPropertyToProperty.end()) + return false; + + QtVariantProperty *fontProperty = vm->variantProperty(it.value()); + + QVariant v = fontProperty->value(); + QFont font = qvariant_cast<QFont>(v); + unsigned mask = font.resolve(); + const unsigned flag = fontFlag(m_fontSubPropertyToFlag.value(property)); + + mask &= ~flag; + font.resolve(mask); + qVariantSetValue(v, font); + fontProperty->setValue(v); + return true; + } + + int FontPropertyManager::antialiasingToIndex(QFont::StyleStrategy antialias) + { + switch (antialias) { + case QFont::PreferDefault: return 0; + case QFont::NoAntialias: return 1; + case QFont::PreferAntialias: return 2; + default: break; + } + return 0; + } + + QFont::StyleStrategy FontPropertyManager::indexToAntialiasing(int idx) + { + switch (idx) { + case 0: return QFont::PreferDefault; + case 1: return QFont::NoAntialias; + case 2: return QFont::PreferAntialias; + } + return QFont::PreferDefault; + } + + unsigned FontPropertyManager::fontFlag(int idx) + { + switch (idx) { + case 0: return QFont::FamilyResolved; + case 1: return QFont::SizeResolved; + case 2: return QFont::WeightResolved; + case 3: return QFont::StyleResolved; + case 4: return QFont::UnderlineResolved; + case 5: return QFont::StrikeOutResolved; + case 6: return QFont::KerningResolved; + case 7: return QFont::StyleStrategyResolved; + } + return 0; + } + + FontPropertyManager::ValueChangedResult FontPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) + { + QtProperty *antialiasingProperty = m_antialiasingToProperty.value(property, 0); + if (!antialiasingProperty) { + if (m_propertyToFontSubProperties.contains(property)) { + updateModifiedState(property, value); + } + return NoMatch; + } + + QtVariantProperty *fontProperty = vm->variantProperty(antialiasingProperty); + const QFont::StyleStrategy newValue = indexToAntialiasing(value.toInt()); + + QFont font = qVariantValue<QFont>(fontProperty->value()); + const QFont::StyleStrategy oldValue = font.styleStrategy(); + if (newValue == oldValue) + return Unchanged; + + font.setStyleStrategy(newValue); + fontProperty->setValue(qVariantFromValue(font)); + return Changed; + } + + void FontPropertyManager::updateModifiedState(QtProperty *property, const QVariant &value) + { + const PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(property); + if (it == m_propertyToFontSubProperties.end()) + return; + + const PropertyList &subProperties = it.value(); + + QFont font = qVariantValue<QFont>(value); + const unsigned mask = font.resolve(); + + const int count = subProperties.size(); + for (int index = 0; index < count; index++) { + const unsigned flag = fontFlag(index); + subProperties.at(index)->setModified(mask & flag); + } + } + + void FontPropertyManager::setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) + { + updateModifiedState(property, value); + + if (QtProperty *antialiasingProperty = m_propertyToAntialiasing.value(property, 0)) { + QtVariantProperty *antialiasing = vm->variantProperty(antialiasingProperty); + if (antialiasing) { + QFont font = qVariantValue<QFont>(value); + antialiasing->setValue(antialiasingToIndex(font.styleStrategy())); + } + } + } + + /* Parse a mappings file of the form: + * <fontmappings> + * <mapping><family>DejaVu Sans</family><display>DejaVu Sans [CE]</display></mapping> + * ... which is used to display on which platforms fonts are available.*/ + + static const char *rootTagC = "fontmappings"; + static const char *mappingTagC = "mapping"; + static const char *familyTagC = "family"; + static const char *displayTagC = "display"; + + static QString msgXmlError(const QXmlStreamReader &r, const QString& fileName) + { + return QString::fromUtf8("An error has been encountered at line %1 of %2: %3:").arg(r.lineNumber()).arg(fileName, r.errorString()); + } + + /* Switch stages when encountering a start element (state table) */ + enum ParseStage { ParseBeginning, ParseWithinRoot, ParseWithinMapping, ParseWithinFamily, + ParseWithinDisplay, ParseError }; + + static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) + { + switch (currentStage) { + case ParseBeginning: + return startElement == QLatin1String(rootTagC) ? ParseWithinRoot : ParseError; + case ParseWithinRoot: + case ParseWithinDisplay: // Next mapping, was in <display> + return startElement == QLatin1String(mappingTagC) ? ParseWithinMapping : ParseError; + case ParseWithinMapping: + return startElement == QLatin1String(familyTagC) ? ParseWithinFamily : ParseError; + case ParseWithinFamily: + return startElement == QLatin1String(displayTagC) ? ParseWithinDisplay : ParseError; + case ParseError: + break; + } + return ParseError; + } + + bool FontPropertyManager::readFamilyMapping(NameMap *rc, QString *errorMessage) + { + rc->clear(); + const QString fileName = QLatin1String(":/trolltech/propertyeditor/fontmapping.xml"); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + *errorMessage = QString::fromUtf8("Unable to open %1: %2").arg(fileName, file.errorString()); + return false; + } + + QXmlStreamReader reader(&file); + QXmlStreamReader::TokenType token; + + QString family; + ParseStage stage = ParseBeginning; + do { + token = reader.readNext(); + switch (token) { + case QXmlStreamReader::Invalid: + *errorMessage = msgXmlError(reader, fileName); + return false; + case QXmlStreamReader::StartElement: + stage = nextStage(stage, reader.name()); + switch (stage) { + case ParseError: + reader.raiseError(QString::fromUtf8("Unexpected element <%1>.").arg(reader.name().toString())); + *errorMessage = msgXmlError(reader, fileName); + return false; + case ParseWithinFamily: + family = reader.readElementText(); + break; + case ParseWithinDisplay: + rc->insert(family, reader.readElementText()); + break; + default: + break; + } + default: + break; + } + } while (token != QXmlStreamReader::EndDocument); + return true; + } + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/fontpropertymanager.h b/tools/designer/src/components/propertyeditor/fontpropertymanager.h new file mode 100644 index 0000000..915dcd9 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/fontpropertymanager.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FONTPROPERTYMANAGER_H +#define FONTPROPERTYMANAGER_H + +#include <QtCore/QMap> +#include <QtCore/QStringList> +#include <QtGui/QFont> + +QT_BEGIN_NAMESPACE + +class QtProperty; +class QtVariantPropertyManager; + +class QString; +class QVariant; + +namespace qdesigner_internal { + +/* FontPropertyManager: A mixin for DesignerPropertyManager that manages font + * properties. Adds an antialiasing subproperty and reset flags/mask handling + * for the other subproperties. It also modifies the font family + * enumeration names, which it reads from an XML mapping file that + * contains annotations indicating the platform the font is available on. */ + +class FontPropertyManager { + Q_DISABLE_COPY(FontPropertyManager) + +public: + FontPropertyManager(); + + typedef QMap<QtProperty *, bool> ResetMap; + typedef QMap<QString, QString> NameMap; + + // Call before QtVariantPropertyManager::initializeProperty. + void preInitializeProperty(QtProperty *property, int type, ResetMap &resetMap); + // Call after QtVariantPropertyManager::initializeProperty. This will trigger + // a recursion for the sub properties + void postInitializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int type, int enumTypeId); + + bool uninitializeProperty(QtProperty *property); + + // Call from QtPropertyManager's propertyDestroyed signal + void slotPropertyDestroyed(QtProperty *property); + + bool resetFontSubProperty(QtVariantPropertyManager *vm, QtProperty *subProperty); + + // Call from slotValueChanged(). + enum ValueChangedResult { NoMatch, Unchanged, Changed }; + ValueChangedResult valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + // Call from setValue() before calling setValue() on QtVariantPropertyManager. + void setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + static bool readFamilyMapping(NameMap *rc, QString *errorMessage); + +private: + typedef QMap<QtProperty *, QtProperty *> PropertyToPropertyMap; + typedef QList<QtProperty *> PropertyList; + typedef QMap<QtProperty *, PropertyList> PropertyToSubPropertiesMap; + + void removeAntialiasingProperty(QtProperty *); + void updateModifiedState(QtProperty *property, const QVariant &value); + static int antialiasingToIndex(QFont::StyleStrategy antialias); + static QFont::StyleStrategy indexToAntialiasing(int idx); + static unsigned fontFlag(int idx); + + PropertyToPropertyMap m_propertyToAntialiasing; + PropertyToPropertyMap m_antialiasingToProperty; + + PropertyToSubPropertiesMap m_propertyToFontSubProperties; + QMap<QtProperty *, int> m_fontSubPropertyToFlag; + PropertyToPropertyMap m_fontSubPropertyToProperty; + QtProperty *m_createdFontProperty; + QStringList m_aliasingEnumNames; + // Font families with Designer annotations + QStringList m_designerFamilyNames; + NameMap m_familyMappings; +}; + +} + +QT_END_NAMESPACE + +#endif // FONTPROPERTYMANAGER_H diff --git a/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp new file mode 100644 index 0000000..b9f0227 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newdynamicpropertydialog.h" +#include "ui_newdynamicpropertydialog.h" +#include <abstractdialoggui_p.h> +#include <qdesigner_propertysheet_p.h> + +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +NewDynamicPropertyDialog::NewDynamicPropertyDialog(QDesignerDialogGuiInterface *dialogGui, + QWidget *parent) : + QDialog(parent), + m_dialogGui(dialogGui), + m_ui(new Ui::NewDynamicPropertyDialog) +{ + m_ui->setupUi(this); + connect(m_ui->m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(nameChanged(QString))); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_ui->m_comboBox->addItem(QLatin1String("String"), QVariant(QVariant::String)); + m_ui->m_comboBox->addItem(QLatin1String("StringList"), QVariant(QVariant::StringList)); + m_ui->m_comboBox->addItem(QLatin1String("Char"), QVariant(QVariant::Char)); + m_ui->m_comboBox->addItem(QLatin1String("ByteArray"), QVariant(QVariant::ByteArray)); + m_ui->m_comboBox->addItem(QLatin1String("Url"), QVariant(QVariant::Url)); + m_ui->m_comboBox->addItem(QLatin1String("Bool"), QVariant(QVariant::Bool)); + m_ui->m_comboBox->addItem(QLatin1String("Int"), QVariant(QVariant::Int)); + m_ui->m_comboBox->addItem(QLatin1String("UInt"), QVariant(QVariant::UInt)); + m_ui->m_comboBox->addItem(QLatin1String("LongLong"), QVariant(QVariant::LongLong)); + m_ui->m_comboBox->addItem(QLatin1String("ULongLong"), QVariant(QVariant::ULongLong)); + m_ui->m_comboBox->addItem(QLatin1String("Double"), QVariant(QVariant::Double)); + m_ui->m_comboBox->addItem(QLatin1String("Size"), QVariant(QVariant::Size)); + m_ui->m_comboBox->addItem(QLatin1String("SizeF"), QVariant(QVariant::SizeF)); + m_ui->m_comboBox->addItem(QLatin1String("Point"), QVariant(QVariant::Point)); + m_ui->m_comboBox->addItem(QLatin1String("PointF"), QVariant(QVariant::PointF)); + m_ui->m_comboBox->addItem(QLatin1String("Rect"), QVariant(QVariant::Rect)); + m_ui->m_comboBox->addItem(QLatin1String("RectF"), QVariant(QVariant::RectF)); + m_ui->m_comboBox->addItem(QLatin1String("Date"), QVariant(QVariant::Date)); + m_ui->m_comboBox->addItem(QLatin1String("Time"), QVariant(QVariant::Time)); + m_ui->m_comboBox->addItem(QLatin1String("DateTime"), QVariant(QVariant::DateTime)); + m_ui->m_comboBox->addItem(QLatin1String("Font"), QVariant(QVariant::Font)); + m_ui->m_comboBox->addItem(QLatin1String("Palette"), QVariant(QVariant::Palette)); + m_ui->m_comboBox->addItem(QLatin1String("Color"), QVariant(QVariant::Color)); + m_ui->m_comboBox->addItem(QLatin1String("Pixmap"), QVariant(QVariant::Pixmap)); + m_ui->m_comboBox->addItem(QLatin1String("Icon"), QVariant(QVariant::Icon)); + m_ui->m_comboBox->addItem(QLatin1String("Cursor"), QVariant(QVariant::Cursor)); + m_ui->m_comboBox->addItem(QLatin1String("SizePolicy"), QVariant(QVariant::SizePolicy)); + m_ui->m_comboBox->addItem(QLatin1String("KeySequence"), QVariant(QVariant::KeySequence)); + + m_ui->m_comboBox->setCurrentIndex(0); // String + setOkButtonEnabled(false); +} + +void NewDynamicPropertyDialog::setOkButtonEnabled(bool e) +{ + m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(e); +} + +NewDynamicPropertyDialog::~NewDynamicPropertyDialog() +{ + delete m_ui; +} + +void NewDynamicPropertyDialog::setReservedNames(const QStringList &names) +{ + m_reservedNames = names; +} + +void NewDynamicPropertyDialog::setPropertyType(QVariant::Type t) +{ + const int index = m_ui->m_comboBox->findData(QVariant(t)); + if (index != -1) + m_ui->m_comboBox->setCurrentIndex(index); +} + +QString NewDynamicPropertyDialog::propertyName() const +{ + return m_ui->m_lineEdit->text(); +} + +QVariant NewDynamicPropertyDialog::propertyValue() const +{ + const int index = m_ui->m_comboBox->currentIndex(); + if (index == -1) + return QVariant(); + return m_ui->m_comboBox->itemData(index); +} + +void NewDynamicPropertyDialog::information(const QString &message) +{ + m_dialogGui->message(this, QDesignerDialogGuiInterface::PropertyEditorMessage, QMessageBox::Information, tr("Set Property Name"), message); +} + +void NewDynamicPropertyDialog::nameChanged(const QString &s) +{ + setOkButtonEnabled(!s.isEmpty()); +} + +bool NewDynamicPropertyDialog::validatePropertyName(const QString& name) +{ + if (m_reservedNames.contains(name)) { + information(tr("The current object already has a property named '%1'.\nPlease select another, unique one.").arg(name)); + return false; + } + if (!QDesignerPropertySheet::internalDynamicPropertiesEnabled() && name.startsWith(QLatin1String("_q_"))) { + information(tr("The '_q_' prefix is reserved for the Qt library.\nPlease select another name.")); + return false; + } + return true; +} + +void NewDynamicPropertyDialog::on_m_buttonBox_clicked(QAbstractButton *btn) +{ + const int role = m_ui->m_buttonBox->buttonRole(btn); + switch (role) { + case QDialogButtonBox::RejectRole: + reject(); + break; + case QDialogButtonBox::AcceptRole: + if (validatePropertyName(propertyName())) + accept(); + break; + } +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.h b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.h new file mode 100644 index 0000000..025f4fd --- /dev/null +++ b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWDYNAMICPROPERTYDIALOG_P_H +#define NEWDYNAMICPROPERTYDIALOG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "propertyeditor_global.h" +#include <QtGui/QDialog> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +class QAbstractButton; +class QDesignerDialogGuiInterface; + +namespace qdesigner_internal { + +namespace Ui +{ + class NewDynamicPropertyDialog; +} + +class QT_PROPERTYEDITOR_EXPORT NewDynamicPropertyDialog: public QDialog +{ + Q_OBJECT +public: + explicit NewDynamicPropertyDialog(QDesignerDialogGuiInterface *dialogGui, QWidget *parent = 0); + ~NewDynamicPropertyDialog(); + + void setReservedNames(const QStringList &names); + void setPropertyType(QVariant::Type t); + + QString propertyName() const; + QVariant propertyValue() const; + +private slots: + + void on_m_buttonBox_clicked(QAbstractButton *btn); + void nameChanged(const QString &); + +private: + bool validatePropertyName(const QString& name); + void setOkButtonEnabled(bool e); + void information(const QString &message); + + QDesignerDialogGuiInterface *m_dialogGui; + Ui::NewDynamicPropertyDialog *m_ui; + QStringList m_reservedNames; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // NEWDYNAMICPROPERTYDIALOG_P_H diff --git a/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.ui b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.ui new file mode 100644 index 0000000..2aa91f3 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/newdynamicpropertydialog.ui @@ -0,0 +1,106 @@ +<ui version="4.0" > + <class>qdesigner_internal::NewDynamicPropertyDialog</class> + <widget class="QDialog" name="qdesigner_internal::NewDynamicPropertyDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>340</width> + <height>118</height> + </rect> + </property> + <property name="windowTitle" > + <string>Create Dynamic Property</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <layout class="QFormLayout" name="formLayout" > + <item row="0" column="1" > + <widget class="QLineEdit" name="m_lineEdit" > + <property name="minimumSize" > + <size> + <width>220</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Property Name</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="QComboBox" name="m_comboBox" /> + </item> + <item> + <spacer name="horizontalSpacer" > + <property name="spacerName" stdset="0" > + <string>horizontalSpacer</string> + </property> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Property Type</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer> + <property name="spacerName" stdset="0" > + <string/> + </property> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="m_buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + <property name="centerButtons" > + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/designer/src/components/propertyeditor/paletteeditor.cpp b/tools/designer/src/components/propertyeditor/paletteeditor.cpp new file mode 100644 index 0000000..b0dc82b --- /dev/null +++ b/tools/designer/src/components/propertyeditor/paletteeditor.cpp @@ -0,0 +1,623 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::PaletteEditor +*/ +/* +TRANSLATOR qdesigner_internal::PaletteModel +*/ + +#include "paletteeditor.h" + +#include <iconloader_p.h> +#include <qtcolorbutton.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QDesignerIconCacheInterface> + +#include <QtCore/QMetaProperty> +#include <QtGui/QPainter> +#include <QtGui/QToolButton> +#include <QtGui/QLabel> +#include <QtGui/QHeaderView> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +enum { BrushRole = 33 }; + +PaletteEditor::PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QDialog(parent), + m_currentColorGroup(QPalette::Active), + m_paletteModel(new PaletteModel(this)), + m_modelUpdated(false), + m_paletteUpdated(false), + m_compute(true), + m_core(core) +{ + ui.setupUi(this); + ui.paletteView->setModel(m_paletteModel); + updatePreviewPalette(); + updateStyledButton(); + ui.paletteView->setModel(m_paletteModel); + ColorDelegate *delegate = new ColorDelegate(core, this); + ui.paletteView->setItemDelegate(delegate); + ui.paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers); + connect(m_paletteModel, SIGNAL(paletteChanged(const QPalette &)), + this, SLOT(paletteChanged(const QPalette &))); + ui.paletteView->setSelectionBehavior(QAbstractItemView::SelectRows); + ui.paletteView->setDragEnabled(true); + ui.paletteView->setDropIndicatorShown(true); + ui.paletteView->setRootIsDecorated(false); + ui.paletteView->setColumnHidden(2, true); + ui.paletteView->setColumnHidden(3, true); +} + +PaletteEditor::~PaletteEditor() +{ +} + +QPalette PaletteEditor::palette() const +{ + return m_editPalette; +} + +void PaletteEditor::setPalette(const QPalette &palette) +{ + m_editPalette = palette; + const uint mask = palette.resolve(); + for (int i = 0; i < (int)QPalette::NColorRoles; i++) { + if (!(mask & (1 << i))) { + m_editPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i), + m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i))); + m_editPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i), + m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i))); + m_editPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i), + m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i))); + } + } + m_editPalette.resolve(mask); + updatePreviewPalette(); + updateStyledButton(); + m_paletteUpdated = true; + if (!m_modelUpdated) + m_paletteModel->setPalette(m_editPalette, m_parentPalette); + m_paletteUpdated = false; +} + +void PaletteEditor::setPalette(const QPalette &palette, const QPalette &parentPalette) +{ + m_parentPalette = parentPalette; + setPalette(palette); +} + +void PaletteEditor::on_buildButton_colorChanged(const QColor &) +{ + buildPalette(); +} + +void PaletteEditor::on_activeRadio_clicked() +{ + m_currentColorGroup = QPalette::Active; + updatePreviewPalette(); +} + +void PaletteEditor::on_inactiveRadio_clicked() +{ + m_currentColorGroup = QPalette::Inactive; + updatePreviewPalette(); +} + +void PaletteEditor::on_disabledRadio_clicked() +{ + m_currentColorGroup = QPalette::Disabled; + updatePreviewPalette(); +} + +void PaletteEditor::on_computeRadio_clicked() +{ + if (m_compute) + return; + ui.paletteView->setColumnHidden(2, true); + ui.paletteView->setColumnHidden(3, true); + m_compute = true; + m_paletteModel->setCompute(true); +} + +void PaletteEditor::on_detailsRadio_clicked() +{ + if (!m_compute) + return; + const int w = ui.paletteView->columnWidth(1); + ui.paletteView->setColumnHidden(2, false); + ui.paletteView->setColumnHidden(3, false); + QHeaderView *header = ui.paletteView->header(); + header->resizeSection(1, w / 3); + header->resizeSection(2, w / 3); + header->resizeSection(3, w / 3); + m_compute = false; + m_paletteModel->setCompute(false); +} + +void PaletteEditor::paletteChanged(const QPalette &palette) +{ + m_modelUpdated = true; + if (!m_paletteUpdated) + setPalette(palette); + m_modelUpdated = false; +} + +void PaletteEditor::buildPalette() +{ + const QColor btn = ui.buildButton->color(); + const QPalette temp = QPalette(btn); + setPalette(temp); +} + +void PaletteEditor::updatePreviewPalette() +{ + const QPalette::ColorGroup g = currentColorGroup(); + // build the preview palette + const QPalette currentPalette = palette(); + QPalette previewPalette; + for (int i = QPalette::WindowText; i < QPalette::NColorRoles; i++) { + const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(i); + const QBrush br = currentPalette.brush(g, r); + previewPalette.setBrush(QPalette::Active, r, br); + previewPalette.setBrush(QPalette::Inactive, r, br); + previewPalette.setBrush(QPalette::Disabled, r, br); + } + ui.previewFrame->setPreviewPalette(previewPalette); + + const bool enabled = g != QPalette::Disabled; + ui.previewFrame->setEnabled(enabled); + ui.previewFrame->setSubWindowActive(g != QPalette::Inactive); +} + +void PaletteEditor::updateStyledButton() +{ + ui.buildButton->setColor(palette().color(QPalette::Active, QPalette::Button)); +} + +QPalette PaletteEditor::getPalette(QDesignerFormEditorInterface *core, QWidget* parent, const QPalette &init, + const QPalette &parentPal, int *ok) +{ + PaletteEditor dlg(core, parent); + QPalette parentPalette(parentPal); + uint mask = init.resolve(); + for (int i = 0; i < (int)QPalette::NColorRoles; i++) { + if (!(mask & (1 << i))) { + parentPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i), + init.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i))); + parentPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i), + init.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i))); + parentPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i), + init.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i))); + } + } + dlg.setPalette(init, parentPalette); + + const int result = dlg.exec(); + if (ok) *ok = result; + + return result == QDialog::Accepted ? dlg.palette() : init; +} + +////////////////////// + +PaletteModel::PaletteModel(QObject *parent) : + QAbstractTableModel(parent), + m_compute(true) +{ + const QMetaObject *meta = metaObject(); + const int index = meta->indexOfProperty("colorRole"); + const QMetaProperty p = meta->property(index); + const QMetaEnum e = p.enumerator(); + for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) { + m_roleNames[static_cast<QPalette::ColorRole>(r)] = QLatin1String(e.key(r)); + } +} + +int PaletteModel::rowCount(const QModelIndex &) const +{ + return m_roleNames.count(); +} + +int PaletteModel::columnCount(const QModelIndex &) const +{ + return 4; +} + +QVariant PaletteModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (index.row() < 0 || index.row() >= QPalette::NColorRoles) + return QVariant(); + if (index.column() < 0 || index.column() >= 4) + return QVariant(); + + if (index.column() == 0) { + if (role == Qt::DisplayRole) + return m_roleNames[static_cast<QPalette::ColorRole>(index.row())]; + if (role == Qt::EditRole) { + const uint mask = m_palette.resolve(); + if (mask & (1 << index.row())) + return true; + return false; + } + return QVariant(); + } + if (role == BrushRole) + return m_palette.brush(columnToGroup(index.column()), + static_cast<QPalette::ColorRole>(index.row())); + return QVariant(); +} + +bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + + if (index.column() != 0 && role == BrushRole) { + const QBrush br = qVariantValue<QBrush>(value); + const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(index.row()); + const QPalette::ColorGroup g = columnToGroup(index.column()); + m_palette.setBrush(g, r, br); + + QModelIndex idxBegin = PaletteModel::index(r, 0); + QModelIndex idxEnd = PaletteModel::index(r, 3); + if (m_compute) { + m_palette.setBrush(QPalette::Inactive, r, br); + switch (r) { + case QPalette::WindowText: + case QPalette::Text: + case QPalette::ButtonText: + case QPalette::Base: + break; + case QPalette::Dark: + m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Text, br); + m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br); + idxBegin = PaletteModel::index(0, 0); + idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3); + break; + case QPalette::Window: + m_palette.setBrush(QPalette::Disabled, QPalette::Base, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Window, br); + idxBegin = PaletteModel::index(QPalette::Base, 0); + break; + case QPalette::Highlight: + //m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120)); + break; + default: + m_palette.setBrush(QPalette::Disabled, r, br); + break; + } + } + emit paletteChanged(m_palette); + emit dataChanged(idxBegin, idxEnd); + return true; + } + if (index.column() == 0 && role == Qt::EditRole) { + uint mask = m_palette.resolve(); + const bool isMask = qVariantValue<bool>(value); + const int r = index.row(); + if (isMask) + mask |= (1 << r); + else { + m_palette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(r), + m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(r))); + m_palette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r), + m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r))); + m_palette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r), + m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r))); + + mask &= ~(1 << index.row()); + } + m_palette.resolve(mask); + emit paletteChanged(m_palette); + const QModelIndex idxEnd = PaletteModel::index(r, 3); + emit dataChanged(index, idxEnd); + return true; + } + return false; +} + +Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + return Qt::ItemIsEditable | Qt::ItemIsEnabled; +} + +QVariant PaletteModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + if (section == 0) + return tr("Color Role"); + if (section == groupToColumn(QPalette::Active)) + return tr("Active"); + if (section == groupToColumn(QPalette::Inactive)) + return tr("Inactive"); + if (section == groupToColumn(QPalette::Disabled)) + return tr("Disabled"); + } + return QVariant(); +} + +QPalette PaletteModel::getPalette() const +{ + return m_palette; +} + +void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette) +{ + m_parentPalette = parentPalette; + m_palette = palette; + const QModelIndex idxBegin = index(0, 0); + const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3); + emit dataChanged(idxBegin, idxEnd); +} + +QPalette::ColorGroup PaletteModel::columnToGroup(int index) const +{ + if (index == 1) + return QPalette::Active; + if (index == 2) + return QPalette::Inactive; + return QPalette::Disabled; +} + +int PaletteModel::groupToColumn(QPalette::ColorGroup group) const +{ + if (group == QPalette::Active) + return 1; + if (group == QPalette::Inactive) + return 2; + return 3; +} + +////////////////////////// + +BrushEditor::BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_button(new QtColorButton(this)), + m_changed(false), + m_core(core) +{ + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_button); + connect(m_button, SIGNAL(colorChanged(const QColor &)), this, SLOT(brushChanged())); + setFocusProxy(m_button); +} + +void BrushEditor::setBrush(const QBrush &brush) +{ + m_button->setColor(brush.color()); + m_changed = false; +} + +QBrush BrushEditor::brush() const +{ + return QBrush(m_button->color()); +} + +void BrushEditor::brushChanged() +{ + m_changed = true; + emit changed(this); +} + +bool BrushEditor::changed() const +{ + return m_changed; +} + +////////////////////////// + +RoleEditor::RoleEditor(QWidget *parent) : + QWidget(parent), + m_label(new QLabel(this)), + m_edited(false) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + + layout->addWidget(m_label); + m_label->setAutoFillBackground(true); + m_label->setIndent(3); // ### hardcode it should have the same value of textMargin in QItemDelegate + setFocusProxy(m_label); + + QToolButton *button = new QToolButton(this); + button->setToolButtonStyle(Qt::ToolButtonIconOnly); + button->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + button->setIconSize(QSize(8,8)); + button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); + layout->addWidget(button); + connect(button, SIGNAL(clicked()), this, SLOT(emitResetProperty())); +} + +void RoleEditor::setLabel(const QString &label) +{ + m_label->setText(label); +} + +void RoleEditor::setEdited(bool on) +{ + QFont font; + if (on == true) { + font.setBold(on); + } + m_label->setFont(font); + m_edited = on; +} + +bool RoleEditor::edited() const +{ + return m_edited; +} + +void RoleEditor::emitResetProperty() +{ + setEdited(false); + emit changed(this); +} + +////////////////////////// +ColorDelegate::ColorDelegate(QDesignerFormEditorInterface *core, QObject *parent) : + QItemDelegate(parent), + m_core(core) +{ +} + +QWidget *ColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &index) const +{ + QWidget *ed = 0; + if (index.column() == 0) { + RoleEditor *editor = new RoleEditor(parent); + connect(editor, SIGNAL(changed(QWidget *)), this, SIGNAL(commitData(QWidget *))); + //editor->setFocusPolicy(Qt::NoFocus); + //editor->installEventFilter(const_cast<ColorDelegate *>(this)); + ed = editor; + } else { + BrushEditor *editor = new BrushEditor(m_core, parent); + connect(editor, SIGNAL(changed(QWidget *)), this, SIGNAL(commitData(QWidget *))); + editor->setFocusPolicy(Qt::NoFocus); + editor->installEventFilter(const_cast<ColorDelegate *>(this)); + ed = editor; + } + return ed; +} + +void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const +{ + if (index.column() == 0) { + const bool mask = qVariantValue<bool>(index.model()->data(index, Qt::EditRole)); + RoleEditor *editor = static_cast<RoleEditor *>(ed); + editor->setEdited(mask); + const QString colorName = qVariantValue<QString>(index.model()->data(index, Qt::DisplayRole)); + editor->setLabel(colorName); + } else { + const QBrush br = qVariantValue<QBrush>(index.model()->data(index, BrushRole)); + BrushEditor *editor = static_cast<BrushEditor *>(ed); + editor->setBrush(br); + } +} + +void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (index.column() == 0) { + RoleEditor *editor = static_cast<RoleEditor *>(ed); + const bool mask = editor->edited(); + model->setData(index, mask, Qt::EditRole); + } else { + BrushEditor *editor = static_cast<BrushEditor *>(ed); + if (editor->changed()) { + QBrush br = editor->brush(); + model->setData(index, br, BrushRole); + } + } +} + +void ColorDelegate::updateEditorGeometry(QWidget *ed, + const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QItemDelegate::updateEditorGeometry(ed, option, index); + ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1)); +} + +void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, + const QModelIndex &index) const +{ + QStyleOptionViewItem option = opt; + const bool mask = qVariantValue<bool>(index.model()->data(index, Qt::EditRole)); + if (index.column() == 0 && mask) { + option.font.setBold(true); + } + QBrush br = qVariantValue<QBrush>(index.model()->data(index, BrushRole)); + if (br.style() == Qt::LinearGradientPattern || + br.style() == Qt::RadialGradientPattern || + br.style() == Qt::ConicalGradientPattern) { + painter->save(); + painter->translate(option.rect.x(), option.rect.y()); + painter->scale(option.rect.width(), option.rect.height()); + QGradient gr = *(br.gradient()); + gr.setCoordinateMode(QGradient::LogicalMode); + br = QBrush(gr); + painter->fillRect(0, 0, 1, 1, br); + painter->restore(); + } else { + painter->save(); + painter->setBrushOrigin(option.rect.x(), option.rect.y()); + painter->fillRect(option.rect, br); + painter->restore(); + } + QItemDelegate::paint(painter, option, index); + + + const QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option)); + const QPen oldPen = painter->pen(); + painter->setPen(QPen(color)); + + painter->drawLine(option.rect.right(), option.rect.y(), + option.rect.right(), option.rect.bottom()); + painter->drawLine(option.rect.x(), option.rect.bottom(), + option.rect.right(), option.rect.bottom()); + painter->setPen(oldPen); +} + +QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const +{ + return QItemDelegate::sizeHint(opt, index) + QSize(4, 4); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/paletteeditor.h b/tools/designer/src/components/propertyeditor/paletteeditor.h new file mode 100644 index 0000000..f501968 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/paletteeditor.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PALETTEEDITOR_H +#define PALETTEEDITOR_H + +#include "ui_paletteeditor.h" +#include <QtGui/QItemDelegate> + +QT_BEGIN_NAMESPACE + +class QListView; +class QLabel; +class QtColorButton; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class PaletteEditor: public QDialog +{ + Q_OBJECT +public: + virtual ~PaletteEditor(); + + static QPalette getPalette(QDesignerFormEditorInterface *core, + QWidget* parent, const QPalette &init = QPalette(), + const QPalette &parentPal = QPalette(), int *result = 0); + + QPalette palette() const; + void setPalette(const QPalette &palette); + void setPalette(const QPalette &palette, const QPalette &parentPalette); + +private slots: + + void on_buildButton_colorChanged(const QColor &); + void on_activeRadio_clicked(); + void on_inactiveRadio_clicked(); + void on_disabledRadio_clicked(); + void on_computeRadio_clicked(); + void on_detailsRadio_clicked(); + + void paletteChanged(const QPalette &palette); + +protected: + +private: + PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent); + void buildPalette(); + + void updatePreviewPalette(); + void updateStyledButton(); + + QPalette::ColorGroup currentColorGroup() const + { return m_currentColorGroup; } + + Ui::PaletteEditor ui; + QPalette m_editPalette; + QPalette m_parentPalette; + QPalette::ColorGroup m_currentColorGroup; + class PaletteModel *m_paletteModel; + bool m_modelUpdated; + bool m_paletteUpdated; + bool m_compute; + QDesignerFormEditorInterface *m_core; +}; + + +class PaletteModel : public QAbstractTableModel +{ + Q_OBJECT + Q_PROPERTY(QPalette::ColorRole colorRole READ colorRole) +public: + explicit PaletteModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QPalette getPalette() const; + void setPalette(const QPalette &palette, const QPalette &parentPalette); + + QPalette::ColorRole colorRole() const { return QPalette::NoRole; } + void setCompute(bool on) { m_compute = on; } +signals: + void paletteChanged(const QPalette &palette); +private: + + QPalette::ColorGroup columnToGroup(int index) const; + int groupToColumn(QPalette::ColorGroup group) const; + + QPalette m_palette; + QPalette m_parentPalette; + QMap<QPalette::ColorRole, QString> m_roleNames; + bool m_compute; +}; + +class BrushEditor : public QWidget +{ + Q_OBJECT +public: + explicit BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0); + + void setBrush(const QBrush &brush); + QBrush brush() const; + bool changed() const; +signals: + void changed(QWidget *widget); +private slots: + void brushChanged(); +private: + QtColorButton *m_button; + bool m_changed; + QDesignerFormEditorInterface *m_core; +}; + +class RoleEditor : public QWidget +{ + Q_OBJECT +public: + explicit RoleEditor(QWidget *parent = 0); + + void setLabel(const QString &label); + void setEdited(bool on); + bool edited() const; +signals: + void changed(QWidget *widget); +private slots: + void emitResetProperty(); +private: + QLabel *m_label; + bool m_edited; +}; + +class ColorDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + explicit ColorDelegate(QDesignerFormEditorInterface *core, QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void setEditorData(QWidget *ed, const QModelIndex &index) const; + void setModelData(QWidget *ed, QAbstractItemModel *model, + const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *ed, + const QStyleOptionViewItem &option, const QModelIndex &index) const; + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &opt, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const; +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PALETTEEDITOR_H diff --git a/tools/designer/src/components/propertyeditor/paletteeditor.ui b/tools/designer/src/components/propertyeditor/paletteeditor.ui new file mode 100644 index 0000000..55ef5ac --- /dev/null +++ b/tools/designer/src/components/propertyeditor/paletteeditor.ui @@ -0,0 +1,264 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::PaletteEditor</class> + <widget class="QDialog" name="qdesigner_internal::PaletteEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>365</width> + <height>409</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle" > + <string>Edit Palette</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="advancedBox" > + <property name="minimumSize" > + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="title" > + <string>Tune Palette</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="1" > + <widget class="QtColorButton" name="buildButton" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>13</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="0" colspan="4" > + <widget class="QTreeView" name="paletteView" > + <property name="minimumSize" > + <size> + <width>0</width> + <height>200</height> + </size> + </property> + </widget> + </item> + <item row="0" column="3" > + <widget class="QRadioButton" name="detailsRadio" > + <property name="text" > + <string>Show Details</string> + </property> + </widget> + </item> + <item row="0" column="2" > + <widget class="QRadioButton" name="computeRadio" > + <property name="text" > + <string>Compute Details</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Quick</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="GroupBox126" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>Preview</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>8</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="2" > + <widget class="QRadioButton" name="disabledRadio" > + <property name="text" > + <string>Disabled</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QRadioButton" name="inactiveRadio" > + <property name="text" > + <string>Inactive</string> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QRadioButton" name="activeRadio" > + <property name="text" > + <string>Active</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0" colspan="3" > + <widget class="qdesigner_internal::PreviewFrame" native="1" name="previewFrame" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QtColorButton</class> + <extends>QToolButton</extends> + <header>qtcolorbutton.h</header> + </customwidget> + <customwidget> + <class>qdesigner_internal::PreviewFrame</class> + <extends>QWidget</extends> + <header>previewframe.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>qdesigner_internal::PaletteEditor</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>180</x> + <y>331</y> + </hint> + <hint type="destinationlabel" > + <x>134</x> + <y>341</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>qdesigner_internal::PaletteEditor</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>287</x> + <y>329</y> + </hint> + <hint type="destinationlabel" > + <x>302</x> + <y>342</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp b/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp new file mode 100644 index 0000000..d7a76b9 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::PaletteEditorButton +*/ + +#include "paletteeditorbutton.h" +#include "paletteeditor.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +PaletteEditorButton::PaletteEditorButton(QDesignerFormEditorInterface *core, const QPalette &palette, QWidget *parent) + : QToolButton(parent), + m_palette(palette) +{ + m_core = core; + setFocusPolicy(Qt::NoFocus); + setText(tr("Change Palette")); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + + connect(this, SIGNAL(clicked()), this, SLOT(showPaletteEditor())); +} + +PaletteEditorButton::~PaletteEditorButton() +{ +} + +void PaletteEditorButton::setPalette(const QPalette &palette) +{ + m_palette = palette; +} + +void PaletteEditorButton::setSuperPalette(const QPalette &palette) +{ + m_superPalette = palette; +} + +void PaletteEditorButton::showPaletteEditor() +{ + int result; + QPalette p = QPalette(); + QPalette pal = PaletteEditor::getPalette(m_core, 0, m_palette, m_superPalette, &result); + if (result == QDialog::Accepted) { + m_palette = pal; + emit paletteChanged(m_palette); + } +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/paletteeditorbutton.h b/tools/designer/src/components/propertyeditor/paletteeditorbutton.h new file mode 100644 index 0000000..dea9221 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/paletteeditorbutton.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PALETTEEDITORBUTTON_H +#define PALETTEEDITORBUTTON_H + +#include "propertyeditor_global.h" + +#include <QtGui/QPalette> +#include <QtGui/QToolButton> + +#include "abstractformeditor.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_PROPERTYEDITOR_EXPORT PaletteEditorButton: public QToolButton +{ + Q_OBJECT +public: + PaletteEditorButton(QDesignerFormEditorInterface *core, const QPalette &palette, QWidget *parent = 0); + virtual ~PaletteEditorButton(); + + void setSuperPalette(const QPalette &palette); + inline QPalette palette() const + { return m_palette; } + +signals: + void paletteChanged(const QPalette &palette); + +public slots: + void setPalette(const QPalette &palette); + +private slots: + void showPaletteEditor(); + +private: + QPalette m_palette; + QPalette m_superPalette; + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PALETTEEDITORBUTTON_H diff --git a/tools/designer/src/components/propertyeditor/previewframe.cpp b/tools/designer/src/components/propertyeditor/previewframe.cpp new file mode 100644 index 0000000..95d533d --- /dev/null +++ b/tools/designer/src/components/propertyeditor/previewframe.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::PreviewWorkspace +*/ + +#include "previewframe.h" +#include "previewwidget.h" + +#include <QtGui/QPainter> +#include <QtGui/QMdiArea> +#include <QtGui/QMdiSubWindow> +#include <QtGui/QPaintEvent> +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace { + class PreviewMdiArea: public QMdiArea { + public: + PreviewMdiArea(QWidget *parent = 0) : QMdiArea(parent) {} + protected: + bool viewportEvent ( QEvent * event ); + }; + + bool PreviewMdiArea::viewportEvent (QEvent * event) { + if (event->type() != QEvent::Paint) + return QMdiArea::viewportEvent (event); + QWidget *paintWidget = viewport(); + QPainter p(paintWidget); + p.fillRect(rect(), paintWidget->palette().color(backgroundRole()).dark()); + p.setPen(QPen(Qt::white)); + p.drawText(0, height() / 2, width(), height(), Qt::AlignHCenter, + tr("The moose in the noose\nate the goose who was loose.")); + return true; + } +} + +namespace qdesigner_internal { + +PreviewFrame::PreviewFrame(QWidget *parent) : + QFrame(parent), + m_mdiArea(new PreviewMdiArea(this)) +{ + m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + setLineWidth(1); + + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setMargin(0); + vbox->addWidget(m_mdiArea); + + setMinimumSize(ensureMdiSubWindow()->minimumSizeHint()); +} + +void PreviewFrame::setPreviewPalette(const QPalette &pal) +{ + ensureMdiSubWindow()->widget()->setPalette(pal); +} + +void PreviewFrame::setSubWindowActive(bool active) +{ + m_mdiArea->setActiveSubWindow (active ? ensureMdiSubWindow() : static_cast<QMdiSubWindow *>(0)); +} + +QMdiSubWindow *PreviewFrame::ensureMdiSubWindow() +{ + if (!m_mdiSubWindow) { + PreviewWidget *previewWidget = new PreviewWidget(m_mdiArea); + m_mdiSubWindow = m_mdiArea->addSubWindow(previewWidget, Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + m_mdiSubWindow->move(10,10); + m_mdiSubWindow->showMaximized(); + } + + const Qt::WindowStates state = m_mdiSubWindow->windowState(); + if (state & Qt::WindowMinimized) + m_mdiSubWindow->setWindowState(state & ~Qt::WindowMinimized); + + return m_mdiSubWindow; +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/previewframe.h b/tools/designer/src/components/propertyeditor/previewframe.h new file mode 100644 index 0000000..678a7ab --- /dev/null +++ b/tools/designer/src/components/propertyeditor/previewframe.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREVIEWFRAME_H +#define PREVIEWFRAME_H + +#include <QtGui/QFrame> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QMdiArea; +class QMdiSubWindow; + +namespace qdesigner_internal { + +class PreviewFrame: public QFrame +{ + Q_OBJECT +public: + explicit PreviewFrame(QWidget *parent); + + void setPreviewPalette(const QPalette &palette); + void setSubWindowActive(bool active); + +private: + // The user can on some platforms close the mdi child by invoking the system menu. + // Ensure a child is present. + QMdiSubWindow *ensureMdiSubWindow(); + QMdiArea *m_mdiArea; + QPointer<QMdiSubWindow> m_mdiSubWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/tools/designer/src/components/propertyeditor/previewwidget.cpp b/tools/designer/src/components/propertyeditor/previewwidget.cpp new file mode 100644 index 0000000..fa458e7 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/previewwidget.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewwidget.h" + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +PreviewWidget::PreviewWidget(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +PreviewWidget::~PreviewWidget() +{ +} + + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/previewwidget.h b/tools/designer/src/components/propertyeditor/previewwidget.h new file mode 100644 index 0000000..38690d5 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/previewwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +#include "ui_previewwidget.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class PreviewWidget: public QWidget +{ + Q_OBJECT +public: + explicit PreviewWidget(QWidget *parent); + virtual ~PreviewWidget(); + +private: + Ui::PreviewWidget ui; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PREVIEWWIDGET_H diff --git a/tools/designer/src/components/propertyeditor/previewwidget.ui b/tools/designer/src/components/propertyeditor/previewwidget.ui new file mode 100644 index 0000000..c61f0d6 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/previewwidget.ui @@ -0,0 +1,238 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::PreviewWidget</class> + <widget class="QWidget" name="qdesigner_internal::PreviewWidget" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>471</width> + <height>251</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle" > + <string>Preview Window</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item rowspan="3" row="0" column="1" > + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLineEdit" name="LineEdit1" > + <property name="text" > + <string>LineEdit</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="ComboBox1" > + <item> + <property name="text" > + <string>ComboBox</string> + </property> + </item> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QSpinBox" name="SpinBox1" /> + </item> + <item> + <widget class="QPushButton" name="PushButton1" > + <property name="text" > + <string>PushButton</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QScrollBar" name="ScrollBar1" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="Slider1" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="listWidget" > + <property name="maximumSize" > + <size> + <width>32767</width> + <height>50</height> + </size> + </property> + </widget> + </item> + </layout> + </item> + <item row="3" column="0" colspan="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" > + <widget class="QProgressBar" name="ProgressBar1" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QGroupBox" name="ButtonGroup2" > + <property name="title" > + <string>ButtonGroup2</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QCheckBox" name="CheckBox1" > + <property name="text" > + <string>CheckBox1</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="CheckBox2" > + <property name="text" > + <string>CheckBox2</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" > + <widget class="QGroupBox" name="ButtonGroup1" > + <property name="title" > + <string>ButtonGroup</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QRadioButton" name="RadioButton1" > + <property name="text" > + <string>RadioButton1</string> + </property> + <property name="checked" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="RadioButton2" > + <property name="text" > + <string>RadioButton2</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="RadioButton3" > + <property name="text" > + <string>RadioButton3</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.cpp b/tools/designer/src/components/propertyeditor/propertyeditor.cpp new file mode 100644 index 0000000..63b57d8 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/propertyeditor.cpp @@ -0,0 +1,1245 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertyeditor.h" + +#include "qttreepropertybrowser.h" +#include "qtbuttonpropertybrowser.h" +#include "qtvariantproperty.h" +#include "designerpropertymanager.h" +#include "qdesigner_propertysheet_p.h" +#include "formwindowbase_p.h" +#include "filterwidget_p.h" // For FilterWidget + +#include "newdynamicpropertydialog.h" +#include "dynamicpropertysheet.h" +#include "shared_enums_p.h" + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerPropertySheetExtension> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> +#include <QtDesigner/private/abstractsettings_p.h> +// shared +#include <qdesigner_utils_p.h> +#include <qdesigner_propertycommand_p.h> +#include <metadatabase_p.h> +#include <iconloader_p.h> +#ifdef Q_OS_WIN +# include <widgetfactory_p.h> +#endif +#include <QtGui/QAction> +#include <QtGui/QLineEdit> +#include <QtGui/QMenu> +#include <QtGui/QApplication> +#include <QtGui/QVBoxLayout> +#include <QtGui/QScrollArea> +#include <QtGui/QStackedWidget> +#include <QtGui/QToolBar> +#include <QtGui/QToolButton> +#include <QtGui/QActionGroup> +#include <QtGui/QLabel> + +#include <QtCore/QDebug> +#include <QtCore/QTextStream> + +static const char *SettingsGroupC = "PropertyEditor"; +#if QT_VERSION >= 0x040500 +static const char *ViewKeyC = "View"; +#endif +static const char *ColorKeyC = "Colored"; +static const char *SortedKeyC = "Sorted"; +static const char *ExpansionKeyC = "ExpandedItems"; + +enum SettingsView { TreeView, ButtonView }; + +QT_BEGIN_NAMESPACE + +// --------------------------------------------------------------------------------- + +namespace qdesigner_internal { +// ----------- PropertyEditor::Strings + +PropertyEditor::Strings::Strings() : + m_fontProperty(QLatin1String("font")), + m_qLayoutWidget(QLatin1String("QLayoutWidget")), + m_designerPrefix(QLatin1String("QDesigner")), + m_layout(QLatin1String("Layout")), + m_validationModeAttribute(QLatin1String("validationMode")), + m_fontAttribute(QLatin1String("font")), + m_superPaletteAttribute(QLatin1String("superPalette")), + m_enumNamesAttribute(QLatin1String("enumNames")), + m_resettableAttribute(QLatin1String("resettable")), + m_flagsAttribute(QLatin1String("flags")) +{ + m_alignmentProperties.insert(QLatin1String("alignment")); + m_alignmentProperties.insert(QLatin1String("layoutLabelAlignment")); // QFormLayout + m_alignmentProperties.insert(QLatin1String("layoutFormAlignment")); +} + +// ----------- PropertyEditor + +QDesignerMetaDataBaseItemInterface* PropertyEditor::metaDataBaseItem() const +{ + QObject *o = object(); + if (!o) + return 0; + QDesignerMetaDataBaseInterface *db = core()->metaDataBase(); + if (!db) + return 0; + return db->item(o); +} + +void PropertyEditor::setupStringProperty(QtVariantProperty *property, bool isMainContainer) +{ + const StringPropertyParameters params = textPropertyValidationMode(core(), m_object, property->propertyName(), isMainContainer); + // Does a meta DB entry exist - add comment + const bool hasComment = params.second; + property->setAttribute(m_strings.m_validationModeAttribute, params.first); + // assuming comment cannot appear or disappear for the same property in different object instance + if (!hasComment) { + QList<QtProperty *> commentProperties = property->subProperties(); + if (commentProperties.count() > 0) + delete commentProperties.at(0); + if (commentProperties.count() > 1) + delete commentProperties.at(1); + } +} + +void PropertyEditor::setupPaletteProperty(QtVariantProperty *property) +{ + QPalette value = qvariant_cast<QPalette>(property->value()); + QPalette superPalette = QPalette(); + QWidget *currentWidget = qobject_cast<QWidget *>(m_object); + if (currentWidget) { + if (currentWidget->isWindow()) + superPalette = QApplication::palette(currentWidget); + else { + if (currentWidget->parentWidget()) + superPalette = currentWidget->parentWidget()->palette(); + } + } + m_updatingBrowser = true; + property->setAttribute(m_strings.m_superPaletteAttribute, superPalette); + m_updatingBrowser = false; +} + +static inline QToolButton *createDropDownButton(QAction *defaultAction, QWidget *parent = 0) +{ + QToolButton *rc = new QToolButton(parent); + rc->setDefaultAction(defaultAction); + rc->setPopupMode(QToolButton::InstantPopup); + return rc; +} + +PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) : + QDesignerPropertyEditor(parent, flags), + m_core(core), + m_propertySheet(0), + m_currentBrowser(0), + m_treeBrowser(0), + m_propertyManager(new DesignerPropertyManager(m_core, this)), + m_dynamicGroup(0), + m_updatingBrowser(false), + m_stackedWidget(new QStackedWidget), + m_filterWidget(new FilterWidget(0, FilterWidget::LayoutAlignNone)), + m_buttonIndex(-1), + m_treeIndex(-1), + m_addDynamicAction(new QAction(createIconSet(QLatin1String("plus.png")), tr("Add Dynamic Property..."), this)), + m_removeDynamicAction(new QAction(createIconSet(QLatin1String("minus.png")), tr("Remove Dynamic Property"), this)), + m_sortingAction(new QAction(createIconSet(QLatin1String("sort.png")), tr("Sorting"), this)), + m_coloringAction(new QAction(createIconSet(QLatin1String("color.png")), tr("Color Groups"), this)), + m_treeAction(new QAction(tr("Tree View"), this)), + m_buttonAction(new QAction(tr("Drop Down Button View"), this)), + m_classLabel(new QLabel), + m_sorting(false), + m_coloring(false), + m_brightness(false) +{ + QVector<QColor> colors; + colors.reserve(6); + colors.push_back(QColor(255, 230, 191)); + colors.push_back(QColor(255, 255, 191)); + colors.push_back(QColor(191, 255, 191)); + colors.push_back(QColor(199, 255, 255)); + colors.push_back(QColor(234, 191, 255)); + colors.push_back(QColor(255, 191, 239)); + m_colors.reserve(colors.count()); + for (int i = 0; i < colors.count(); i++) { + QColor c = colors.at(i); + m_colors.push_back(qMakePair(c, c.darker(150))); + } + QColor dynamicColor(191, 207, 255); + QColor layoutColor(255, 191, 191); + m_dynamicColor = qMakePair(dynamicColor, dynamicColor.darker(150)); + m_layoutColor = qMakePair(layoutColor, layoutColor.darker(150)); + + updateForegroundBrightness(); + + QActionGroup *actionGroup = new QActionGroup(this); + + m_treeAction->setCheckable(true); + m_treeAction->setIcon(createIconSet(QLatin1String("widgets/listview.png"))); + m_buttonAction->setCheckable(true); + m_buttonAction->setIcon(createIconSet(QLatin1String("dropdownbutton.png"))); + + actionGroup->addAction(m_treeAction); + actionGroup->addAction(m_buttonAction); + connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewTriggered(QAction*))); + + QWidget *classWidget = new QWidget; + QHBoxLayout *l = new QHBoxLayout(classWidget); + l->setContentsMargins(5, 0, 5, 0); + l->addWidget(m_classLabel); + + // Add actions + QActionGroup *addDynamicActionGroup = new QActionGroup(this); + connect(addDynamicActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotAddDynamicProperty(QAction*))); + + QMenu *addDynamicActionMenu = new QMenu(this); + m_addDynamicAction->setMenu(addDynamicActionMenu); + m_addDynamicAction->setEnabled(false); + QAction *addDynamicAction = addDynamicActionGroup->addAction(tr("String...")); + addDynamicAction->setData(static_cast<int>(QVariant::String)); + addDynamicActionMenu->addAction(addDynamicAction); + addDynamicAction = addDynamicActionGroup->addAction(tr("Bool...")); + addDynamicAction->setData(static_cast<int>(QVariant::Bool)); + addDynamicActionMenu->addAction(addDynamicAction); + addDynamicActionMenu->addSeparator(); + addDynamicAction = addDynamicActionGroup->addAction(tr("Other...")); + addDynamicAction->setData(static_cast<int>(QVariant::Invalid)); + addDynamicActionMenu->addAction(addDynamicAction); + // remove + m_removeDynamicAction->setEnabled(false); + connect(m_removeDynamicAction, SIGNAL(triggered()), this, SLOT(slotRemoveDynamicProperty())); + // Configure + QAction *configureAction = new QAction(tr("Configure Property Editor"), this); + configureAction->setIcon(createIconSet(QLatin1String("configure.png"))); + QMenu *configureMenu = new QMenu(this); + configureAction->setMenu(configureMenu); + + m_sortingAction->setCheckable(true); + connect(m_sortingAction, SIGNAL(toggled(bool)), this, SLOT(slotSorting(bool))); + + m_coloringAction->setCheckable(true); + connect(m_coloringAction, SIGNAL(toggled(bool)), this, SLOT(slotColoring(bool))); + + configureMenu->addAction(m_sortingAction); + configureMenu->addAction(m_coloringAction); +#if QT_VERSION >= 0x040600 + configureMenu->addSeparator(); + configureMenu->addAction(m_treeAction); + configureMenu->addAction(m_buttonAction); +#endif + // Assemble toolbar + QToolBar *toolBar = new QToolBar; + toolBar->addWidget(classWidget); + toolBar->addWidget(m_filterWidget); + toolBar->addWidget(createDropDownButton(m_addDynamicAction)); + toolBar->addAction(m_removeDynamicAction); + toolBar->addWidget(createDropDownButton(configureAction)); + // Views + QScrollArea *buttonScroll = new QScrollArea(m_stackedWidget); + m_buttonBrowser = new QtButtonPropertyBrowser(buttonScroll); + buttonScroll->setWidgetResizable(true); + buttonScroll->setWidget(m_buttonBrowser); + m_buttonIndex = m_stackedWidget->addWidget(buttonScroll); + connect(m_buttonBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*))); + + m_treeBrowser = new QtTreePropertyBrowser(m_stackedWidget); + m_treeBrowser->setRootIsDecorated(false); + m_treeBrowser->setPropertiesWithoutValueMarked(true); + m_treeBrowser->setResizeMode(QtTreePropertyBrowser::Interactive); + m_treeIndex = m_stackedWidget->addWidget(m_treeBrowser); + connect(m_treeBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*))); + connect(m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(setFilter(QString))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(toolBar); + layout->addWidget(m_stackedWidget); + layout->setMargin(0); + layout->setSpacing(0); + + m_treeFactory = new DesignerEditorFactory(m_core, this); + m_treeFactory->setSpacing(0); + m_groupFactory = new DesignerEditorFactory(m_core, this); + QtVariantPropertyManager *variantManager = m_propertyManager; + m_buttonBrowser->setFactoryForManager(variantManager, m_groupFactory); + m_treeBrowser->setFactoryForManager(variantManager, m_treeFactory); + + m_stackedWidget->setCurrentIndex(m_treeIndex); + m_currentBrowser = m_treeBrowser; + m_treeAction->setChecked(true); + + connect(m_groupFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*))); + connect(m_treeFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*))); + connect(variantManager, SIGNAL(valueChanged(QtProperty*,QVariant,bool)), this, SLOT(slotValueChanged(QtProperty*,QVariant,bool))); + + // retrieve initial settings + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(SettingsGroupC)); +#if QT_VERSION >= 0x040500 + const SettingsView view = settings->value(QLatin1String(ViewKeyC), TreeView).toInt() == TreeView ? TreeView : ButtonView; +#endif + // Coloring not available unless treeview and not sorted + m_sorting = settings->value(QLatin1String(SortedKeyC), false).toBool(); + m_coloring = settings->value(QLatin1String(ColorKeyC), true).toBool(); + const QVariantMap expansionState = settings->value(QLatin1String(ExpansionKeyC), QVariantMap()).toMap(); + settings->endGroup(); + // Apply settings + m_sortingAction->setChecked(m_sorting); + m_coloringAction->setChecked(m_coloring); +#if QT_VERSION >= 0x040500 + switch (view) { + case TreeView: + m_currentBrowser = m_treeBrowser; + m_stackedWidget->setCurrentIndex(m_treeIndex); + m_treeAction->setChecked(true); + break; + case ButtonView: + m_currentBrowser = m_buttonBrowser; + m_stackedWidget->setCurrentIndex(m_buttonIndex); + m_buttonAction->setChecked(true); + break; + } +#endif + // Restore expansionState from QVariant map + if (!expansionState.empty()) { + const QVariantMap::const_iterator cend = expansionState.constEnd(); + for (QVariantMap::const_iterator it = expansionState.constBegin(); it != cend; ++it) + m_expansionState.insert(it.key(), it.value().toBool()); + } + updateActionsState(); +} + +PropertyEditor::~PropertyEditor() +{ + storeExpansionState(); + saveSettings(); +} + +void PropertyEditor::saveSettings() const +{ + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(SettingsGroupC)); +#if QT_VERSION >= 0x040500 + settings->setValue(QLatin1String(ViewKeyC), QVariant(m_treeAction->isChecked() ? TreeView : ButtonView)); +#endif + settings->setValue(QLatin1String(ColorKeyC), QVariant(m_coloring)); + settings->setValue(QLatin1String(SortedKeyC), QVariant(m_sorting)); + // Save last expansionState as QVariant map + QVariantMap expansionState; + if (!m_expansionState.empty()) { + const QMap<QString, bool>::const_iterator cend = m_expansionState.constEnd(); + for (QMap<QString, bool>::const_iterator it = m_expansionState.constBegin(); it != cend; ++it) + expansionState.insert(it.key(), QVariant(it.value())); + } + settings->setValue(QLatin1String(ExpansionKeyC), expansionState); + settings->endGroup(); +} + +void PropertyEditor::setExpanded(QtBrowserItem *item, bool expanded) +{ + if (m_buttonBrowser == m_currentBrowser) + m_buttonBrowser->setExpanded(item, expanded); + else if (m_treeBrowser == m_currentBrowser) + m_treeBrowser->setExpanded(item, expanded); +} + +bool PropertyEditor::isExpanded(QtBrowserItem *item) const +{ + if (m_buttonBrowser == m_currentBrowser) + return m_buttonBrowser->isExpanded(item); + else if (m_treeBrowser == m_currentBrowser) + return m_treeBrowser->isExpanded(item); + return false; +} + +void PropertyEditor::setItemVisible(QtBrowserItem *item, bool visible) +{ + if (m_currentBrowser == m_treeBrowser) { + m_treeBrowser->setItemVisible(item, visible); + } else { + qWarning("** WARNING %s is not implemented for this browser.", Q_FUNC_INFO); + } +} + +bool PropertyEditor::isItemVisible(QtBrowserItem *item) const +{ + return m_currentBrowser == m_treeBrowser ? m_treeBrowser->isItemVisible(item) : true; +} + +/* Default handling of items not found in the map: + * - Top-level items (classes) are assumed to be expanded + * - Anything below (properties) is assumed to be collapsed + * That is, the map is required, the state cannot be stored in a set */ + +void PropertyEditor::storePropertiesExpansionState(const QList<QtBrowserItem *> &items) +{ + const QChar bar = QLatin1Char('|'); + QListIterator<QtBrowserItem *> itProperty(items); + while (itProperty.hasNext()) { + QtBrowserItem *propertyItem = itProperty.next(); + if (!propertyItem->children().empty()) { + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const QMap<QtProperty *, QString>::const_iterator itGroup = m_propertyToGroup.constFind(property); + if (itGroup != m_propertyToGroup.constEnd()) { + QString key = itGroup.value(); + key += bar; + key += propertyName; + m_expansionState[key] = isExpanded(propertyItem); + } + } + } +} + +void PropertyEditor::storeExpansionState() +{ + const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + storePropertiesExpansionState(items); + } else { + QListIterator<QtBrowserItem *> itGroup(items); + while (itGroup.hasNext()) { + QtBrowserItem *item = itGroup.next(); + const QString groupName = item->property()->propertyName(); + QList<QtBrowserItem *> propertyItems = item->children(); + if (!propertyItems.empty()) + m_expansionState[groupName] = isExpanded(item); + + // properties stuff here + storePropertiesExpansionState(propertyItems); + } + } +} + +void PropertyEditor::collapseAll() +{ + QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems(); + QListIterator<QtBrowserItem *> itGroup(items); + while (itGroup.hasNext()) + setExpanded(itGroup.next(), false); +} + +void PropertyEditor::applyPropertiesExpansionState(const QList<QtBrowserItem *> &items) +{ + const QChar bar = QLatin1Char('|'); + QListIterator<QtBrowserItem *> itProperty(items); + while (itProperty.hasNext()) { + const QMap<QString, bool>::const_iterator excend = m_expansionState.constEnd(); + QtBrowserItem *propertyItem = itProperty.next(); + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const QMap<QtProperty *, QString>::const_iterator itGroup = m_propertyToGroup.constFind(property); + if (itGroup != m_propertyToGroup.constEnd()) { + QString key = itGroup.value(); + key += bar; + key += propertyName; + const QMap<QString, bool>::const_iterator pit = m_expansionState.constFind(key); + if (pit != excend) + setExpanded(propertyItem, pit.value()); + else + setExpanded(propertyItem, false); + } + } +} + +void PropertyEditor::applyExpansionState() +{ + const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + applyPropertiesExpansionState(items); + } else { + QListIterator<QtBrowserItem *> itTopLevel(items); + const QMap<QString, bool>::const_iterator excend = m_expansionState.constEnd(); + while (itTopLevel.hasNext()) { + QtBrowserItem *item = itTopLevel.next(); + const QString groupName = item->property()->propertyName(); + const QMap<QString, bool>::const_iterator git = m_expansionState.constFind(groupName); + if (git != excend) + setExpanded(item, git.value()); + else + setExpanded(item, true); + // properties stuff here + applyPropertiesExpansionState(item->children()); + } + } +} + +int PropertyEditor::applyPropertiesFilter(const QList<QtBrowserItem *> &items) +{ + int showCount = 0; + const bool matchAll = m_filterPattern.isEmpty(); + QListIterator<QtBrowserItem *> itProperty(items); + while (itProperty.hasNext()) { + QtBrowserItem *propertyItem = itProperty.next(); + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const bool showProperty = matchAll || propertyName.contains(m_filterPattern, Qt::CaseInsensitive); + setItemVisible(propertyItem, showProperty); + if (showProperty) + showCount++; + } + return showCount; +} + +void PropertyEditor::applyFilter() +{ + const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + applyPropertiesFilter(items); + } else { + QListIterator<QtBrowserItem *> itTopLevel(items); + while (itTopLevel.hasNext()) { + QtBrowserItem *item = itTopLevel.next(); + setItemVisible(item, applyPropertiesFilter(item->children())); + } + } +} + +void PropertyEditor::clearView() +{ + m_currentBrowser->clear(); +} + +bool PropertyEditor::event(QEvent *event) +{ + if (event->type() == QEvent::PaletteChange) + updateForegroundBrightness(); + + return QDesignerPropertyEditor::event(event); +} + +void PropertyEditor::updateForegroundBrightness() +{ + QColor c = palette().color(QPalette::Text); + bool newBrightness = qRound(0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()); + + if (m_brightness == newBrightness) + return; + + m_brightness = newBrightness; + + updateColors(); +} + +QColor PropertyEditor::propertyColor(QtProperty *property) const +{ + if (!m_coloring) + return QColor(); + + QtProperty *groupProperty = property; + + QMap<QtProperty *, QString>::ConstIterator itProp = m_propertyToGroup.constFind(property); + if (itProp != m_propertyToGroup.constEnd()) + groupProperty = m_nameToGroup.value(itProp.value()); + + const int groupIdx = m_groups.indexOf(groupProperty); + QPair<QColor, QColor> pair; + if (groupIdx != -1) { + if (groupProperty == m_dynamicGroup) + pair = m_dynamicColor; + else if (isLayoutGroup(groupProperty)) + pair = m_layoutColor; + else + pair = m_colors[groupIdx % m_colors.count()]; + } + if (!m_brightness) + return pair.first; + return pair.second; +} + +void PropertyEditor::fillView() +{ + if (m_sorting) { + QMapIterator<QString, QtVariantProperty *> itProperty(m_nameToProperty); + while (itProperty.hasNext()) { + QtVariantProperty *property = itProperty.next().value(); + m_currentBrowser->addProperty(property); + } + } else { + QListIterator<QtProperty *> itGroup(m_groups); + while (itGroup.hasNext()) { + QtProperty *group = itGroup.next(); + QtBrowserItem *item = m_currentBrowser->addProperty(group); + if (m_currentBrowser == m_treeBrowser) + m_treeBrowser->setBackgroundColor(item, propertyColor(group)); + group->setModified(m_currentBrowser == m_treeBrowser); + } + } +} + +bool PropertyEditor::isLayoutGroup(QtProperty *group) const +{ + return group->propertyName() == m_strings.m_layout; +} + +void PropertyEditor::updateActionsState() +{ + m_coloringAction->setEnabled(m_treeAction->isChecked() && !m_sortingAction->isChecked()); +} + +void PropertyEditor::slotViewTriggered(QAction *action) +{ + storeExpansionState(); + collapseAll(); + { + UpdateBlocker ub(this); + clearView(); + int idx = 0; + if (action == m_treeAction) { + m_currentBrowser = m_treeBrowser; + idx = m_treeIndex; + } else if (action == m_buttonAction) { + m_currentBrowser = m_buttonBrowser; + idx = m_buttonIndex; + } + fillView(); + m_stackedWidget->setCurrentIndex(idx); + applyExpansionState(); + applyFilter(); + } + updateActionsState(); +} + +void PropertyEditor::slotSorting(bool sort) +{ + if (sort == m_sorting) + return; + + storeExpansionState(); + m_sorting = sort; + collapseAll(); + { + UpdateBlocker ub(this); + clearView(); + m_treeBrowser->setRootIsDecorated(sort); + fillView(); + applyExpansionState(); + applyFilter(); + } + updateActionsState(); +} + +void PropertyEditor::updateColors() +{ + if (m_treeBrowser && m_currentBrowser == m_treeBrowser) { + QList<QtBrowserItem *> items = m_treeBrowser->topLevelItems(); + QListIterator<QtBrowserItem *> itItem(items); + while (itItem.hasNext()) { + QtBrowserItem *item = itItem.next(); + m_treeBrowser->setBackgroundColor(item, propertyColor(item->property())); + } + } +} + +void PropertyEditor::slotColoring(bool coloring) +{ + if (coloring == m_coloring) + return; + + m_coloring = coloring; + + updateColors(); +} + +void PropertyEditor::slotAddDynamicProperty(QAction *action) +{ + if (!m_propertySheet) + return; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object); + + if (!dynamicSheet) + return; + + QString newName; + QVariant newValue; + { // Make sure the dialog is closed before the signal is emitted. + const QVariant::Type type = static_cast<QVariant::Type>(action->data().toInt()); + NewDynamicPropertyDialog dlg(core()->dialogGui(), m_currentBrowser); + if (type != QVariant::Invalid) + dlg.setPropertyType(type); + + QStringList reservedNames; + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; i++) { + if (!dynamicSheet->isDynamicProperty(i) || m_propertySheet->isVisible(i)) + reservedNames.append(m_propertySheet->propertyName(i)); + } + dlg.setReservedNames(reservedNames); + if (dlg.exec() == QDialog::Rejected) + return; + newName = dlg.propertyName(); + newValue = dlg.propertyValue(); + } + m_recentlyAddedDynamicProperty = newName; + emit addDynamicProperty(newName, newValue); +} + +QDesignerFormEditorInterface *PropertyEditor::core() const +{ + return m_core; +} + +bool PropertyEditor::isReadOnly() const +{ + return false; +} + +void PropertyEditor::setReadOnly(bool /*readOnly*/) +{ + qDebug() << "PropertyEditor::setReadOnly() request"; +} + +void PropertyEditor::setPropertyValue(const QString &name, const QVariant &value, bool changed) +{ + const QMap<QString, QtVariantProperty*>::const_iterator it = m_nameToProperty.constFind(name); + if (it == m_nameToProperty.constEnd()) + return; + QtVariantProperty *property = it.value(); + updateBrowserValue(property, value); + property->setModified(changed); +} + +/* Quick update that assumes the actual count of properties has not changed + * N/A when for example executing a layout command and margin properties appear. */ +void PropertyEditor::updatePropertySheet() +{ + if (!m_propertySheet) + return; + + updateToolBarLabel(); + + const int propertyCount = m_propertySheet->count(); + const QMap<QString, QtVariantProperty*>::const_iterator npcend = m_nameToProperty.constEnd(); + for (int i = 0; i < propertyCount; ++i) { + const QString propertyName = m_propertySheet->propertyName(i); + QMap<QString, QtVariantProperty*>::const_iterator it = m_nameToProperty.constFind(propertyName); + if (it != npcend) + updateBrowserValue(it.value(), m_propertySheet->property(i)); + } +} + +static inline QLayout *layoutOfQLayoutWidget(QObject *o) +{ + if (o->isWidgetType() && !qstrcmp(o->metaObject()->className(), "QLayoutWidget")) + return static_cast<QWidget*>(o)->layout(); + return 0; +} + +void PropertyEditor::updateToolBarLabel() +{ + QString objectName; + QString className; + if (m_object) { + if (QLayout *l = layoutOfQLayoutWidget(m_object)) + objectName = l->objectName(); + else + objectName = m_object->objectName(); + className = realClassName(m_object); + } + + QString classLabelText = objectName; + classLabelText += QLatin1Char('\n'); + classLabelText += className; + m_classLabel->setText(classLabelText); + m_classLabel->setToolTip(tr("Object: %1\nClass: %2").arg(objectName).arg(className)); +} + +void PropertyEditor::updateBrowserValue(QtVariantProperty *property, const QVariant &value) +{ + QVariant v = value; + const int type = property->propertyType(); + if (type == QtVariantPropertyManager::enumTypeId()) { + const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(v); + v = e.metaEnum.keys().indexOf(e.metaEnum.valueToKey(e.value)); + } else if (type == DesignerPropertyManager::designerFlagTypeId()) { + const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v); + v = QVariant(f.value); + } else if (type == DesignerPropertyManager::designerAlignmentTypeId()) { + const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v); + v = QVariant(f.value); + } + QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension))); + int index = -1; + if (sheet) + index = sheet->indexOf(property->propertyName()); + if (sheet && m_propertyToGroup.contains(property)) { // don't do it for comments since property sheet doesn't keep them + property->setEnabled(sheet->isEnabled(index)); + } + + // Rich text string property with comment: Store/Update the font the rich text editor dialog starts out with + if (type == QVariant::String && !property->subProperties().empty()) { + const int fontIndex = m_propertySheet->indexOf(m_strings.m_fontProperty); + if (fontIndex != -1) + property->setAttribute(m_strings.m_fontAttribute, m_propertySheet->property(fontIndex)); + } + + m_updatingBrowser = true; + property->setValue(v); + if (sheet && sheet->isResourceProperty(index)) + property->setAttribute(QLatin1String("defaultResource"), sheet->defaultResourceProperty(index)); + m_updatingBrowser = false; +} + +int PropertyEditor::toBrowserType(const QVariant &value, const QString &propertyName) const +{ + if (qVariantCanConvert<PropertySheetFlagValue>(value)) { + if (m_strings.m_alignmentProperties.contains(propertyName)) + return DesignerPropertyManager::designerAlignmentTypeId(); + return DesignerPropertyManager::designerFlagTypeId(); + } + if (qVariantCanConvert<PropertySheetEnumValue>(value)) + return DesignerPropertyManager::enumTypeId(); + + return value.userType(); +} + +QString PropertyEditor::realClassName(QObject *object) const +{ + if (!object) + return QString(); + + QString className = QLatin1String(object->metaObject()->className()); + const QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *widgetItem = db->item(db->indexOfObject(object, true))) { + className = widgetItem->name(); + + if (object->isWidgetType() && className == m_strings.m_qLayoutWidget + && static_cast<QWidget*>(object)->layout()) { + className = QLatin1String(static_cast<QWidget*>(object)->layout()->metaObject()->className()); + } + } + + if (className.startsWith(m_strings.m_designerPrefix)) + className.remove(1, m_strings.m_designerPrefix.size() - 1); + + return className; +} + +static QString msgUnsupportedType(const QString &propertyName, unsigned type) +{ + QString rc; + QTextStream str(&rc); + str << "The property \"" << propertyName << "\" of type " << type; + if (type == QVariant::Invalid) { + str << " (invalid) "; + } else { + if (type < QVariant::UserType) { + if (const char *typeName = QVariant::typeToName(static_cast<QVariant::Type>(type))) + str << " (" << typeName << ") "; + } else { + str << " (user type) "; + } + } + str << " is not supported yet!"; + return rc; +} + +void PropertyEditor::setObject(QObject *object) +{ + QDesignerFormWindowInterface *oldFormWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + // In the first setObject() call following the addition of a dynamic property, focus and edit it. + const bool editNewDynamicProperty = object != 0 && m_object == object && !m_recentlyAddedDynamicProperty.isEmpty(); + m_object = object; + m_propertyManager->setObject(object); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow); + m_treeFactory->setFormWindowBase(fwb); + m_groupFactory->setFormWindowBase(fwb); + + storeExpansionState(); + + UpdateBlocker ub(this); + + updateToolBarLabel(); + + QMap<QString, QtVariantProperty *> toRemove = m_nameToProperty; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object); + const QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension))); + + // Optimizization: Instead of rebuilding the complete list every time, compile a list of properties to remove, + // remove them, traverse the sheet, in case property exists just set a value, otherwise - create it. + QExtensionManager *m = m_core->extensionManager(); + + m_propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))); + if (m_propertySheet) { + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; ++i) { + if (!m_propertySheet->isVisible(i)) + continue; + + const QString propertyName = m_propertySheet->propertyName(i); + if (m_propertySheet->indexOf(propertyName) != i) + continue; + const QString groupName = m_propertySheet->propertyGroup(i); + const QMap<QString, QtVariantProperty *>::const_iterator rit = toRemove.constFind(propertyName); + if (rit != toRemove.constEnd()) { + QtVariantProperty *property = rit.value(); + if (m_propertyToGroup.value(property) == groupName && toBrowserType(m_propertySheet->property(i), propertyName) == property->propertyType()) + toRemove.remove(propertyName); + } + } + } + + QMapIterator<QString, QtVariantProperty *> itRemove(toRemove); + while (itRemove.hasNext()) { + itRemove.next(); + + QtVariantProperty *property = itRemove.value(); + m_nameToProperty.remove(itRemove.key()); + m_propertyToGroup.remove(property); + delete property; + } + + if (oldFormWindow != formWindow) + reloadResourceProperties(); + + bool isMainContainer = false; + if (QWidget *widget = qobject_cast<QWidget*>(object)) { + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) { + isMainContainer = (fw->mainContainer() == widget); + } + } + m_groups.clear(); + + if (m_propertySheet) { + QtProperty *lastProperty = 0; + QtProperty *lastGroup = 0; + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; ++i) { + if (!m_propertySheet->isVisible(i)) + continue; + + const QString propertyName = m_propertySheet->propertyName(i); + if (m_propertySheet->indexOf(propertyName) != i) + continue; + const QVariant value = m_propertySheet->property(i); + + const int type = toBrowserType(value, propertyName); + + QtVariantProperty *property = m_nameToProperty.value(propertyName, 0); + bool newProperty = property == 0; + if (newProperty) { + property = m_propertyManager->addProperty(type, propertyName); + if (property) { + newProperty = true; + if (type == DesignerPropertyManager::enumTypeId()) { + const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(value); + QStringList names; + QStringListIterator it(e.metaEnum.keys()); + while (it.hasNext()) + names.append(it.next()); + m_updatingBrowser = true; + property->setAttribute(m_strings.m_enumNamesAttribute, names); + m_updatingBrowser = false; + } else if (type == DesignerPropertyManager::designerFlagTypeId()) { + const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(value); + QList<QPair<QString, uint> > flags; + QStringListIterator it(f.metaFlags.keys()); + while (it.hasNext()) { + const QString name = it.next(); + const uint val = f.metaFlags.keyToValue(name); + flags.append(qMakePair(name, val)); + } + m_updatingBrowser = true; + QVariant v; + qVariantSetValue(v, flags); + property->setAttribute(m_strings.m_flagsAttribute, v); + m_updatingBrowser = false; + } + } + } + + if (property != 0) { + const bool dynamicProperty = (dynamicSheet && dynamicSheet->isDynamicProperty(i)) + || (sheet && sheet->isDefaultDynamicProperty(i)); + switch (type) { + case QVariant::Palette: + setupPaletteProperty(property); + break; + case QVariant::KeySequence: + //addCommentProperty(property, propertyName); + break; + default: + break; + } + if (type == QVariant::String || type == qMetaTypeId<PropertySheetStringValue>()) + setupStringProperty(property, isMainContainer); + property->setAttribute(m_strings.m_resettableAttribute, m_propertySheet->hasReset(i)); + + const QString groupName = m_propertySheet->propertyGroup(i); + QtVariantProperty *groupProperty = 0; + + if (newProperty) { + QMap<QString, QtVariantProperty*>::const_iterator itPrev = m_nameToProperty.insert(propertyName, property); + m_propertyToGroup[property] = groupName; + if (m_sorting) { + QtProperty *previous = 0; + if (itPrev != m_nameToProperty.constBegin()) + previous = (--itPrev).value(); + m_currentBrowser->insertProperty(property, previous); + } + } + const QMap<QString, QtVariantProperty*>::const_iterator gnit = m_nameToGroup.constFind(groupName); + if (gnit != m_nameToGroup.constEnd()) { + groupProperty = gnit.value(); + } else { + groupProperty = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), groupName); + QtBrowserItem *item = 0; + if (!m_sorting) + item = m_currentBrowser->insertProperty(groupProperty, lastGroup); + m_nameToGroup[groupName] = groupProperty; + m_groups.append(groupProperty); + if (dynamicProperty) + m_dynamicGroup = groupProperty; + if (m_currentBrowser == m_treeBrowser && item) { + m_treeBrowser->setBackgroundColor(item, propertyColor(groupProperty)); + groupProperty->setModified(true); + } + } + /* Group changed or new group. Append to last subproperty of + * that group. Note that there are cases in which a derived + * property sheet appends fake properties for the class + * which will appear after the layout group properties + * (QWizardPage). To make them appear at the end of the + * actual class group, goto last element. */ + if (lastGroup != groupProperty) { + lastGroup = groupProperty; + lastProperty = 0; // Append at end + const QList<QtProperty*> subProperties = lastGroup->subProperties(); + if (!subProperties.empty()) + lastProperty = subProperties.back(); + lastGroup = groupProperty; + } + if (!m_groups.contains(groupProperty)) + m_groups.append(groupProperty); + if (newProperty) + groupProperty->insertSubProperty(property, lastProperty); + + lastProperty = property; + + updateBrowserValue(property, value); + + property->setModified(m_propertySheet->isChanged(i)); + if (propertyName == QLatin1String("geometry") && type == QVariant::Rect) { + QList<QtProperty *> subProperties = property->subProperties(); + foreach (QtProperty *subProperty, subProperties) { + const QString subPropertyName = subProperty->propertyName(); + if (subPropertyName == QLatin1String("X") || subPropertyName == QLatin1String("Y")) + subProperty->setEnabled(!isMainContainer); + } + } + } else { + qWarning("%s", qPrintable(msgUnsupportedType(propertyName, type))); + } + } + } + QMap<QString, QtVariantProperty *> groups = m_nameToGroup; + QMapIterator<QString, QtVariantProperty *> itGroup(groups); + while (itGroup.hasNext()) { + QtVariantProperty *groupProperty = itGroup.next().value(); + if (groupProperty->subProperties().empty()) { + if (groupProperty == m_dynamicGroup) + m_dynamicGroup = 0; + delete groupProperty; + m_nameToGroup.remove(itGroup.key()); + } + } + const bool addEnabled = dynamicSheet ? dynamicSheet->dynamicPropertiesAllowed() : false; + m_addDynamicAction->setEnabled(addEnabled); + m_removeDynamicAction->setEnabled(false); + applyExpansionState(); + applyFilter(); + // In the first setObject() call following the addition of a dynamic property, focus and edit it. + if (editNewDynamicProperty) { + // Have QApplication process the events related to completely closing the modal 'add' dialog, + // otherwise, we cannot focus the property editor in docked mode. + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + editProperty(m_recentlyAddedDynamicProperty); + } + m_recentlyAddedDynamicProperty.clear(); + m_filterWidget->setEnabled(object); +} + +void PropertyEditor::reloadResourceProperties() +{ + m_updatingBrowser = true; + m_propertyManager->reloadResourceProperties(); + m_updatingBrowser = false; +} + +QtBrowserItem *PropertyEditor::nonFakePropertyBrowserItem(QtBrowserItem *item) const +{ + // Top-level properties are QObject/QWidget groups, etc. Find first item property below + // which should be nonfake + const QList<QtBrowserItem *> topLevelItems = m_currentBrowser->topLevelItems(); + do { + if (topLevelItems.contains(item->parent())) + return item; + item = item->parent(); + } while (item); + return 0; +} + +QString PropertyEditor::currentPropertyName() const +{ + if (QtBrowserItem *browserItem = m_currentBrowser->currentItem()) + if (QtBrowserItem *topLevelItem = nonFakePropertyBrowserItem(browserItem)) { + return topLevelItem->property()->propertyName(); + } + return QString(); +} + +void PropertyEditor::slotResetProperty(QtProperty *property) +{ + QDesignerFormWindowInterface *form = m_core->formWindowManager()->activeFormWindow(); + if (!form) + return; + + if (m_propertyManager->resetFontSubProperty(property)) + return; + + if (m_propertyManager->resetIconSubProperty(property)) + return; + + if (!m_propertyToGroup.contains(property)) + return; + + emit resetProperty(property->propertyName()); +} + +void PropertyEditor::slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling) +{ + if (m_updatingBrowser) + return; + + if (!m_propertySheet) + return; + + QtVariantProperty *varProp = m_propertyManager->variantProperty(property); + + if (!varProp) + return; + + if (!m_propertyToGroup.contains(property)) + return; + + if (varProp->propertyType() == QtVariantPropertyManager::enumTypeId()) { + PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(m_propertySheet->property(m_propertySheet->indexOf(property->propertyName()))); + const int val = value.toInt(); + const QString valName = varProp->attributeValue(m_strings.m_enumNamesAttribute).toStringList().at(val); + bool ok = false; + e.value = e.metaEnum.parseEnum(valName, &ok); + Q_ASSERT(ok); + QVariant v; + qVariantSetValue(v, e); + emit propertyValueChanged(property->propertyName(), v, true); + return; + } + + emit propertyValueChanged(property->propertyName(), value, enableSubPropertyHandling); +} + +bool PropertyEditor::isDynamicProperty(const QtBrowserItem* item) const +{ + if (!item) + return false; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object); + + if (!dynamicSheet) + return false; + + if (m_propertyToGroup.contains(item->property()) + && dynamicSheet->isDynamicProperty(m_propertySheet->indexOf(item->property()->propertyName()))) + return true; + return false; +} + +void PropertyEditor::editProperty(const QString &name) +{ + // find the browser item belonging to the property, make it current and edit it + QtBrowserItem *browserItem = 0; + if (QtVariantProperty *property = m_nameToProperty.value(name, 0)) { + const QList<QtBrowserItem *> items = m_currentBrowser->items(property); + if (items.size() == 1) + browserItem = items.front(); + } + if (browserItem == 0) + return; + m_currentBrowser->setFocus(Qt::OtherFocusReason); + if (m_currentBrowser == m_treeBrowser) { // edit is currently only supported in tree view + m_treeBrowser->editItem(browserItem); + } else { + m_currentBrowser->setCurrentItem(browserItem); + } +} + +void PropertyEditor::slotCurrentItemChanged(QtBrowserItem *item) +{ + m_removeDynamicAction->setEnabled(isDynamicProperty(item)); + +} + +void PropertyEditor::slotRemoveDynamicProperty() +{ + if (QtBrowserItem* item = m_currentBrowser->currentItem()) + if (isDynamicProperty(item)) + emit removeDynamicProperty(item->property()->propertyName()); +} + +void PropertyEditor::setFilter(const QString &pattern) +{ + m_filterPattern = pattern; + applyFilter(); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.h b/tools/designer/src/components/propertyeditor/propertyeditor.h new file mode 100644 index 0000000..21e81dd --- /dev/null +++ b/tools/designer/src/components/propertyeditor/propertyeditor.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYEDITOR_H +#define PROPERTYEDITOR_H + +#include "propertyeditor_global.h" +#include <qdesigner_propertyeditor_p.h> + +#include <QtCore/QPointer> +#include <QtCore/QMap> +#include <QtCore/QVector> +#include <QtCore/QSet> + +QT_BEGIN_NAMESPACE + +class DomProperty; +class QDesignerMetaDataBaseItemInterface; +class QDesignerPropertySheetExtension; + +class QtAbstractPropertyBrowser; +class QtButtonPropertyBrowser; +class QtTreePropertyBrowser; +class QtProperty; +class QtVariantProperty; +class QtBrowserItem; + +class QStackedWidget; +class QLabel; + +namespace qdesigner_internal { + +class StringProperty; +class DesignerPropertyManager; +class DesignerEditorFactory; +class FilterWidget; + +class QT_PROPERTYEDITOR_EXPORT PropertyEditor: public QDesignerPropertyEditor +{ + Q_OBJECT +public: + explicit PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~PropertyEditor(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual bool isReadOnly() const; + virtual void setReadOnly(bool readOnly); + virtual void setPropertyValue(const QString &name, const QVariant &value, bool changed = true); + virtual void updatePropertySheet(); + + virtual void setObject(QObject *object); + + void reloadResourceProperties(); + + virtual QObject *object() const + { return m_object; } + + virtual QString currentPropertyName() const; + +protected: + + bool event(QEvent *event); + +private slots: + void slotResetProperty(QtProperty *property); + void slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling); + void slotViewTriggered(QAction *action); + void slotAddDynamicProperty(QAction *action); + void slotRemoveDynamicProperty(); + void slotSorting(bool sort); + void slotColoring(bool color); + void slotCurrentItemChanged(QtBrowserItem*); + void setFilter(const QString &pattern); + +private: + void updateBrowserValue(QtVariantProperty *property, const QVariant &value); + void updateToolBarLabel(); + int toBrowserType(const QVariant &value, const QString &propertyName) const; + QString removeScope(const QString &value) const; + QDesignerMetaDataBaseItemInterface *metaDataBaseItem() const; + void setupStringProperty(QtVariantProperty *property, bool isMainContainer); + void setupPaletteProperty(QtVariantProperty *property); + QString realClassName(QObject *object) const; + void storeExpansionState(); + void applyExpansionState(); + void storePropertiesExpansionState(const QList<QtBrowserItem *> &items); + void applyPropertiesExpansionState(const QList<QtBrowserItem *> &items); + void applyFilter(); + int applyPropertiesFilter(const QList<QtBrowserItem *> &items); + void setExpanded(QtBrowserItem *item, bool expanded); + bool isExpanded(QtBrowserItem *item) const; + void setItemVisible(QtBrowserItem *item, bool visible); + bool isItemVisible(QtBrowserItem *item) const; + void collapseAll(); + void clearView(); + void fillView(); + bool isLayoutGroup(QtProperty *group) const; + void updateColors(); + void updateForegroundBrightness(); + QColor propertyColor(QtProperty *property) const; + void updateActionsState(); + QtBrowserItem *nonFakePropertyBrowserItem(QtBrowserItem *item) const; + void saveSettings() const; + void editProperty(const QString &name); + bool isDynamicProperty(const QtBrowserItem* item) const; + + struct Strings { + Strings(); + QSet<QString> m_alignmentProperties; + const QString m_fontProperty; + const QString m_qLayoutWidget; + const QString m_designerPrefix; + const QString m_layout; + const QString m_validationModeAttribute; + const QString m_fontAttribute; + const QString m_superPaletteAttribute; + const QString m_enumNamesAttribute; + const QString m_resettableAttribute; + const QString m_flagsAttribute; + }; + + const Strings m_strings; + QDesignerFormEditorInterface *m_core; + QDesignerPropertySheetExtension *m_propertySheet; + QtAbstractPropertyBrowser *m_currentBrowser; + QtButtonPropertyBrowser *m_buttonBrowser; + QtTreePropertyBrowser *m_treeBrowser; + DesignerPropertyManager *m_propertyManager; + DesignerEditorFactory *m_treeFactory; + DesignerEditorFactory *m_groupFactory; + QPointer<QObject> m_object; + QMap<QString, QtVariantProperty*> m_nameToProperty; + QMap<QtProperty*, QString> m_propertyToGroup; + QMap<QString, QtVariantProperty*> m_nameToGroup; + QList<QtProperty *> m_groups; + QtProperty *m_dynamicGroup; + QString m_recentlyAddedDynamicProperty; + bool m_updatingBrowser; + + QStackedWidget *m_stackedWidget; + FilterWidget *m_filterWidget; + int m_buttonIndex; + int m_treeIndex; + QAction *m_addDynamicAction; + QAction *m_removeDynamicAction; + QAction *m_sortingAction; + QAction *m_coloringAction; + QAction *m_treeAction; + QAction *m_buttonAction; + QLabel *m_classLabel; + + bool m_sorting; + bool m_coloring; + + QMap<QString, bool> m_expansionState; + + QString m_filterPattern; + QVector<QPair<QColor, QColor> > m_colors; + QPair<QColor, QColor> m_dynamicColor; + QPair<QColor, QColor> m_layoutColor; + + bool m_brightness; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PROPERTYEDITOR_H diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.pri b/tools/designer/src/components/propertyeditor/propertyeditor.pri new file mode 100644 index 0000000..d3e44a5 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/propertyeditor.pri @@ -0,0 +1,47 @@ +#the next line prevents non-shadowbuilds from including the same directory twice +#otherwise, the build command would be too long for some win32 shells. +!exists($$QT_BUILD_TREE/tools/designer/src/components/propertyeditor/propertyeditor.h):INCLUDEPATH += $$QT_BUILD_TREE/tools/designer/src/components/propertyeditor + +INCLUDEPATH += $$PWD + +include($$QT_SOURCE_TREE/tools/shared/qtpropertybrowser/qtpropertybrowser.pri) +include($$QT_SOURCE_TREE/tools/shared/qtgradienteditor/qtcolorbutton.pri) + +FORMS += $$PWD/paletteeditor.ui \ + $$PWD/stringlisteditor.ui \ + $$PWD/previewwidget.ui \ + $$PWD/newdynamicpropertydialog.ui + +HEADERS += $$PWD/propertyeditor.h \ + $$PWD/designerpropertymanager.h \ + $$PWD/paletteeditor.h \ + $$PWD/paletteeditorbutton.h \ + $$PWD/stringlisteditor.h \ + $$PWD/stringlisteditorbutton.h \ + $$PWD/previewwidget.h \ + $$PWD/previewframe.h \ + $$PWD/newdynamicpropertydialog.h \ + $$PWD/brushpropertymanager.h \ + $$PWD/fontpropertymanager.h + +SOURCES += $$PWD/propertyeditor.cpp \ + $$PWD/designerpropertymanager.cpp \ + $$PWD/paletteeditor.cpp \ + $$PWD/paletteeditorbutton.cpp \ + $$PWD/stringlisteditor.cpp \ + $$PWD/stringlisteditorbutton.cpp \ + $$PWD/previewwidget.cpp \ + $$PWD/previewframe.cpp \ + $$PWD/newdynamicpropertydialog.cpp \ + $$PWD/brushpropertymanager.cpp \ + $$PWD/fontpropertymanager.cpp + +HEADERS += \ + $$PWD/propertyeditor_global.h \ + $$PWD/defs.h \ + $$PWD/qlonglongvalidator.h + +SOURCES += $$PWD/defs.cpp \ + $$PWD/qlonglongvalidator.cpp + +RESOURCES += $$PWD/propertyeditor.qrc diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.qrc b/tools/designer/src/components/propertyeditor/propertyeditor.qrc new file mode 100644 index 0000000..68008ec --- /dev/null +++ b/tools/designer/src/components/propertyeditor/propertyeditor.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/trolltech/propertyeditor"> + <file>fontmapping.xml</file> + </qresource> +</RCC> diff --git a/tools/designer/src/components/propertyeditor/propertyeditor_global.h b/tools/designer/src/components/propertyeditor/propertyeditor_global.h new file mode 100644 index 0000000..c7c4780 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/propertyeditor_global.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYEDITOR_GLOBAL_H +#define PROPERTYEDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +#ifdef QT_PROPERTYEDITOR_LIBRARY +# define QT_PROPERTYEDITOR_EXPORT +#else +# define QT_PROPERTYEDITOR_EXPORT +#endif +#else +#define QT_PROPERTYEDITOR_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // PROPERTYEDITOR_GLOBAL_H diff --git a/tools/designer/src/components/propertyeditor/qlonglongvalidator.cpp b/tools/designer/src/components/propertyeditor/qlonglongvalidator.cpp new file mode 100644 index 0000000..a6663cf --- /dev/null +++ b/tools/designer/src/components/propertyeditor/qlonglongvalidator.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlonglongvalidator.h" + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +// ---------------------------------------------------------------------------- +QLongLongValidator::QLongLongValidator(QObject * parent) + : QValidator(parent), + b(Q_UINT64_C(0x8000000000000000)), t(Q_UINT64_C(0x7FFFFFFFFFFFFFFF)) +{ +} + +QLongLongValidator::QLongLongValidator(qlonglong minimum, qlonglong maximum, + QObject * parent) + : QValidator(parent), b(minimum), t(maximum) +{ +} + +QLongLongValidator::~QLongLongValidator() +{ + // nothing +} + +QValidator::State QLongLongValidator::validate(QString & input, int &) const +{ + if (input.contains(QLatin1Char(' '))) + return Invalid; + if (input.isEmpty() || (b < 0 && input == QString(QLatin1Char('-')))) + return Intermediate; + bool ok; + qlonglong entered = input.toLongLong(&ok); + if (!ok || (entered < 0 && b >= 0)) { + return Invalid; + } else if (entered >= b && entered <= t) { + return Acceptable; + } else { + if (entered >= 0) + return (entered > t) ? Invalid : Intermediate; + else + return (entered < b) ? Invalid : Intermediate; + } +} + +void QLongLongValidator::setRange(qlonglong bottom, qlonglong top) +{ + b = bottom; + t = top; +} + +void QLongLongValidator::setBottom(qlonglong bottom) +{ + setRange(bottom, top()); +} + +void QLongLongValidator::setTop(qlonglong top) +{ + setRange(bottom(), top); +} + + +// ---------------------------------------------------------------------------- +QULongLongValidator::QULongLongValidator(QObject * parent) + : QValidator(parent), + b(0), t(Q_UINT64_C(0xFFFFFFFFFFFFFFFF)) +{ +} + +QULongLongValidator::QULongLongValidator(qulonglong minimum, qulonglong maximum, + QObject * parent) + : QValidator(parent), b(minimum), t(maximum) +{ +} + +QULongLongValidator::~QULongLongValidator() +{ + // nothing +} + +QValidator::State QULongLongValidator::validate(QString & input, int &) const +{ + if (input.isEmpty()) + return Intermediate; + + bool ok; + qulonglong entered = input.toULongLong(&ok); + if (input.contains(QLatin1Char(' ')) || input.contains(QLatin1Char('-')) || !ok) + return Invalid; + + if (entered >= b && entered <= t) + return Acceptable; + + return Invalid; +} + +void QULongLongValidator::setRange(qulonglong bottom, qulonglong top) +{ + b = bottom; + t = top; +} + +void QULongLongValidator::setBottom(qulonglong bottom) +{ + setRange(bottom, top()); +} + +void QULongLongValidator::setTop(qulonglong top) +{ + setRange(bottom(), top); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/qlonglongvalidator.h b/tools/designer/src/components/propertyeditor/qlonglongvalidator.h new file mode 100644 index 0000000..2b3174b --- /dev/null +++ b/tools/designer/src/components/propertyeditor/qlonglongvalidator.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLONGLONGVALIDATOR_H +#define QLONGLONGVALIDATOR_H + +#include <QtGui/QValidator> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QLongLongValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(qlonglong bottom READ bottom WRITE setBottom) + Q_PROPERTY(qlonglong top READ top WRITE setTop) + +public: + explicit QLongLongValidator(QObject * parent); + QLongLongValidator(qlonglong bottom, qlonglong top, QObject * parent); + ~QLongLongValidator(); + + QValidator::State validate(QString &, int &) const; + + void setBottom(qlonglong); + void setTop(qlonglong); + virtual void setRange(qlonglong bottom, qlonglong top); + + qlonglong bottom() const { return b; } + qlonglong top() const { return t; } + +private: + Q_DISABLE_COPY(QLongLongValidator) + + qlonglong b; + qlonglong t; +}; + +// ---------------------------------------------------------------------------- +class QULongLongValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(qulonglong bottom READ bottom WRITE setBottom) + Q_PROPERTY(qulonglong top READ top WRITE setTop) + +public: + explicit QULongLongValidator(QObject * parent); + QULongLongValidator(qulonglong bottom, qulonglong top, QObject * parent); + ~QULongLongValidator(); + + QValidator::State validate(QString &, int &) const; + + void setBottom(qulonglong); + void setTop(qulonglong); + virtual void setRange(qulonglong bottom, qulonglong top); + + qulonglong bottom() const { return b; } + qulonglong top() const { return t; } + +private: + Q_DISABLE_COPY(QULongLongValidator) + + qulonglong b; + qulonglong t; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QLONGLONGVALIDATOR_H diff --git a/tools/designer/src/components/propertyeditor/stringlisteditor.cpp b/tools/designer/src/components/propertyeditor/stringlisteditor.cpp new file mode 100644 index 0000000..861e699 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/stringlisteditor.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "stringlisteditor.h" +#include <iconloader_p.h> +#include <QtGui/QStringListModel> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +StringListEditor::StringListEditor(QWidget *parent) + : QDialog(parent), m_model(new QStringListModel(this)) +{ + setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + listView->setModel(m_model); + + connect(listView->selectionModel(), + SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(currentIndexChanged(const QModelIndex &, const QModelIndex &))); + connect(listView->itemDelegate(), + SIGNAL(closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)), + this, SLOT(currentValueChanged())); + + QIcon upIcon = createIconSet(QString::fromUtf8("up.png")); + QIcon downIcon = createIconSet(QString::fromUtf8("down.png")); + QIcon minusIcon = createIconSet(QString::fromUtf8("minus.png")); + QIcon plusIcon = createIconSet(QString::fromUtf8("plus.png")); + upButton->setIcon(upIcon); + downButton->setIcon(downIcon); + newButton->setIcon(plusIcon); + deleteButton->setIcon(minusIcon); + + updateUi(); +} + +StringListEditor::~StringListEditor() +{ +} + +QStringList StringListEditor::getStringList(QWidget *parent, const QStringList &init, int *result) +{ + StringListEditor dlg(parent); + dlg.setStringList(init); + int res = dlg.exec(); + if (result) + *result = res; + return (res == QDialog::Accepted) ? dlg.stringList() : init; +} + +void StringListEditor::setStringList(const QStringList &stringList) +{ + m_model->setStringList(stringList); + updateUi(); +} + +QStringList StringListEditor::stringList() const +{ + return m_model->stringList(); +} + +void StringListEditor::currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous); + setCurrentIndex(current.row()); + updateUi(); +} + +void StringListEditor::currentValueChanged() +{ + setCurrentIndex(currentIndex()); + updateUi(); +} + +void StringListEditor::on_upButton_clicked() +{ + int from = currentIndex(); + int to = currentIndex() - 1; + QString value = stringAt(from); + removeString(from); + insertString(to, value); + setCurrentIndex(to); + updateUi(); +} + +void StringListEditor::on_downButton_clicked() +{ + int from = currentIndex(); + int to = currentIndex() + 1; + QString value = stringAt(from); + removeString(from); + insertString(to, value); + setCurrentIndex(to); + updateUi(); +} + +void StringListEditor::on_newButton_clicked() +{ + int to = currentIndex(); + if (to == -1) + to = count() - 1; + ++to; + insertString(to, QString()); + setCurrentIndex(to); + updateUi(); + editString(to); +} + +void StringListEditor::on_deleteButton_clicked() +{ + removeString(currentIndex()); + setCurrentIndex(currentIndex()); + updateUi(); +} + +void StringListEditor::on_valueEdit_textEdited(const QString &text) +{ + setStringAt(currentIndex(), text); +} + +void StringListEditor::updateUi() +{ + upButton->setEnabled((count() > 1) && (currentIndex() > 0)); + downButton->setEnabled((count() > 1) && (currentIndex() >= 0) && (currentIndex() < (count() - 1))); + deleteButton->setEnabled(currentIndex() != -1); + valueEdit->setEnabled(currentIndex() != -1); +} + +int StringListEditor::currentIndex() const +{ + return listView->currentIndex().row(); +} + +void StringListEditor::setCurrentIndex(int index) +{ + QModelIndex modelIndex = m_model->index(index, 0); + if (listView->currentIndex() != modelIndex) + listView->setCurrentIndex(modelIndex); + valueEdit->setText(stringAt(index)); +} + +int StringListEditor::count() const +{ + return m_model->rowCount(); +} + +QString StringListEditor::stringAt(int index) const +{ + return qvariant_cast<QString>(m_model->data(m_model->index(index, 0), Qt::DisplayRole)); +} + +void StringListEditor::setStringAt(int index, const QString &value) +{ + m_model->setData(m_model->index(index, 0), value); +} + +void StringListEditor::removeString(int index) +{ + m_model->removeRows(index, 1); +} + +void StringListEditor::insertString(int index, const QString &value) +{ + m_model->insertRows(index, 1); + m_model->setData(m_model->index(index, 0), value); +} + +void StringListEditor::editString(int index) +{ + listView->edit(m_model->index(index, 0)); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/stringlisteditor.h b/tools/designer/src/components/propertyeditor/stringlisteditor.h new file mode 100644 index 0000000..86b48ff --- /dev/null +++ b/tools/designer/src/components/propertyeditor/stringlisteditor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STRINGLISTEDITOR_H +#define STRINGLISTEDITOR_H + +#include "ui_stringlisteditor.h" +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE +class QStringListModel; + +namespace qdesigner_internal { + +class StringListEditor : public QDialog, private Ui::Dialog +{ + Q_OBJECT +public: + ~StringListEditor(); + void setStringList(const QStringList &stringList); + QStringList stringList() const; + + static QStringList getStringList( + QWidget *parent, const QStringList &init = QStringList(), int *result = 0); + +private slots: + void on_upButton_clicked(); + void on_downButton_clicked(); + void on_newButton_clicked(); + void on_deleteButton_clicked(); + void on_valueEdit_textEdited(const QString &text); + void currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); + void currentValueChanged(); + +private: + StringListEditor(QWidget *parent = 0); + void updateUi(); + int currentIndex() const; + void setCurrentIndex(int index); + int count() const; + QString stringAt(int index) const; + void setStringAt(int index, const QString &value); + void removeString(int index); + void insertString(int index, const QString &value); + void editString(int index); + + QStringListModel *m_model; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // STRINGLISTEDITOR_H diff --git a/tools/designer/src/components/propertyeditor/stringlisteditor.ui b/tools/designer/src/components/propertyeditor/stringlisteditor.ui new file mode 100644 index 0000000..fdcdabc --- /dev/null +++ b/tools/designer/src/components/propertyeditor/stringlisteditor.ui @@ -0,0 +1,265 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::Dialog</class> + <widget class="QDialog" name="qdesigner_internal::Dialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle" > + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>StringList</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" colspan="2" > + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QToolButton" name="newButton" > + <property name="toolTip" > + <string>New String</string> + </property> + <property name="text" > + <string>&New</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="deleteButton" > + <property name="toolTip" > + <string>Delete String</string> + </property> + <property name="text" > + <string>&Delete</string> + </property> + <property name="toolButtonStyle" > + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string>&Value:</string> + </property> + <property name="buddy" > + <cstring>valueEdit</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="valueEdit" /> + </item> + </layout> + </item> + </layout> + </item> + <item row="0" column="1" > + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="upButton" > + <property name="toolTip" > + <string>Move String Up</string> + </property> + <property name="text" > + <string>Up</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="downButton" > + <property name="toolTip" > + <string>Move String Down</string> + </property> + <property name="text" > + <string>Down</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="0" column="0" > + <widget class="QListView" name="listView" /> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>qdesigner_internal::Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>258</x> + <y>283</y> + </hint> + <hint type="destinationlabel" > + <x>138</x> + <y>294</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>qdesigner_internal::Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>350</x> + <y>284</y> + </hint> + <hint type="destinationlabel" > + <x>369</x> + <y>295</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp new file mode 100644 index 0000000..440015c --- /dev/null +++ b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::StringListEditorButton +*/ + +#include "stringlisteditorbutton.h" +#include "stringlisteditor.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +StringListEditorButton::StringListEditorButton( + const QStringList &stringList, QWidget *parent) + : QToolButton(parent), m_stringList(stringList) +{ + setFocusPolicy(Qt::NoFocus); + setText(tr("Change String List")); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + + connect(this, SIGNAL(clicked()), this, SLOT(showStringListEditor())); +} + +StringListEditorButton::~StringListEditorButton() +{ +} + +void StringListEditorButton::setStringList(const QStringList &stringList) +{ + m_stringList = stringList; +} + +void StringListEditorButton::showStringListEditor() +{ + int result; + QStringList lst = StringListEditor::getStringList(0, m_stringList, &result); + if (result == QDialog::Accepted) { + m_stringList = lst; + emit stringListChanged(m_stringList); + } +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/propertyeditor/stringlisteditorbutton.h b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.h new file mode 100644 index 0000000..c843980 --- /dev/null +++ b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STRINGLISTEDITORBUTTON_H +#define STRINGLISTEDITORBUTTON_H + +#include "propertyeditor_global.h" + +#include <QtCore/QStringList> +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_PROPERTYEDITOR_EXPORT StringListEditorButton: public QToolButton +{ + Q_OBJECT +public: + explicit StringListEditorButton(const QStringList &stringList, QWidget *parent = 0); + virtual ~StringListEditorButton(); + + inline QStringList stringList() const + { return m_stringList; } + +signals: + void stringListChanged(const QStringList &stringList); + +public slots: + void setStringList(const QStringList &stringList); + +private slots: + void showStringListEditor(); + +private: + QStringList m_stringList; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // STRINGLISTEDITORBUTTON_H diff --git a/tools/designer/src/components/signalsloteditor/connectdialog.cpp b/tools/designer/src/components/signalsloteditor/connectdialog.cpp new file mode 100644 index 0000000..d9b8ed5 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include <signalslotdialog_p.h> +#include <metadatabase_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerLanguageExtension> + +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList<QListWidgetItem*> ListWidgetItems; +} + +static QString realClassName(QDesignerFormEditorInterface *core, QWidget *widget) +{ + QString class_name = QLatin1String(widget->metaObject()->className()); + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int idx = wdb->indexOfObject(widget); + if (idx != -1) + class_name = wdb->item(idx)->name(); + return class_name; +} + +static QString widgetLabel(QDesignerFormEditorInterface *core, QWidget *widget) +{ + return QString::fromUtf8("%1 (%2)") + .arg(qdesigner_internal::realObjectName(core, widget)) + .arg(realClassName(core, widget)); +} + +namespace qdesigner_internal { + +ConnectDialog::ConnectDialog(QDesignerFormWindowInterface *formWindow, + QWidget *source, QWidget *destination, + QWidget *parent) : + QDialog(parent), + m_source(source), + m_destination(destination), + m_sourceMode(widgetMode(m_source, formWindow)), + m_destinationMode(widgetMode(m_destination, formWindow)), + m_formWindow(formWindow) +{ + m_ui.setupUi(this); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(m_ui.signalList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSignal(QListWidgetItem*))); + connect(m_ui.slotList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSlot(QListWidgetItem*))); + m_ui.slotList->setEnabled(false); + + QPushButton *ok_button = okButton(); + ok_button->setDefault(true); + ok_button->setEnabled(false); + + connect(m_ui.showAllCheckBox, SIGNAL(toggled(bool)), this, SLOT(populateLists())); + + QDesignerFormEditorInterface *core = m_formWindow->core(); + m_ui.signalGroupBox->setTitle(widgetLabel(core, source)); + m_ui.slotGroupBox->setTitle(widgetLabel(core, destination)); + + m_ui.editSignalsButton->setEnabled(m_sourceMode != NormalWidget); + connect(m_ui.editSignalsButton, SIGNAL(clicked()), this, SLOT(editSignals())); + + m_ui.editSlotsButton->setEnabled(m_destinationMode != NormalWidget); + connect(m_ui.editSlotsButton, SIGNAL(clicked()), this, SLOT(editSlots())); + + populateLists(); +} + +ConnectDialog::WidgetMode ConnectDialog::widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow) +{ + QDesignerFormEditorInterface *core = formWindow->core(); + if (qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) + return NormalWidget; + + if (w == formWindow || formWindow->mainContainer() == w) + return MainContainer; + + if (isPromoted(formWindow->core(), w)) + return PromotedWidget; + + return NormalWidget; +} + +QPushButton *ConnectDialog::okButton() +{ + return m_ui.buttonBox->button(QDialogButtonBox::Ok); +} + +void ConnectDialog::setOkButtonEnabled(bool e) +{ + okButton()->setEnabled(e); +} + +void ConnectDialog::populateLists() +{ + populateSignalList(); +} + +void ConnectDialog::setSignalSlot(const QString &signal, const QString &slot) +{ + ListWidgetItems sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + + if (sigItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + } + + if (!sigItems.empty()) { + selectSignal(sigItems.front()); + ListWidgetItems slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + if (slotItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + } + if (!slotItems.empty()) + selectSlot(slotItems.front()); + } +} + +bool ConnectDialog::showAllSignalsSlots() const +{ + return m_ui.showAllCheckBox->isChecked(); +} + +void ConnectDialog::setShowAllSignalsSlots(bool showIt) +{ + m_ui.showAllCheckBox->setChecked(showIt); +} + +void ConnectDialog::selectSignal(QListWidgetItem *item) +{ + if (item) { + m_ui.signalList->setCurrentItem(item); + populateSlotList(item->text()); + m_ui.slotList->setEnabled(true); + setOkButtonEnabled(!m_ui.slotList->selectedItems().isEmpty()); + } else { + m_ui.signalList->clearSelection(); + populateSlotList(); + m_ui.slotList->setEnabled(false); + setOkButtonEnabled(false); + } +} + +void ConnectDialog::selectSlot(QListWidgetItem *item) +{ + if (item) { + m_ui.slotList->setCurrentItem(item); + } else { + m_ui.slotList->clearSelection(); + } + setOkButtonEnabled(true); +} + +QString ConnectDialog::signal() const +{ + const ListWidgetItems item_list = m_ui.signalList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +QString ConnectDialog::slot() const +{ + const ListWidgetItems item_list = m_ui.slotList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +void ConnectDialog::populateSlotList(const QString &signal) +{ + QString selectedName; + if (const QListWidgetItem * item = m_ui.slotList->currentItem()) + selectedName = item->text(); + + m_ui.slotList->clear(); + + QMap<QString, QString> memberToClassName = getMatchingSlots(m_formWindow->core(), m_destination, signal, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = qVariantFromValue(font); + + QListWidgetItem *curr = 0; + QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin(); + const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Slot = isQt3Slot(m_formWindow->core(), m_destination, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.slotList); + item->setText(member); + if (member == selectedName) + curr = item; + + if (qt3Slot) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) + m_ui.slotList->setCurrentItem(curr); + + if (m_ui.slotList->selectedItems().isEmpty()) + setOkButtonEnabled(false); +} + +void ConnectDialog::populateSignalList() +{ + QString selectedName; + if (const QListWidgetItem *item = m_ui.signalList->currentItem()) + selectedName = item->text(); + + m_ui.signalList->clear(); + + QMap<QString, QString> memberToClassName = getSignals(m_formWindow->core(), m_source, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = qVariantFromValue(font); + + QListWidgetItem *curr = 0; + QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin(); + const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Signal = isQt3Signal(m_formWindow->core(), m_source, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.signalList); + item->setText(member); + if (!selectedName.isEmpty() && member == selectedName) + curr = item; + + if (qt3Signal) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) { + m_ui.signalList->setCurrentItem(curr); + } else { + selectedName.clear(); + } + + populateSlotList(selectedName); + if (!curr) + m_ui.slotList->setEnabled(false); +} + +void ConnectDialog::editSignals() +{ + editSignalsSlots(m_source, m_sourceMode, SignalSlotDialog::FocusSignals); +} + +void ConnectDialog::editSlots() +{ + editSignalsSlots(m_destination, m_destinationMode, SignalSlotDialog::FocusSlots); +} + +void ConnectDialog::editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogModeInt) +{ + const SignalSlotDialog::FocusMode signalSlotDialogMode = static_cast<SignalSlotDialog::FocusMode>(signalSlotDialogModeInt); + switch (mode) { + case NormalWidget: + break; + case MainContainer: + if (SignalSlotDialog::editMetaDataBase(m_formWindow, w, this, signalSlotDialogMode)) + populateLists(); + break; + case PromotedWidget: + if (SignalSlotDialog::editPromotedClass(m_formWindow->core(), w, this, signalSlotDialogMode)) + populateLists(); + break; + } +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/connectdialog.ui b/tools/designer/src/components/signalsloteditor/connectdialog.ui new file mode 100644 index 0000000..bd062eb --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog.ui @@ -0,0 +1,150 @@ +<ui version="4.0" > + <class>ConnectDialog</class> + <widget class="QDialog" name="ConnectDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>585</width> + <height>361</height> + </rect> + </property> + <property name="windowTitle" > + <string>Configure Connection</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="2" > + <widget class="QGroupBox" name="signalGroupBox" > + <property name="title" > + <string>GroupBox</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QListWidget" name="signalList" > + <property name="textElideMode" > + <enum>Qt::ElideMiddle</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QToolButton" name="editSignalsButton" > + <property name="text" > + <string>Edit...</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="0" column="2" > + <widget class="QGroupBox" name="slotGroupBox" > + <property name="title" > + <string>GroupBox</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QListWidget" name="slotList" > + <property name="textElideMode" > + <enum>Qt::ElideMiddle</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QToolButton" name="editSlotsButton" > + <property name="text" > + <string>Edit...</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" > + <widget class="QCheckBox" name="showAllCheckBox" > + <property name="text" > + <string>Show signals and slots inherited from QWidget</string> + </property> + </widget> + </item> + <item row="2" column="1" colspan="2" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ConnectDialog</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>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ConnectDialog</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/tools/designer/src/components/signalsloteditor/connectdialog_p.h b/tools/designer/src/components/signalsloteditor/connectdialog_p.h new file mode 100644 index 0000000..8fdc019 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONNECTDIALOG_H +#define CONNECTDIALOG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "ui_connectdialog.h" +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QPushButton; + +namespace qdesigner_internal { + +class ConnectDialog : public QDialog +{ + Q_OBJECT +public: + ConnectDialog(QDesignerFormWindowInterface *formWindow, QWidget *sender, QWidget *receiver, QWidget *parent = 0); + + QString signal() const; + QString slot() const; + + void setSignalSlot(const QString &signal, const QString &slot); + + bool showAllSignalsSlots() const; + void setShowAllSignalsSlots(bool showIt); + +private slots: + void populateLists(); + void selectSignal(QListWidgetItem *item); + void selectSlot(QListWidgetItem *item); + void populateSignalList(); + void populateSlotList(const QString &signal = QString()); + void editSignals(); + void editSlots(); + +private: + enum WidgetMode { NormalWidget, MainContainer, PromotedWidget }; + + static WidgetMode widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow); + QPushButton *okButton(); + void setOkButtonEnabled(bool); + void editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogMode); + + QWidget *m_source; + QWidget *m_destination; + const WidgetMode m_sourceMode; + const WidgetMode m_destinationMode; + QDesignerFormWindowInterface *m_formWindow; + Ui::ConnectDialog m_ui; +}; + +} + +QT_END_NAMESPACE + +#endif // CONNECTDIALOG_H diff --git a/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp b/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp new file mode 100644 index 0000000..f4c7693 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalslot_utils_p.h" + +#include <qdesigner_membersheet_p.h> +#include <widgetdatabase_p.h> +#include <metadatabase_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerLanguageExtension> + +#include <QtCore/QPair> + +QT_BEGIN_NAMESPACE + +typedef QPair<QString, QString> ClassNameSignaturePair; + +// Find all member functions that match a predicate on the signature string +// using the member sheet and the fake methods stored in the widget +// database and the meta data base. +// Assign a pair of <classname, signature> to OutputIterator. + +template <class SignaturePredicate, class OutputIterator> +static void memberList(QDesignerFormEditorInterface *core, + QObject *object, + qdesigner_internal::MemberType member_type, + bool showAll, + SignaturePredicate predicate, + OutputIterator it) +{ + if (!object) + return; + + // 1) member sheet + const QDesignerMemberSheetExtension *members = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object); + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) { + if (!members->isVisible(i)) + continue; + + if (member_type == qdesigner_internal::SignalMember && !members->isSignal(i)) + continue; + + if (member_type == qdesigner_internal::SlotMember && !members->isSlot(i)) + continue; + + if (!showAll && members->inheritedFromWidget(i)) + continue; + + const QString signature = members->signature(i); + if (predicate(signature)) { + *it = ClassNameSignaturePair(members->declaredInClass(i), signature); + ++it; + } + } + // 2) fake slots from widget DB + const qdesigner_internal::WidgetDataBase *wdb = qobject_cast<qdesigner_internal::WidgetDataBase *>(core->widgetDataBase()); + if (!wdb) + return; + const int idx = wdb->indexOfObject(object); + Q_ASSERT(idx != -1); + // get the promoted class name + const qdesigner_internal::WidgetDataBaseItem *wdbItem = static_cast<qdesigner_internal::WidgetDataBaseItem *>(wdb->item(idx)); + const QString className = wdbItem->name(); + + const QStringList wdbFakeMethods = member_type == qdesigner_internal::SlotMember ? wdbItem->fakeSlots() : wdbItem->fakeSignals(); + if (!wdbFakeMethods.empty()) + foreach (const QString &fakeMethod, wdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } + // 3) fake slots from meta DB + qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase()); + if (!metaDataBase) + return; + + const qdesigner_internal::MetaDataBaseItem *mdbItem = metaDataBase->metaDataBaseItem(object); + Q_ASSERT(mdbItem); + const QStringList mdbFakeMethods = member_type == qdesigner_internal::SlotMember ? mdbItem->fakeSlots() : mdbItem->fakeSignals(); + if (!mdbFakeMethods.empty()) + foreach (const QString &fakeMethod, mdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } +} + +namespace { + // Predicate that matches the exact signature string + class EqualsPredicate { + public: + EqualsPredicate(const QString &pattern) : m_pattern(pattern) {} + bool operator()(const QString &s) const { return s == m_pattern; } + private: + const QString m_pattern; + }; + // Predicate for a QString member signature that matches signals up with slots and vice versa + class SignalMatchesSlotPredicate { + public: + SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType); + bool operator()(const QString &s) const; + + private: + bool signalMatchesSlot(const QString &signal, const QString &slot) const; + + const QString m_peer; + qdesigner_internal::MemberType m_memberType; + const QDesignerLanguageExtension *m_lang; + }; + + SignalMatchesSlotPredicate::SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType) : + m_peer(peer), + m_memberType(memberType), + m_lang(qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) + { + } + + bool SignalMatchesSlotPredicate::operator()(const QString &s) const + { + return m_memberType == qdesigner_internal::SlotMember ? signalMatchesSlot(m_peer, s) : signalMatchesSlot(s, m_peer); + } + + bool SignalMatchesSlotPredicate::signalMatchesSlot(const QString &signal, const QString &slot) const + { + if (m_lang) + return m_lang->signalMatchesSlot(signal, slot); + + return QDesignerMemberSheet::signalMatchesSlot(signal, slot); + } + + // Output iterator for a pair of pair of <classname, signature> + // that builds the reverse class list for reverseClassesMemberFunctions() + // (for the combos of the ToolWindow) + class ReverseClassesMemberIterator { + public: + ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result); + + ReverseClassesMemberIterator &operator*() { return *this; } + ReverseClassesMemberIterator &operator++(int) { return *this; } + ReverseClassesMemberIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature); + + private: + qdesigner_internal::ClassesMemberFunctions *m_result; + QString m_lastClassName; + QStringList *m_memberList; + }; + + ReverseClassesMemberIterator::ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result) : + m_result(result), + m_memberList(0) + { + } + + void ReverseClassesMemberIterator::operator=(const ClassNameSignaturePair &classNameSignature) + { + // prepend a new entry if class changes + if (!m_memberList || classNameSignature.first != m_lastClassName) { + m_lastClassName = classNameSignature.first; + m_result->push_front(qdesigner_internal::ClassMemberFunctions(m_lastClassName)); + m_memberList = &(m_result->front().m_memberList); + } + m_memberList->push_back(classNameSignature.second); + } + + // Output iterator for a pair of pair of <classname, signature> + // that adds the signatures to a string list + class SignatureIterator { + public: + SignatureIterator(QMap<QString, QString> *result) : m_result(result) {} + + SignatureIterator &operator*() { return *this; } + SignatureIterator &operator++(int) { return *this; } + SignatureIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature) { + m_result->insert(classNameSignature.second, classNameSignature.first); + } + + private: + QMap<QString, QString> *m_result; + }; +} + +static inline bool truePredicate(const QString &) { return true; } + +namespace qdesigner_internal { + + ClassMemberFunctions::ClassMemberFunctions(const QString &class_name) : + m_className(class_name) + { + } + + bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot) + { + const SignalMatchesSlotPredicate predicate(core, signal, qdesigner_internal::SlotMember); + return predicate(slot); + } + + // return classes and members in reverse class order to + // populate of the combo of the ToolWindow + ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form) + { + QObject *object = qFindChild<QObject*>(form, obj_name); + if (!object) + return ClassesMemberFunctions(); + + QDesignerFormEditorInterface *core = form->core(); + + ClassesMemberFunctions rc; + memberList(form->core(), object, member_type, true, SignalMatchesSlotPredicate(core, peer, member_type), + ReverseClassesMemberIterator(&rc)); + return rc; + } + + QMap<QString, QString> getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll) + { + QMap<QString, QString> rc; + memberList(core, object, SignalMember, showAll, truePredicate, SignatureIterator(&rc)); + return rc; + } + + bool isQt3Signal(QDesignerFormEditorInterface *core, + QObject *object, const QString &signalSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object)) { + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSignal(i) && members->signature(i) == signalSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast<QDesignerMemberSheet*>(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return memberSheet->isQt3Signal(i); + } + } + + return false; + } + + bool isQt3Slot(QDesignerFormEditorInterface *core, + QObject *object, const QString &slotSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object)) { + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSlot(i) && members->signature(i) == slotSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast<QDesignerMemberSheet*>(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return memberSheet->isQt3Slot(i); + } + } + return false; + } + + QMap<QString, QString> getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature, bool showAll) + { + QMap<QString, QString> rc; + memberList(core, object, SlotMember, showAll, SignalMatchesSlotPredicate(core, signalSignature, qdesigner_internal::SlotMember), SignatureIterator(&rc)); + return rc; + } + + bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature) + { + QMap<QString, QString> rc; + memberList(core, object, type, true, EqualsPredicate(signature), SignatureIterator(&rc)); + return !rc.empty(); + } + + // ### deprecated + QString realObjectName(QDesignerFormEditorInterface *core, QObject *object) + { + if (!object) + return QString(); + + const QDesignerMetaDataBaseInterface *mdb = core->metaDataBase(); + if (const QDesignerMetaDataBaseItemInterface *item = mdb->item(object)) + return item->name(); + + return object->objectName(); + } +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h b/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h new file mode 100644 index 0000000..9b051e4 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTUTILS_P_H +#define SIGNALSLOTUTILS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +enum MemberType { SignalMember, SlotMember }; + +// member to class name +QMap<QString, QString> getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll); +QMap<QString, QString> getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, + const QString &signalSignature, bool showAll); + +bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature); + +// Members functions listed by class they were inherited from +struct ClassMemberFunctions +{ + ClassMemberFunctions() {} + ClassMemberFunctions(const QString &_class_name); + + QString m_className; + QStringList m_memberList; +}; + +typedef QList<ClassMemberFunctions> ClassesMemberFunctions; + +// Return classes and members in reverse class order to +// populate of the combo of the ToolWindow. + +ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form); + +bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot); + +QString realObjectName(QDesignerFormEditorInterface *core, QObject *object); + +bool isQt3Signal(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); +bool isQt3Slot(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTUTILS_P_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp new file mode 100644 index 0000000..511b91f --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp @@ -0,0 +1,528 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditor.h" +#include "signalsloteditor_p.h" +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include <metadatabase_p.h> +#include <ui4_p.h> +#include <qdesigner_formwindowcommand_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> + +#include <QtGui/QApplication> +#include <QtGui/QUndoCommand> +#include <QtGui/QMenu> + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotConnection +*/ + +SignalSlotConnection::SignalSlotConnection(ConnectionEdit *edit, QWidget *source, QWidget *target) + : Connection(edit, source, target) +{ +} + +DomConnection *SignalSlotConnection::toUi() const +{ + DomConnection *result = new DomConnection; + + result->setElementSender(sender()); + result->setElementSignal(signal()); + result->setElementReceiver(receiver()); + result->setElementSlot(slot()); + + DomConnectionHints *hints = new DomConnectionHints; + QList<DomConnectionHint*> list; + + QPoint sp = endPointPos(EndPoint::Source); + QPoint tp = endPointPos(EndPoint::Target); + + DomConnectionHint *hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("sourcelabel")); + hint->setElementX(sp.x()); + hint->setElementY(sp.y()); + list.append(hint); + + hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("destinationlabel")); + hint->setElementX(tp.x()); + hint->setElementY(tp.y()); + list.append(hint); + + hints->setElementHint(list); + result->setElementHints(hints); + + return result; +} + +void SignalSlotConnection::setSignal(const QString &signal) +{ + m_signal = signal; + setLabel(EndPoint::Source, m_signal); +} + +void SignalSlotConnection::setSlot(const QString &slot) +{ + m_slot = slot; + setLabel(EndPoint::Target, m_slot); +} + +QString SignalSlotConnection::sender() const +{ + QObject *source = object(EndPoint::Source); + if (!source) + return QString(); + + SignalSlotEditor *edit = qobject_cast<SignalSlotEditor*>(this->edit()); + Q_ASSERT(edit != 0); + + return realObjectName(edit->formWindow()->core(), source); +} + +QString SignalSlotConnection::receiver() const +{ + QObject *sink = object(EndPoint::Target); + if (!sink) + return QString(); + + SignalSlotEditor *edit = qobject_cast<SignalSlotEditor*>(this->edit()); + Q_ASSERT(edit != 0); + return realObjectName(edit->formWindow()->core(), sink); +} + +void SignalSlotConnection::updateVisibility() +{ + Connection::updateVisibility(); + if (isVisible() && (signal().isEmpty() || slot().isEmpty())) + setVisible(false); +} + +QString SignalSlotConnection::toString() const +{ + return QCoreApplication::translate("SignalSlotConnection", "SENDER(%1), SIGNAL(%2), RECEIVER(%3), SLOT(%4)") + .arg(sender()).arg(signal()).arg(receiver()).arg(slot()); +} + +SignalSlotConnection::State SignalSlotConnection::isValid(const QWidget *background) const +{ + const QObject *source = object(EndPoint::Source); + if (!source) + return ObjectDeleted; + + const QObject *target = object(EndPoint::Target); + if (!target) + return ObjectDeleted; + + if (m_slot.isEmpty() || m_signal.isEmpty()) + return InvalidMethod; + + if (const QWidget *sourceWidget = qobject_cast<const QWidget*>(source)) + if (!background->isAncestorOf(sourceWidget)) + return NotAncestor; + + if (const QWidget *targetWidget = qobject_cast<const QWidget*>(target)) + if (!background->isAncestorOf(targetWidget)) + return NotAncestor; + + return Valid; +} + +/******************************************************************************* +** Commands +*/ + +class SetMemberCommand : public QUndoCommand, public CETypes +{ +public: + SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor); + virtual void redo(); + virtual void undo(); +private: + const QString m_old_member; + const QString m_new_member; + const EndPoint::Type m_type; + SignalSlotConnection *m_con; + SignalSlotEditor *m_editor; +}; + +SetMemberCommand::SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor) : + m_old_member(type == EndPoint::Source ? con->signal() : con->slot()), + m_new_member(member), + m_type(type), + m_con(con), + m_editor(editor) +{ + if (type == EndPoint::Source) + setText(QApplication::translate("Command", "Change signal")); + else + setText(QApplication::translate("Command", "Change slot")); +} + +void SetMemberCommand::redo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_new_member); + else + m_con->setSlot(m_new_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +void SetMemberCommand::undo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_old_member); + else + m_con->setSlot(m_old_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +// Command to modify a connection +class ModifyConnectionCommand : public QDesignerFormWindowCommand +{ +public: + explicit ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot); + virtual void redo(); + virtual void undo(); + +private: + SignalSlotConnection *m_conn; + const QString m_oldSignal; + const QString m_oldSlot; + const QString m_newSignal; + const QString m_newSlot; +}; + +ModifyConnectionCommand::ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot) : + QDesignerFormWindowCommand(QCoreApplication::translate("Command", "Change signal-slot connection"), form), + m_conn(conn), + m_oldSignal(conn->signal()), + m_oldSlot(conn->slot()), + m_newSignal(newSignal), + m_newSlot(newSlot) +{ +} + +void ModifyConnectionCommand::redo() +{ + m_conn->setSignal(m_newSignal); + m_conn->setSlot(m_newSlot); +} + +void ModifyConnectionCommand::undo() +{ + m_conn->setSignal(m_oldSignal); + m_conn->setSlot(m_oldSlot); +} + +/******************************************************************************* +** SignalSlotEditor +*/ + +SignalSlotEditor::SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent) : + ConnectionEdit(parent, form_window), + m_form_window(form_window), + m_showAllSignalsSlots(false) +{ +} + +void SignalSlotEditor::modifyConnection(Connection *con) +{ + SignalSlotConnection *sigslot_con = static_cast<SignalSlotConnection*>(con); + ConnectDialog dialog(m_form_window, + sigslot_con->widget(EndPoint::Source), + sigslot_con->widget(EndPoint::Target), + m_form_window->core()->topLevel()); + + dialog.setSignalSlot(sigslot_con->signal(), sigslot_con->slot()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + const QString newSignal = dialog.signal(); + const QString newSlot = dialog.slot(); + if (sigslot_con->signal() != newSignal || sigslot_con->slot() != newSlot) { + ModifyConnectionCommand *cmd = new ModifyConnectionCommand(m_form_window, sigslot_con, newSignal, newSlot); + m_form_window->commandHistory()->push(cmd); + } + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); +} + +Connection *SignalSlotEditor::createConnection(QWidget *source, QWidget *destination) +{ + SignalSlotConnection *con = 0; + + Q_ASSERT(source != 0); + Q_ASSERT(destination != 0); + + ConnectDialog dialog(m_form_window, source, destination, m_form_window->core()->topLevel()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + con = new SignalSlotConnection(this, source, destination); + con->setSignal(dialog.signal()); + con->setSlot(dialog.slot()); + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); + + return con; +} + +DomConnections *SignalSlotEditor::toUi() const +{ + DomConnections *result = new DomConnections; + QList<DomConnection*> list; + + const int count = connectionCount(); + for (int i = 0; i < count; ++i) { + const SignalSlotConnection *con = static_cast<const SignalSlotConnection*>(connection(i)); + Q_ASSERT(con != 0); + + // If a widget's parent has been removed or moved to a different form, + // and the parent was not a managed widget + // (a page in a tab widget), we never get a widgetRemoved(). So we filter out + // these child widgets here (check QPointer and verify ancestor). + // Also, the user might demote a promoted widget or remove a fake + // slot in the editor, which causes the connection to become invalid + // once he doubleclicks on the method combo. + switch (con->isValid(background())) { + case SignalSlotConnection::Valid: + list.append(con->toUi()); + break; + case SignalSlotConnection::ObjectDeleted: + case SignalSlotConnection::InvalidMethod: + case SignalSlotConnection::NotAncestor: + break; + } + } + result->setElementConnection(list); + return result; +} + +QObject *SignalSlotEditor::objectByName(QWidget *topLevel, const QString &name) const +{ + if (name.isEmpty()) + return 0; + + Q_ASSERT(topLevel); + QObject *object = 0; + if (topLevel->objectName() == name) + object = topLevel; + else + object = qFindChild<QObject*>(topLevel, name); + const QDesignerMetaDataBaseInterface *mdb = formWindow()->core()->metaDataBase(); + if (mdb->item(object)) + return object; + return 0; +} + +void SignalSlotEditor::fromUi(const DomConnections *connections, QWidget *parent) +{ + if (connections == 0) + return; + + setBackground(parent); + clear(); + const QList<DomConnection*> list = connections->elementConnection(); + foreach (const DomConnection *dom_con, list) { + QObject *source = objectByName(parent, dom_con->elementSender()); + if (source == 0) { + qDebug("SignalSlotEditor::fromUi(): no source widget called \"%s\"", + dom_con->elementSender().toUtf8().constData()); + continue; + } + QObject *destination = objectByName(parent, dom_con->elementReceiver()); + if (destination == 0) { + qDebug("SignalSlotEditor::fromUi(): no destination widget called \"%s\"", + dom_con->elementReceiver().toUtf8().constData()); + continue; + } + + QPoint sp = QPoint(20, 20), tp = QPoint(20, 20); + const DomConnectionHints *dom_hints = dom_con->elementHints(); + if (dom_hints != 0) { + QList<DomConnectionHint*> list = dom_hints->elementHint(); + foreach (DomConnectionHint *hint, list) { + QString attr_type = hint->attributeType(); + QPoint p = QPoint(hint->elementX(), hint->elementY()); + if (attr_type == QLatin1String("sourcelabel")) + sp = p; + else if (attr_type == QLatin1String("destinationlabel")) + tp = p; + } + } + + SignalSlotConnection *con = new SignalSlotConnection(this); + + con->setEndPoint(EndPoint::Source, source, sp); + con->setEndPoint(EndPoint::Target, destination, tp); + con->setSignal(dom_con->elementSignal()); + con->setSlot(dom_con->elementSlot()); + addConnection(con); + } +} + +static bool skipWidget(const QWidget *w) +{ + const QString name = QLatin1String(w->metaObject()->className()); + if (name == QLatin1String("QDesignerWidget")) + return true; + if (name == QLatin1String("QLayoutWidget")) + return true; + if (name == QLatin1String("qdesigner_internal::FormWindow")) + return true; + if (name == QLatin1String("Spacer")) + return true; + return false; +} + +QWidget *SignalSlotEditor::widgetAt(const QPoint &pos) const +{ + QWidget *widget = ConnectionEdit::widgetAt(pos); + + if (widget == m_form_window->mainContainer()) + return widget; + + for (; widget != 0; widget = widget->parentWidget()) { + QDesignerMetaDataBaseItemInterface *item = m_form_window->core()->metaDataBase()->item(widget); + if (item == 0) + continue; + if (skipWidget(widget)) + continue; + break; + } + + return widget; +} + +void SignalSlotEditor::setSignal(SignalSlotConnection *con, const QString &member) +{ + if (member == con->signal()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change signal")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, member, this)); + if (!signalMatchesSlot(m_form_window->core(), member, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSlot(SignalSlotConnection *con, const QString &member) +{ + if (member == con->slot()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change slot")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, member, this)); + if (!signalMatchesSlot(m_form_window->core(), con->signal(), member)) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSource(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(_con); + + if (con->sender() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change sender")); + ConnectionEdit::setSource(con, obj_name); + + QObject *sourceObject = con->object(EndPoint::Source); + + if (!memberFunctionListContains(m_form_window->core(), sourceObject, SignalMember, con->signal())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::setTarget(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(_con); + + if (con->receiver() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change receiver")); + ConnectionEdit::setTarget(con, obj_name); + + QObject *targetObject = con->object(EndPoint::Target); + if (!memberFunctionListContains(m_form_window->core(), targetObject, SlotMember, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::addEmptyConnection() +{ + SignalSlotConnection *con = new SignalSlotConnection(this); + undoStack()->push(new AddConnectionCommand(this, con)); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.h b/tools/designer/src/components/signalsloteditor/signalsloteditor.h new file mode 100644 index 0000000..f330ca0 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_H +#define SIGNALSLOTEDITOR_H + +#include "signalsloteditor_global.h" + +#include <QtDesigner/private/connectionedit_p.h> + +#include <QtXml/QDomDocument> +#include <QtXml/QDomElement> + +QT_BEGIN_NAMESPACE + +class DomConnections; + +namespace qdesigner_internal { + +class SignalSlotConnection; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditor : public ConnectionEdit +{ + Q_OBJECT + +public: + SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent); + + virtual void setSignal(SignalSlotConnection *con, const QString &member); + virtual void setSlot(SignalSlotConnection *con, const QString &member); + virtual void setSource(Connection *con, const QString &obj_name); + virtual void setTarget(Connection *con, const QString &obj_name); + + DomConnections *toUi() const; + void fromUi(const DomConnections *connections, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const { return m_form_window; } + + QObject *objectByName(QWidget *topLevel, const QString &name) const; + + void addEmptyConnection(); + +protected: + virtual QWidget *widgetAt(const QPoint &pos) const; + +private: + virtual Connection *createConnection(QWidget *source, QWidget *destination); + virtual void modifyConnection(Connection *con); + + QDesignerFormWindowInterface *m_form_window; + bool m_showAllSignalsSlots; + + friend class SetMemberCommand; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.pri b/tools/designer/src/components/signalsloteditor/signalsloteditor.pri new file mode 100644 index 0000000..e903ce1 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.pri @@ -0,0 +1,21 @@ + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/signalslot_utils_p.h \ + $$PWD/connectdialog_p.h \ + $$PWD/signalsloteditor.h \ + $$PWD/signalsloteditor_tool.h \ + $$PWD/signalsloteditor_plugin.h \ + $$PWD/signalsloteditor_global.h \ + $$PWD/signalsloteditor_p.h \ + $$PWD/signalsloteditorwindow.h + +SOURCES += $$PWD/signalslot_utils.cpp \ + $$PWD/connectdialog.cpp \ + $$PWD/signalsloteditor.cpp \ + $$PWD/signalsloteditor_tool.cpp \ + $$PWD/signalsloteditor_plugin.cpp \ + $$PWD/signalsloteditor_instance.cpp \ + $$PWD/signalsloteditorwindow.cpp + +FORMS += $$PWD/connectdialog.ui diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h new file mode 100644 index 0000000..399778a --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_GLOBAL_H +#define SIGNALSLOTEDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_SIGNALSLOTEDITOR_LIBRARY +# define QT_SIGNALSLOTEDITOR_EXPORT +#else +# define QT_SIGNALSLOTEDITOR_EXPORT +#endif +#else +#define QT_SIGNALSLOTEDITOR_EXPORT +#endif + +#endif // SIGNALSLOTEDITOR_GLOBAL_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp new file mode 100644 index 0000000..c7a799a --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qplugin.h> + +#include "signalsloteditor_plugin.h" + +QT_USE_NAMESPACE + +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(SignalSlotEditorPlugin) diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h new file mode 100644 index 0000000..8cec010 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_P_H +#define SIGNALSLOTEDITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> +#include <QtCore/QPointer> +#include <QtCore/QAbstractItemModel> + +#include <connectionedit_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class DomConnection; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class SignalSlotConnection : public Connection +{ +public: + explicit SignalSlotConnection(ConnectionEdit *edit, QWidget *source = 0, QWidget *target = 0); + + void setSignal(const QString &signal); + void setSlot(const QString &slot); + + QString sender() const; + QString receiver() const; + inline QString signal() const { return m_signal; } + inline QString slot() const { return m_slot; } + + DomConnection *toUi() const; + + virtual void updateVisibility(); + + enum State { Valid, ObjectDeleted, InvalidMethod, NotAncestor }; + State isValid(const QWidget *background) const; + + // format for messages, etc. + QString toString() const; + +private: + QString m_signal, m_slot; +}; + +class ConnectionModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit ConnectionModel(QObject *parent = 0); + void setEditor(SignalSlotEditor *editor = 0); + + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &child) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::DisplayRole); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QModelIndex connectionToIndex(Connection *con) const; + Connection *indexToConnection(const QModelIndex &index) const; + void updateAll(); + +private slots: + void connectionAdded(Connection *con); + void connectionRemoved(int idx); + void aboutToRemoveConnection(Connection *con); + void aboutToAddConnection(int idx); + void connectionChanged(Connection *con); + +private: + QPointer<SignalSlotEditor> m_editor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_P_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp new file mode 100644 index 0000000..311c843 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::SignalSlotEditorPlugin +*/ + +#include "signalsloteditor_plugin.h" +#include "signalsloteditor_tool.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtGui/QAction> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorPlugin::SignalSlotEditorPlugin() + : m_initialized(false), m_action(0) +{ +} + +SignalSlotEditorPlugin::~SignalSlotEditorPlugin() +{ +} + +bool SignalSlotEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void SignalSlotEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Signals/Slots"), this); + m_action->setObjectName(QLatin1String("__qt_edit_signals_slots_action")); + m_action->setShortcut(tr("F4")); + QIcon icon(QIcon(core->resourceLocation() + QLatin1String("/signalslottool.png"))); + m_action->setIcon(icon); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +QDesignerFormEditorInterface *SignalSlotEditorPlugin::core() const +{ + return m_core; +} + +void SignalSlotEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + SignalSlotEditorTool *tool = new SignalSlotEditorTool(formWindow, this); + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + m_tools[formWindow] = tool; + formWindow->registerTool(tool); +} + +void SignalSlotEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + SignalSlotEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *SignalSlotEditorPlugin::action() const +{ + return m_action; +} + +void SignalSlotEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h new file mode 100644 index 0000000..546110d --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_PLUGIN_H +#define SIGNALSLOTEDITOR_PLUGIN_H + +#include "signalsloteditor_global.h" + +#include <QtDesigner/QDesignerFormEditorPluginInterface> + +#include <QtCore/QPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class SignalSlotEditorTool; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + SignalSlotEditorPlugin(); + virtual ~SignalSlotEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + virtual QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer<QDesignerFormEditorInterface> m_core; + QHash<QDesignerFormWindowInterface*, SignalSlotEditorTool*> m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_PLUGIN_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp new file mode 100644 index 0000000..973105c --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::SignalSlotEditorTool +*/ + +#include "signalsloteditor_tool.h" +#include "signalsloteditor.h" +#include "ui4_p.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorTool::SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Signals/Slots"), this)) +{ +} + +SignalSlotEditorTool::~SignalSlotEditorTool() +{ +} + +QDesignerFormEditorInterface *SignalSlotEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *SignalSlotEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool SignalSlotEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(event); + + return false; +} + +QWidget *SignalSlotEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new qdesigner_internal::SignalSlotEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); + } + + return m_editor; +} + +QAction *SignalSlotEditorTool::action() const +{ + return m_action; +} + +void SignalSlotEditorTool::activated() +{ + m_editor->enableUpdateBackground(true); +} + +void SignalSlotEditorTool::deactivated() +{ + m_editor->enableUpdateBackground(false); +} + +void SignalSlotEditorTool::saveToDom(DomUI *ui, QWidget*) +{ + ui->setElementConnections(m_editor->toUi()); +} + +void SignalSlotEditorTool::loadFromDom(DomUI *ui, QWidget *mainContainer) +{ + m_editor->fromUi(ui->elementConnections(), mainContainer); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h new file mode 100644 index 0000000..97ea831 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_TOOL_H +#define SIGNALSLOTEDITOR_TOOL_H + +#include "signalsloteditor_global.h" +#include "signalsloteditor.h" + +#include <QtCore/QPointer> +#include <QtDesigner/QDesignerFormWindowToolInterface> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~SignalSlotEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + + QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + virtual void saveToDom(DomUI *ui, QWidget *mainContainer); + virtual void loadFromDom(DomUI *ui, QWidget *mainContainer); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer<qdesigner_internal::SignalSlotEditor> m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_TOOL_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp new file mode 100644 index 0000000..dc6b3c3 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp @@ -0,0 +1,859 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ConnectionModel +*/ + +#include "signalsloteditorwindow.h" +#include "signalsloteditor_p.h" +#include "signalsloteditor.h" +#include "qdesigner_integration_p.h" +#include "signalslot_utils_p.h" + +#include <iconloader_p.h> +#include <spacer_widget_p.h> +#include <qlayout_widget_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <abstractdialoggui_p.h> + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QDebug> +#include <QtGui/QAction> +#include <QtGui/QButtonGroup> +#include <QtGui/QMenu> +#include <QtGui/QStandardItemModel> +#include <QtGui/QComboBox> +#include <QtGui/QApplication> +#include <QtGui/QItemDelegate> +#include <QtGui/QItemEditorFactory> +#include <QtGui/QTreeView> +#include <QtGui/QHeaderView> +#include <QtGui/QVBoxLayout> +#include <QtGui/QToolButton> +#include <QtGui/QButtonGroup> + +QT_BEGIN_NAMESPACE + +// Add suitable form widgets to a list of objects for the signal slot +// editor. Prevent special widgets from showing up there. +static void addWidgetToObjectList(const QWidget *w, QStringList &r) +{ + const QMetaObject *mo = w->metaObject(); + if (mo != &QLayoutWidget::staticMetaObject && mo != &Spacer::staticMetaObject) { + const QString name = w->objectName().trimmed(); + if (!name.isEmpty()) + r.push_back(name); + } +} + +static QStringList objectNameList(QDesignerFormWindowInterface *form) +{ + typedef QList<QAction*> ActionList; + typedef QList<QButtonGroup *> ButtonGroupList; + + QStringList result; + + QWidget *mainContainer = form->mainContainer(); + if (!mainContainer) + return result; + + // Add main container container pages (QStatusBar, QWizardPages) etc. + // to the list. Pages of containers on the form are not added, however. + if (const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension *>(form->core()->extensionManager(), mainContainer)) { + const int count = c->count(); + for (int i = 0 ; i < count; i++) + addWidgetToObjectList(c->widget(i), result); + } + + const QDesignerFormWindowCursorInterface *cursor = form->cursor(); + const int widgetCount = cursor->widgetCount(); + for (int i = 0; i < widgetCount; ++i) + addWidgetToObjectList(cursor->widget(i), result); + + const QDesignerMetaDataBaseInterface *mdb = form->core()->metaDataBase(); + + // Add managed actions and actions with managed menus + const ActionList actions = qFindChildren<QAction*>(mainContainer); + if (!actions.empty()) { + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { + QAction *a = *it; + if (!a->isSeparator()) { + if (QMenu *menu = a->menu()) { + if (mdb->item(menu)) + result.push_back(menu->objectName()); + } else { + if (mdb->item(a)) + result.push_back(a->objectName()); + } + } + } + } + + // Add managed buttons groups + const ButtonGroupList buttonGroups = qFindChildren<QButtonGroup *>(mainContainer); + if (!buttonGroups.empty()) { + const ButtonGroupList::const_iterator cend = buttonGroups.constEnd(); + for (ButtonGroupList::const_iterator it = buttonGroups.constBegin(); it != cend; ++it) + if (mdb->item(*it)) + result.append((*it)->objectName()); + } + + result.sort(); + return result; +} + +namespace qdesigner_internal { + +// ------------ ConnectionModel + +ConnectionModel::ConnectionModel(QObject *parent) : + QAbstractItemModel(parent) +{ +} + +void ConnectionModel::setEditor(SignalSlotEditor *editor) +{ + if (m_editor == editor) + return; + + if (m_editor) { + disconnect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + disconnect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + disconnect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + disconnect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + disconnect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + m_editor = editor; + if (m_editor) { + connect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + connect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + connect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + connect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + connect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + reset(); +} + +QVariant ConnectionModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + + static const QVariant senderTitle = tr("Sender"); + static const QVariant signalTitle = tr("Signal"); + static const QVariant receiverTitle = tr("Receiver"); + static const QVariant slotTitle = tr("Slot"); + + switch (section) { + case 0: + return senderTitle; + case 1: + return signalTitle; + case 2: + return receiverTitle; + case 3: + return slotTitle; + } + return QVariant(); +} + +QModelIndex ConnectionModel::index(int row, int column, + const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return QModelIndex(); + if (row < 0 || row >= m_editor->connectionCount()) + return QModelIndex(); + return createIndex(row, column); +} + +Connection *ConnectionModel::indexToConnection(const QModelIndex &index) const +{ + if (!index.isValid() || !m_editor) + return 0; + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) + return 0; + return m_editor->connection(index.row()); +} + +QModelIndex ConnectionModel::connectionToIndex(Connection *con) const +{ + Q_ASSERT(m_editor); + return createIndex(m_editor->indexOfConnection(con), 0); +} + +QModelIndex ConnectionModel::parent(const QModelIndex&) const +{ + return QModelIndex(); +} + +int ConnectionModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return 0; + return m_editor->connectionCount(); +} + +int ConnectionModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return 4; +} + +QVariant ConnectionModel::data(const QModelIndex &index, int role) const +{ + if ((role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole && role != Qt::ForegroundRole) || !m_editor) + return QVariant(); + + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) { + return QVariant(); + } + + const SignalSlotConnection *con = static_cast<SignalSlotConnection*>(m_editor->connection(index.row())); + Q_ASSERT(con != 0); + + if (role == Qt::FontRole || role == Qt::ForegroundRole) { + bool isQt3Member = false; + if (index.column() == 1) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Source), con->signal()); + } else if (index.column() == 3) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Target), con->slot()); + } + if (isQt3Member) { + if (role == Qt::ForegroundRole) + return Qt::red; + QFont font = QApplication::font(); + font.setItalic(true); + return font; + } + return QVariant(); + } + + static const QVariant senderDefault = tr("<sender>"); + static const QVariant signalDefault = tr("<signal>"); + static const QVariant receiverDefault = tr("<receiver>"); + static const QVariant slotDefault = tr("<slot>"); + + switch (index.column()) { + case 0: { + const QString sender = con->sender(); + if (sender.isEmpty()) + return senderDefault; + return sender; + } + case 1: { + const QString signal = con->signal(); + if (signal.isEmpty()) + return signalDefault; + return signal; + } + case 2: { + const QString receiver = con->receiver(); + if (receiver.isEmpty()) + return receiverDefault; + return receiver; + } + case 3: { + const QString slot = con->slot(); + if (slot.isEmpty()) + return slotDefault; + return slot; + } + } + return QVariant(); +} + +bool ConnectionModel::setData(const QModelIndex &index, const QVariant &data, int) +{ + if (!index.isValid() || !m_editor) + return false; + if (data.type() != QVariant::String) + return false; + + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(m_editor->connection(index.row())); + QDesignerFormWindowInterface *form = m_editor->formWindow(); + + QString s = data.toString(); + switch (index.column()) { + case 0: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setSource(con, s); + break; + case 1: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Source), SignalMember, s)) + s.clear(); + m_editor->setSignal(con, s); + break; + case 2: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setTarget(con, s); + break; + case 3: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Target), SlotMember, s)) + s.clear(); + m_editor->setSlot(con, s); + break; + } + + return true; +} + +void ConnectionModel::connectionAdded(Connection*) +{ + endInsertRows(); +} + +void ConnectionModel::connectionRemoved(int) +{ + endRemoveRows(); +} + +void ConnectionModel::aboutToRemoveConnection(Connection *con) +{ + Q_ASSERT(m_editor); + int idx = m_editor->indexOfConnection(con); + beginRemoveRows(QModelIndex(), idx, idx); +} + +void ConnectionModel::aboutToAddConnection(int idx) +{ + Q_ASSERT(m_editor); + beginInsertRows(QModelIndex(), idx, idx); +} + +Qt::ItemFlags ConnectionModel::flags(const QModelIndex&) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; +} + +void ConnectionModel::connectionChanged(Connection *con) +{ + Q_ASSERT(m_editor); + const int idx = m_editor->indexOfConnection(con); + SignalSlotConnection *changedCon = static_cast<SignalSlotConnection*>(m_editor->connection(idx)); + SignalSlotConnection *c = 0; + for (int i=0; i<m_editor->connectionCount(); ++i) { + if (i == idx) + continue; + c = static_cast<SignalSlotConnection*>(m_editor->connection(i)); + if (c->sender() == changedCon->sender() && c->signal() == changedCon->signal() + && c->receiver() == changedCon->receiver() && c->slot() == changedCon->slot()) { + const QString message = tr("The connection already exists!<br>%1").arg(changedCon->toString()); + m_editor->formWindow()->core()->dialogGui()->message(m_editor->parentWidget(), QDesignerDialogGuiInterface::SignalSlotEditorMessage, + QMessageBox::Warning, tr("Signal and Slot Editor"), message, QMessageBox::Ok); + break; + } + } + emit dataChanged(createIndex(idx, 0), createIndex(idx, 3)); +} + +void ConnectionModel::updateAll() +{ + emit dataChanged(index(0, 0), index(rowCount(), columnCount())); +} +} + +namespace { +// ---------------------- InlineEditorModel + +class InlineEditorModel : public QStandardItemModel +{ + Q_OBJECT +public: + enum { TitleItem = 1 }; + + InlineEditorModel(int rows, int cols, QObject *parent = 0); + + void addTitle(const QString &title); + void addTextList(const QMap<QString, bool> &text_list); + void addText(const QString &text); + bool isTitle(int idx) const; + + int findText(const QString &text) const; + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; +}; + +InlineEditorModel::InlineEditorModel(int rows, int cols, QObject *parent) + : QStandardItemModel(rows, cols, parent) +{ +} + +void InlineEditorModel::addTitle(const QString &title) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + QModelIndex cat_idx = index(cnt, 0); + setData(cat_idx, title + QLatin1Char(':'), Qt::DisplayRole); + setData(cat_idx, TitleItem, Qt::UserRole); + QFont font = QApplication::font(); + font.setBold(true); + setData(cat_idx, font, Qt::FontRole); +} + +bool InlineEditorModel::isTitle(int idx) const +{ + if (idx == -1) + return false; + + return data(index(idx, 0), Qt::UserRole).toInt() == TitleItem; +} + +void InlineEditorModel::addText(const QString &text) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + setData(index(cnt, 0), text, Qt::DisplayRole); +} + +void InlineEditorModel::addTextList(const QMap<QString, bool> &text_list) +{ + int cnt = rowCount(); + insertRows(cnt, text_list.size()); + QFont font = QApplication::font(); + font.setItalic(true); + QVariant fontVariant = qVariantFromValue(font); + QMap<QString, bool>::ConstIterator it = text_list.constBegin(); + const QMap<QString, bool>::ConstIterator itEnd = text_list.constEnd(); + while (it != itEnd) { + const QModelIndex text_idx = index(cnt++, 0); + setData(text_idx, it.key(), Qt::DisplayRole); + if (it.value()) { + setData(text_idx, fontVariant, Qt::FontRole); + setData(text_idx, Qt::red, Qt::ForegroundRole); + } + ++it; + } +} + +Qt::ItemFlags InlineEditorModel::flags(const QModelIndex &index) const +{ + if (isTitle(index.row())) + return Qt::ItemIsEnabled; + else + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +int InlineEditorModel::findText(const QString &text) const +{ + const int cnt = rowCount(); + for (int i = 0; i < cnt; ++i) { + const QModelIndex idx = index(i, 0); + if (data(idx, Qt::UserRole).toInt() == TitleItem) + continue; + if (data(idx, Qt::DisplayRole).toString() == text) + return i; + } + return -1; +} + +// ------------ InlineEditor +class InlineEditor : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText USER true) +public: + InlineEditor(QWidget *parent = 0); + + QString text() const; + void setText(const QString &text); + + void addTitle(const QString &title); + void addText(const QString &text); + void addTextList(const QMap<QString, bool> &text_list); + +private slots: + void checkSelection(int idx); + +private: + InlineEditorModel *m_model; + int m_idx; +}; + +InlineEditor::InlineEditor(QWidget *parent) : + QComboBox(parent), + m_idx(-1) +{ + setModel(m_model = new InlineEditorModel(0, 4, this)); + setFrame(false); + m_idx = -1; + connect(this, SIGNAL(activated(int)), this, SLOT(checkSelection(int))); +} + +void InlineEditor::checkSelection(int idx) +{ + if (idx == m_idx) + return; + + if (m_model->isTitle(idx)) + setCurrentIndex(m_idx); + else + m_idx = idx; +} + +void InlineEditor::addTitle(const QString &title) +{ + m_model->addTitle(title); +} + +void InlineEditor::addTextList(const QMap<QString, bool> &text_list) +{ + m_model->addTextList(text_list); +} + +void InlineEditor::addText(const QString &text) +{ + m_model->addText(text); +} + +QString InlineEditor::text() const +{ + return currentText(); +} + +void InlineEditor::setText(const QString &text) +{ + m_idx = m_model->findText(text); + if (m_idx == -1) + m_idx = 0; + setCurrentIndex(m_idx); +} + +// ------------------ ConnectionDelegate + +class ConnectionDelegate : public QItemDelegate +{ + Q_OBJECT +public: + ConnectionDelegate(QWidget *parent = 0); + + void setForm(QDesignerFormWindowInterface *form); + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + +private slots: + void emitCommitData(); + +private: + QDesignerFormWindowInterface *m_form; +}; + +ConnectionDelegate::ConnectionDelegate(QWidget *parent) + : QItemDelegate(parent) +{ + m_form = 0; + + static QItemEditorFactory *factory = 0; + if (factory == 0) { + factory = new QItemEditorFactory; + QItemEditorCreatorBase *creator + = new QItemEditorCreator<InlineEditor>("text"); + factory->registerEditor(QVariant::String, creator); + } + + setItemEditorFactory(factory); +} + +void ConnectionDelegate::setForm(QDesignerFormWindowInterface *form) +{ + m_form = form; +} + +QWidget *ConnectionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (m_form == 0) + return 0; + + QWidget *w = QItemDelegate::createEditor(parent, option, index); + InlineEditor *inline_editor = qobject_cast<InlineEditor*>(w); + Q_ASSERT(inline_editor != 0); + const QAbstractItemModel *model = index.model(); + + const QModelIndex obj_name_idx = model->index(index.row(), index.column() <= 1 ? 0 : 2); + const QString obj_name = model->data(obj_name_idx, Qt::DisplayRole).toString(); + + switch (index.column()) { + case 0: + case 2: { // object names + QStringList obj_name_list = objectNameList(m_form); + QMap<QString, bool> markedNameList; + markedNameList.insert(tr("<object>"), false); + inline_editor->addTextList(markedNameList); + markedNameList.clear(); + foreach (const QString &name, obj_name_list) + markedNameList.insert(name, false); + inline_editor->addTextList(markedNameList); + } + break; + case 1: + case 3: { // signals, slots + const qdesigner_internal::MemberType type = index.column() == 1 ? qdesigner_internal::SignalMember : qdesigner_internal::SlotMember; + const QModelIndex peer_index = model->index(index.row(), type == qdesigner_internal::SignalMember ? 3 : 1); + const QString peer = model->data(peer_index, Qt::DisplayRole).toString(); + + const qdesigner_internal::ClassesMemberFunctions class_list = qdesigner_internal::reverseClassesMemberFunctions(obj_name, type, peer, m_form); + + QObject *object = qFindChild<QObject*>(m_form, obj_name); + + inline_editor->addText(type == qdesigner_internal::SignalMember ? tr("<signal>") : tr("<slot>")); + foreach (const qdesigner_internal::ClassMemberFunctions &class_info, class_list) { + if (class_info.m_className.isEmpty() || class_info.m_memberList.isEmpty()) + continue; + QStringList memberList = class_info.m_memberList; + QMap<QString, bool> markedMemberList; + foreach (const QString &member, memberList) { + bool mark = false; + if (type == qdesigner_internal::SignalMember) + mark = qdesigner_internal::isQt3Signal(m_form->core(), object, member); + else + mark = qdesigner_internal::isQt3Slot(m_form->core(), object, member); + + if (!mark) + markedMemberList.insert(member, mark); + } + inline_editor->addTitle(class_info.m_className); + inline_editor->addTextList(markedMemberList); + } + } + break; + default: + break; + } + + connect(inline_editor, SIGNAL(activated(int)), this, SLOT(emitCommitData())); + + return inline_editor; +} + +void ConnectionDelegate::emitCommitData() +{ + InlineEditor *editor = qobject_cast<InlineEditor*>(sender()); + emit commitData(editor); +} + +} + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotEditorWindow +*/ + +SignalSlotEditorWindow::SignalSlotEditorWindow(QDesignerFormEditorInterface *core, + QWidget *parent) : + QWidget(parent), + m_view(new QTreeView), + m_editor(0), + m_add_button(new QToolButton), + m_remove_button(new QToolButton), + m_core(core), + m_model(new ConnectionModel(this)), + m_handling_selection_change(false) +{ + m_view->setModel(m_model); + m_view->setItemDelegate(new ConnectionDelegate(this)); + m_view->setEditTriggers(QAbstractItemView::DoubleClicked + | QAbstractItemView::EditKeyPressed); + m_view->setRootIsDecorated(false); + m_view->setTextElideMode (Qt::ElideMiddle); + connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(updateUi())); + connect(m_view->header(), SIGNAL(sectionDoubleClicked(int)), m_view, SLOT(resizeColumnToContents(int))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_view); + + QHBoxLayout *layout2 = new QHBoxLayout; + layout2->setMargin(3); + layout->addLayout(layout2); + layout2->addStretch(); + + m_remove_button->setIcon(createIconSet(QLatin1String("minus.png"))); + connect(m_remove_button, SIGNAL(clicked()), this, SLOT(removeConnection())); + layout2->addWidget(m_remove_button); + + m_add_button->setIcon(createIconSet(QLatin1String("plus.png"))); + connect(m_add_button, SIGNAL(clicked()), this, SLOT(addConnection())); + layout2->addWidget(m_add_button); + + connect(core->formWindowManager(), + SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(setActiveFormWindow(QDesignerFormWindowInterface*))); + + updateUi(); +} + +void SignalSlotEditorWindow::setActiveFormWindow(QDesignerFormWindowInterface *form) +{ + QDesignerIntegration *integration = qobject_cast<QDesignerIntegration *>(m_core->integration()); + + if (!m_editor.isNull()) { + disconnect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + disconnect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + disconnect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString))); + } + } + + m_editor = qFindChild<SignalSlotEditor*>(form); + m_model->setEditor(m_editor); + if (!m_editor.isNull()) { + ConnectionDelegate *delegate + = qobject_cast<ConnectionDelegate*>(m_view->itemDelegate()); + if (delegate != 0) + delegate->setForm(form); + + connect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + connect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + connect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString))); + } + } + + updateUi(); +} + +void SignalSlotEditorWindow::updateDialogSelection(Connection *con) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + QModelIndex index = m_model->connectionToIndex(con); + if (index == m_view->currentIndex()) + return; + m_handling_selection_change = true; + m_view->setCurrentIndex(index); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::updateEditorSelection(const QModelIndex &index) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + if (m_editor == 0) + return; + + Connection *con = m_model->indexToConnection(index); + if (m_editor->selected(con)) + return; + m_handling_selection_change = true; + m_editor->selectNone(); + m_editor->setSelected(con, true); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::objectNameChanged(QDesignerFormWindowInterface *, QObject *, const QString &, const QString &) +{ + if (m_editor) + m_model->updateAll(); +} + +void SignalSlotEditorWindow::addConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->addEmptyConnection(); + updateUi(); +} + +void SignalSlotEditorWindow::removeConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->deleteSelected(); + updateUi(); +} + +void SignalSlotEditorWindow::updateUi() +{ + m_add_button->setEnabled(!m_editor.isNull()); + m_remove_button->setEnabled(!m_editor.isNull() && m_view->currentIndex().isValid()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#include "signalsloteditorwindow.moc" diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h new file mode 100644 index 0000000..417e44b --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITORWINDOW_H +#define SIGNALSLOTEDITORWINDOW_H + +#include <QtCore/QPointer> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QModelIndex; +class QTreeView; +class QToolButton; + +namespace qdesigner_internal { + +class SignalSlotEditor; +class ConnectionModel; +class Connection; + +class SignalSlotEditorWindow : public QWidget +{ + Q_OBJECT +public: + explicit SignalSlotEditorWindow(QDesignerFormEditorInterface *core, QWidget *parent = 0); + +public slots: + void setActiveFormWindow(QDesignerFormWindowInterface *form); + +private slots: + void updateDialogSelection(Connection *con); + void updateEditorSelection(const QModelIndex &index); + + void objectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName); + + void addConnection(); + void removeConnection(); + void updateUi(); + +private: + QTreeView *m_view; + QPointer<SignalSlotEditor> m_editor; + QToolButton *m_add_button, *m_remove_button; + QDesignerFormEditorInterface *m_core; + ConnectionModel *m_model; + bool m_handling_selection_change; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITORWINDOW_H diff --git a/tools/designer/src/components/tabordereditor/tabordereditor.cpp b/tools/designer/src/components/tabordereditor/tabordereditor.cpp new file mode 100644 index 0000000..92f5ed1 --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tabordereditor.h" + +#include <metadatabase_p.h> +#include <qdesigner_command_p.h> +#include <qdesigner_utils_p.h> +#include <qlayout_widget_p.h> +#include <orderdialog_p.h> + +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetFactoryInterface> +#include <QtDesigner/QDesignerPropertySheetExtension> + +#include <QtGui/QPainter> +#include <QtGui/QMouseEvent> +#include <QtGui/QResizeEvent> +#include <QtGui/QMenu> +#include <QtGui/QApplication> + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +namespace { + enum { VBOX_MARGIN = 1, HBOX_MARGIN = 4, BG_ALPHA = 32 }; +} + +static QRect fixRect(const QRect &r) +{ + return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1); +} + +namespace qdesigner_internal { + +TabOrderEditor::TabOrderEditor(QDesignerFormWindowInterface *form, QWidget *parent) : + QWidget(parent), + m_form_window(form), + m_bg_widget(0), + m_undo_stack(form->commandHistory()), + m_font_metrics(font()), + m_current_index(0), + m_beginning(true) +{ + connect(form, SIGNAL(widgetRemoved(QWidget*)), this, SLOT(widgetRemoved(QWidget*))); + + QFont tabFont = font(); + tabFont.setPointSize(tabFont.pointSize()*2); + tabFont.setBold(true); + setFont(tabFont); + m_font_metrics = QFontMetrics(tabFont); + setAttribute(Qt::WA_MouseTracking, true); +} + +QDesignerFormWindowInterface *TabOrderEditor::formWindow() const +{ + return m_form_window; +} + +void TabOrderEditor::setBackground(QWidget *background) +{ + if (background == m_bg_widget) { + return; + } + + m_bg_widget = background; + updateBackground(); +} + +void TabOrderEditor::updateBackground() +{ + if (m_bg_widget == 0) { + // nothing to do + return; + } + + initTabOrder(); + update(); +} + +void TabOrderEditor::widgetRemoved(QWidget*) +{ + initTabOrder(); +} + +void TabOrderEditor::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + updateBackground(); +} + +QRect TabOrderEditor::indicatorRect(int index) const +{ + if (index < 0 || index >= m_tab_order_list.size()) + return QRect(); + + const QWidget *w = m_tab_order_list.at(index); + const QString text = QString::number(index + 1); + + const QPoint tl = mapFromGlobal(w->mapToGlobal(w->rect().topLeft())); + const QSize size = m_font_metrics.size(Qt::TextSingleLine, text); + QRect r(tl - QPoint(size.width(), size.height())/2, size); + r = QRect(r.left() - HBOX_MARGIN, r.top() - VBOX_MARGIN, + r.width() + HBOX_MARGIN*2, r.height() + VBOX_MARGIN*2); + + return r; +} + +static bool isWidgetVisible(QWidget *widget) +{ + while (widget && widget->parentWidget()) { + if (!widget->isVisibleTo(widget->parentWidget())) + return false; + + widget = widget->parentWidget(); + } + + return true; +} + +void TabOrderEditor::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + p.setClipRegion(e->region()); + + int cur = m_current_index - 1; + if (m_beginning == false && cur < 0) + cur = m_tab_order_list.size() - 1; + + for (int i = 0; i < m_tab_order_list.size(); ++i) { + QWidget *widget = m_tab_order_list.at(i); + if (!isWidgetVisible(widget)) + continue; + + const QRect r = indicatorRect(i); + + QColor c = Qt::darkGreen; + if (i == cur) + c = Qt::red; + else if (i > cur) + c = Qt::blue; + p.setPen(c); + c.setAlpha(BG_ALPHA); + p.setBrush(c); + p.drawRect(fixRect(r)); + + p.setPen(Qt::white); + p.drawText(r, QString::number(i + 1), QTextOption(Qt::AlignCenter)); + } +} + +bool TabOrderEditor::skipWidget(QWidget *w) const +{ + if (qobject_cast<QLayoutWidget*>(w) + || w == formWindow()->mainContainer() + || w->isHidden()) + return true; + + if (!formWindow()->isManaged(w)) { + return true; + } + + QExtensionManager *ext = formWindow()->core()->extensionManager(); + if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(ext, w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + Qt::FocusPolicy q = (Qt::FocusPolicy) Utils::valueOf(sheet->property(index), &ok); + return !ok || q == Qt::NoFocus; + } + } + + return true; +} + +void TabOrderEditor::initTabOrder() +{ + m_tab_order_list.clear(); + + QDesignerFormEditorInterface *core = formWindow()->core(); + + if (const QDesignerMetaDataBaseItemInterface *item = core->metaDataBase()->item(formWindow())) { + m_tab_order_list = item->tabOrder(); + } + + // Remove any widgets that have been removed form the form + for (int i = 0; i < m_tab_order_list.size(); ) { + QWidget *w = m_tab_order_list.at(i); + if (!formWindow()->mainContainer()->isAncestorOf(w) || skipWidget(w)) + m_tab_order_list.removeAt(i); + else + ++i; + } + + // Append any widgets that are in the form but are not in the tab order + QList<QWidget *> childQueue; + childQueue.append(formWindow()->mainContainer()); + while (!childQueue.isEmpty()) { + QWidget *child = childQueue.takeFirst(); + childQueue += qVariantValue<QWidgetList>(child->property("_q_widgetOrder")); + + if (skipWidget(child)) + continue; + + if (!m_tab_order_list.contains(child)) + m_tab_order_list.append(child); + } + + // Just in case we missed some widgets + QDesignerFormWindowCursorInterface *cursor = formWindow()->cursor(); + for (int i = 0; i < cursor->widgetCount(); ++i) { + + QWidget *widget = cursor->widget(i); + if (skipWidget(widget)) + continue; + + if (!m_tab_order_list.contains(widget)) + m_tab_order_list.append(widget); + } + + m_indicator_region = QRegion(); + for (int i = 0; i < m_tab_order_list.size(); ++i) { + if (m_tab_order_list.at(i)->isVisible()) + m_indicator_region |= indicatorRect(i); + } + + if (m_current_index >= m_tab_order_list.size()) + m_current_index = m_tab_order_list.size() - 1; + if (m_current_index < 0) + m_current_index = 0; +} + +void TabOrderEditor::mouseMoveEvent(QMouseEvent *e) +{ + e->accept(); +#ifndef QT_NO_CURSOR + if (m_indicator_region.contains(e->pos())) + setCursor(Qt::PointingHandCursor); + else + setCursor(QCursor()); +#endif +} + +int TabOrderEditor::widgetIndexAt(const QPoint &pos) const +{ + int target_index = -1; + for (int i = 0; i < m_tab_order_list.size(); ++i) { + if (!m_tab_order_list.at(i)->isVisible()) + continue; + if (indicatorRect(i).contains(pos)) { + target_index = i; + break; + } + } + + return target_index; +} + +void TabOrderEditor::mousePressEvent(QMouseEvent *e) +{ + e->accept(); + + if (!m_indicator_region.contains(e->pos())) { + if (QWidget *child = m_bg_widget->childAt(e->pos())) { + QDesignerFormEditorInterface *core = m_form_window->core(); + if (core->widgetFactory()->isPassiveInteractor(child)) { + + QMouseEvent event(QEvent::MouseButtonPress, + child->mapFromGlobal(e->globalPos()), + e->button(), e->buttons(), e->modifiers()); + + qApp->sendEvent(child, &event); + + QMouseEvent event2(QEvent::MouseButtonRelease, + child->mapFromGlobal(e->globalPos()), + e->button(), e->buttons(), e->modifiers()); + + qApp->sendEvent(child, &event2); + + updateBackground(); + } + } + return; + } + + if (e->button() != Qt::LeftButton) + return; + + const int target_index = widgetIndexAt(e->pos()); + if (target_index == -1) + return; + + m_beginning = false; + + if (e->modifiers() & Qt::ControlModifier) { + m_current_index = target_index + 1; + if (m_current_index >= m_tab_order_list.size()) + m_current_index = 0; + update(); + return; + } + + if (m_current_index == -1) + return; + + m_tab_order_list.swap(target_index, m_current_index); + + ++m_current_index; + if (m_current_index == m_tab_order_list.size()) + m_current_index = 0; + + TabOrderCommand *cmd = new TabOrderCommand(formWindow()); + cmd->init(m_tab_order_list); + formWindow()->commandHistory()->push(cmd); +} + +void TabOrderEditor::contextMenuEvent(QContextMenuEvent *e) +{ + QMenu menu(this); + const int target_index = widgetIndexAt(e->pos()); + QAction *setIndex = menu.addAction(tr("Start from Here")); + setIndex->setEnabled(target_index >= 0); + + QAction *resetIndex = menu.addAction(tr("Restart")); + menu.addSeparator(); + QAction *showDialog = menu.addAction(tr("Tab Order List...")); + showDialog->setEnabled(m_tab_order_list.size() > 1); + + QAction *result = menu.exec(e->globalPos()); + if (result == resetIndex) { + m_current_index = 0; + m_beginning = true; + update(); + } else if (result == setIndex) { + m_beginning = false; + m_current_index = target_index + 1; + if (m_current_index >= m_tab_order_list.size()) + m_current_index = 0; + update(); + } else if (result == showDialog) { + showTabOrderDialog(); + } +} + +void TabOrderEditor::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + return; + + const int target_index = widgetIndexAt(e->pos()); + if (target_index >= 0) + return; + + m_beginning = true; + m_current_index = 0; + update(); +} + +void TabOrderEditor::resizeEvent(QResizeEvent *e) +{ + updateBackground(); + QWidget::resizeEvent(e); +} + +void TabOrderEditor::showTabOrderDialog() +{ + if (m_tab_order_list.size() < 2) + return; + OrderDialog dlg(this); + dlg.setWindowTitle(tr("Tab Order List")); + dlg.setDescription(tr("Tab Order")); + dlg.setFormat(OrderDialog::TabOrderFormat); + dlg.setPageList(m_tab_order_list); + + if (dlg.exec() == QDialog::Rejected) + return; + + const QWidgetList newOrder = dlg.pageList(); + if (newOrder == m_tab_order_list) + return; + + m_tab_order_list = newOrder; + TabOrderCommand *cmd = new TabOrderCommand(formWindow()); + cmd->init(m_tab_order_list); + formWindow()->commandHistory()->push(cmd); + update(); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/tabordereditor/tabordereditor.h b/tools/designer/src/components/tabordereditor/tabordereditor.h new file mode 100644 index 0000000..ec7a81d --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_H +#define TABORDEREDITOR_H + +#include "tabordereditor_global.h" + +#include <QtCore/QPointer> +#include <QtGui/QWidget> +#include <QtGui/QRegion> +#include <QtGui/QFont> +#include <QtGui/QFontMetrics> + +QT_BEGIN_NAMESPACE + +class QUndoStack; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class QT_TABORDEREDITOR_EXPORT TabOrderEditor : public QWidget +{ + Q_OBJECT + +public: + TabOrderEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const; + +public slots: + void setBackground(QWidget *background); + void updateBackground(); + void widgetRemoved(QWidget*); + void initTabOrder(); + +private slots: + void showTabOrderDialog(); + +protected: + virtual void paintEvent(QPaintEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void contextMenuEvent(QContextMenuEvent *e); + virtual void resizeEvent(QResizeEvent *e); + virtual void showEvent(QShowEvent *e); + +private: + QRect indicatorRect(int index) const; + int widgetIndexAt(const QPoint &pos) const; + bool skipWidget(QWidget *w) const; + + QPointer<QDesignerFormWindowInterface> m_form_window; + + QWidgetList m_tab_order_list; + + QWidget *m_bg_widget; + QUndoStack *m_undo_stack; + QRegion m_indicator_region; + + QFontMetrics m_font_metrics; + int m_current_index; + bool m_beginning; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/tools/designer/src/components/tabordereditor/tabordereditor.pri b/tools/designer/src/components/tabordereditor/tabordereditor.pri new file mode 100644 index 0000000..786c6ae --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor.pri @@ -0,0 +1,16 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/tabordereditor.h \ + $$PWD/tabordereditor_plugin.h \ + $$PWD/tabordereditor_tool.h \ + $$PWD/tabordereditor_global.h + +SOURCES += \ + $$PWD/tabordereditor.cpp \ + $$PWD/tabordereditor_tool.cpp \ + $$PWD/tabordereditor_plugin.cpp \ + $$PWD/tabordereditor_instance.cpp diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_global.h b/tools/designer/src/components/tabordereditor/tabordereditor_global.h new file mode 100644 index 0000000..af40dbd --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_GLOBAL_H +#define TABORDEREDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_TABORDEREDITOR_LIBRARY +# define QT_TABORDEREDITOR_EXPORT +#else +# define QT_TABORDEREDITOR_EXPORT +#endif +#else +#define QT_TABORDEREDITOR_EXPORT +#endif + +#endif // TABORDEREDITOR_GLOBAL_H diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_instance.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_instance.cpp new file mode 100644 index 0000000..fe006ce --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_instance.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qplugin.h> + +#include "tabordereditor_plugin.h" + +QT_USE_NAMESPACE +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(TabOrderEditorPlugin) diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp new file mode 100644 index 0000000..46bf378 --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TabOrderEditorPlugin +*/ + +#include <QtGui/QAction> + +#include "tabordereditor_plugin.h" +#include "tabordereditor_tool.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TabOrderEditorPlugin::TabOrderEditorPlugin() + : m_initialized(false) +{ +} + +TabOrderEditorPlugin::~TabOrderEditorPlugin() +{ +} + +bool TabOrderEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void TabOrderEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Tab Order"), this); + m_action->setObjectName(QLatin1String("_qt_edit_tab_order_action")); + m_action->setIcon(QIcon(core->resourceLocation() + QLatin1String("/tabordertool.png"))); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +void TabOrderEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QDesignerFormEditorInterface *TabOrderEditorPlugin::core() const +{ + return m_core; +} + +void TabOrderEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + TabOrderEditorTool *tool = new TabOrderEditorTool(formWindow, this); + m_tools[formWindow] = tool; + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + formWindow->registerTool(tool); +} + +void TabOrderEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + TabOrderEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *TabOrderEditorPlugin::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.h b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.h new file mode 100644 index 0000000..e5ef762 --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_PLUGIN_H +#define TABORDEREDITOR_PLUGIN_H + +#include "tabordereditor_global.h" + +#include <QtDesigner/QDesignerFormEditorPluginInterface> + +#include <QtCore/QPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class TabOrderEditorTool; + +class QT_TABORDEREDITOR_EXPORT TabOrderEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + TabOrderEditorPlugin(); + virtual ~TabOrderEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer<QDesignerFormEditorInterface> m_core; + QHash<QDesignerFormWindowInterface*, TabOrderEditorTool*> m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABORDEREDITOR_PLUGIN_H diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp new file mode 100644 index 0000000..4f291a1 --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TabOrderEditorTool +*/ + +#include "tabordereditor_tool.h" +#include "tabordereditor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtCore/QEvent> +#include <QtGui/QAction> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TabOrderEditorTool::TabOrderEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Tab Order"), this)) +{ +} + +TabOrderEditorTool::~TabOrderEditorTool() +{ +} + +QDesignerFormEditorInterface *TabOrderEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *TabOrderEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool TabOrderEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) + return true; + + return false; +} + +QWidget *TabOrderEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new TabOrderEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + } + + return m_editor; +} + +void TabOrderEditorTool::activated() +{ + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); +} + +void TabOrderEditorTool::deactivated() +{ + disconnect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); +} + +QAction *TabOrderEditorTool::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_tool.h b/tools/designer/src/components/tabordereditor/tabordereditor_tool.h new file mode 100644 index 0000000..ea74da2 --- /dev/null +++ b/tools/designer/src/components/tabordereditor/tabordereditor_tool.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_TOOL_H +#define TABORDEREDITOR_TOOL_H + +#include "tabordereditor_global.h" + +#include <QtCore/QPointer> + +#include <QtDesigner/QDesignerFormWindowToolInterface> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class TabOrderEditor; + +class QT_TABORDEREDITOR_EXPORT TabOrderEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit TabOrderEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~TabOrderEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer<TabOrderEditor> m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABORDEREDITOR_TOOL_H diff --git a/tools/designer/src/components/taskmenu/button_taskmenu.cpp b/tools/designer/src/components/taskmenu/button_taskmenu.cpp new file mode 100644 index 0000000..ced32ce --- /dev/null +++ b/tools/designer/src/components/taskmenu/button_taskmenu.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ButtonTaskMenu +*/ + +#include "button_taskmenu.h" +#include "inplace_editor.h" +#include <qdesigner_formwindowcommand_p.h> +#include <formwindowbase_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QDesignerObjectInspectorInterface> +#include <QtDesigner/QDesignerPropertyEditorInterface> + +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QMenu> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> +#include <QtGui/QAbstractButton> +#include <QtGui/QButtonGroup> +#include <QtGui/QApplication> +#include <QtCore/QDebug> + +Q_DECLARE_METATYPE(QButtonGroup*) + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +enum { debugButtonMenu = 0 }; + +typedef QList<QAbstractButton *> ButtonList; +typedef QList<QButtonGroup *> ButtonGroupList; + +// ButtonGroupCommand: Base for commands handling button groups and button lists +// addButtonsToGroup() and removeButtonsFromGroup() are low-level helpers for +// adding/removing members to/from existing groups. +// +// createButtonGroup()/breakButtonGroup() create and remove the groups from scratch. +// When using them in a command, the command must be executed within +// a macro since it makes the form emit objectRemoved() which might cause other components +// to add commands (for example, removal of signals and slots) +class ButtonGroupCommand : public QDesignerFormWindowCommand { + +protected: + ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow); + + void initialize(const ButtonList &bl, QButtonGroup *buttonGroup); + + // Helper: Add the buttons to the group + void addButtonsToGroup(); + // Helper; Remove the buttons + void removeButtonsFromGroup(); + + // Create the button group in Designer + void createButtonGroup(); + // Remove the button group from Designer + void breakButtonGroup(); + +public: + static QString nameList(const ButtonList& bl); + static ButtonGroupList managedButtonGroups(const QDesignerFormWindowInterface *formWindow); + +private: + ButtonList m_buttonList; + QButtonGroup *m_buttonGroup; +}; + +ButtonGroupCommand::ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(description, formWindow), + m_buttonGroup(0) +{ +} + +void ButtonGroupCommand::initialize(const ButtonList &bl, QButtonGroup *buttonGroup) +{ + m_buttonList = bl; + m_buttonGroup = buttonGroup; +} + +void ButtonGroupCommand::addButtonsToGroup() +{ + if (debugButtonMenu) + qDebug() << "Adding " << m_buttonList << " to " << m_buttonGroup; + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + m_buttonGroup->addButton(*it); +} + +void ButtonGroupCommand::removeButtonsFromGroup() +{ + if (debugButtonMenu) + qDebug() << "Removing " << m_buttonList << " from " << m_buttonGroup; + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + m_buttonGroup->removeButton(*it); +} + +void ButtonGroupCommand::createButtonGroup() +{ + if (debugButtonMenu) + qDebug() << "Creating " << m_buttonGroup << " from " << m_buttonList; + + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + core->metaDataBase()->add(m_buttonGroup); + addButtonsToGroup(); + // Make button group visible + core->objectInspector()->setFormWindow(fw); +} + +void ButtonGroupCommand::breakButtonGroup() +{ + if (debugButtonMenu) + qDebug() << "Removing " << m_buttonGroup << " consisting of " << m_buttonList; + + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + // Button group was selected, that is, break was invoked via its context menu. Remove it from property editor, select the buttons + if (core->propertyEditor()->object() == m_buttonGroup) { + fw->clearSelection(false); + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + fw->selectWidget(*it, true); + } + // Now remove and refresh object inspector + removeButtonsFromGroup(); + // Notify components (for example, signal slot editor) + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fw)) + fwb->emitObjectRemoved(m_buttonGroup); + core->metaDataBase()->remove(m_buttonGroup); + core->objectInspector()->setFormWindow(fw); +} + +QString ButtonGroupCommand::nameList(const ButtonList& bl) +{ + QString rc; + const QChar quote = QLatin1Char('\''); + const QString separator = QLatin1String(", "); + const int size = bl.size(); + for (int i = 0; i < size; i++) { + if (i) + rc += separator; + rc += quote; + rc += bl[i]->objectName(); + rc += quote; + } + return rc; + +} + +ButtonGroupList ButtonGroupCommand::managedButtonGroups(const QDesignerFormWindowInterface *formWindow) +{ + const QDesignerMetaDataBaseInterface *mdb = formWindow->core()->metaDataBase(); + ButtonGroupList bl; + // Check 1st order children for managed button groups + const QObjectList children = formWindow->mainContainer()->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + if (!(*it)->isWidgetType()) + if (QButtonGroup *bg = qobject_cast<QButtonGroup *>(*it)) + if (mdb->item(bg)) + bl.push_back(bg); + } + return bl; +} + +// --------------- CreateButtonGroupCommand +// This command might be executed in a macro with a remove +// command to move buttons from one group to a new one. +class CreateButtonGroupCommand : public ButtonGroupCommand { +public: + CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(const ButtonList &bl); + + virtual void undo() { breakButtonGroup(); } + virtual void redo() { createButtonGroup(); } +}; + +CreateButtonGroupCommand::CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Create button group"), formWindow) +{ +} + +bool CreateButtonGroupCommand::init(const ButtonList &bl) +{ + if (bl.empty()) + return false; + QDesignerFormWindowInterface *fw = formWindow(); + QButtonGroup *buttonGroup = new QButtonGroup(fw->mainContainer()); + buttonGroup->setObjectName(QLatin1String("buttonGroup")); + fw->ensureUniqueObjectName(buttonGroup); + initialize(bl, buttonGroup); + return true; +} + +// --------------- BreakButtonGroupCommand +class BreakButtonGroupCommand : public ButtonGroupCommand { +public: + BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(QButtonGroup *group); + + virtual void undo() { createButtonGroup(); } + virtual void redo() { breakButtonGroup(); } +}; + +BreakButtonGroupCommand::BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Break button group"), formWindow) +{ +} + +bool BreakButtonGroupCommand::init(QButtonGroup *group) +{ + if (!group) + return false; + initialize(group->buttons(), group); + setText(QApplication::translate("Command", "Break button group '%1'").arg(group->objectName())); + return true; +} + +// --------------- AddButtonsToGroupCommand +// This command might be executed in a macro with a remove +// command to move buttons from one group to a new one. +class AddButtonsToGroupCommand : public ButtonGroupCommand { +public: + AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow); + void init(const ButtonList &bl, QButtonGroup *group); + + virtual void undo() { removeButtonsFromGroup(); } + virtual void redo() { addButtonsToGroup(); } +}; + +AddButtonsToGroupCommand::AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Add buttons to group"), formWindow) +{ +} + +void AddButtonsToGroupCommand::init(const ButtonList &bl, QButtonGroup *group) +{ + initialize(bl, group); + //: Command description for adding buttons to a QButtonGroup + setText(QApplication::translate("Command", "Add '%1' to '%2'").arg(nameList(bl), group->objectName())); +} + +//-------------------- RemoveButtonsFromGroupCommand +class RemoveButtonsFromGroupCommand : public ButtonGroupCommand { +public: + RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(const ButtonList &bl); + + virtual void undo() { addButtonsToGroup(); } + virtual void redo() { removeButtonsFromGroup(); } +}; + +RemoveButtonsFromGroupCommand::RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Remove buttons from group"), formWindow) +{ +} + +bool RemoveButtonsFromGroupCommand::init(const ButtonList &bl) +{ + if (bl.empty()) + return false; + QButtonGroup *group = bl.front()->group(); + if (!group) + return false; + if (bl.size() >= group->buttons().size()) + return false; + initialize(bl, group); + //: Command description for removing buttons from a QButtonGroup + setText(QApplication::translate("Command", "Remove '%1' from '%2'").arg(nameList(bl), group->objectName())); + return true; +} + +// -------- ButtonGroupMenu +ButtonGroupMenu::ButtonGroupMenu(QObject *parent) : + QObject(parent), + m_selectGroupAction(new QAction(tr("Select members"), this)), + m_breakGroupAction(new QAction(tr("Break"), this)), + m_formWindow(0), + m_buttonGroup(0), + m_currentButton(0) +{ + connect(m_breakGroupAction, SIGNAL(triggered()), this, SLOT(breakGroup())); + connect(m_selectGroupAction, SIGNAL(triggered()), this, SLOT(selectGroup())); +} + +void ButtonGroupMenu::initialize(QDesignerFormWindowInterface *formWindow, QButtonGroup *buttonGroup, QAbstractButton *currentButton) +{ + m_buttonGroup = buttonGroup; + m_currentButton = currentButton; + m_formWindow = formWindow; + Q_ASSERT(m_formWindow); + + const bool canBreak = buttonGroup != 0; + m_breakGroupAction->setEnabled(canBreak); + m_selectGroupAction->setEnabled(canBreak); +} + +void ButtonGroupMenu::selectGroup() +{ + // Select and make current button "current" again by selecting it last (if there is any) + const ButtonList buttons = m_buttonGroup->buttons(); + m_formWindow->clearSelection(false); + const ButtonList::const_iterator cend = buttons.constEnd(); + for (ButtonList::const_iterator it = buttons.constBegin(); it != cend; ++it) + if (*it != m_currentButton) + m_formWindow->selectWidget(*it, true); + if (m_currentButton) + m_formWindow->selectWidget(m_currentButton, true); +} + +void ButtonGroupMenu::breakGroup() +{ + BreakButtonGroupCommand *cmd = new BreakButtonGroupCommand(m_formWindow); + if (cmd->init(m_buttonGroup)) { + // Need a macro since the command might trigger additional commands + QUndoStack *history = m_formWindow->commandHistory(); + history->beginMacro(cmd->text()); + history->push(cmd); + history->endMacro(); + } else { + qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); + delete cmd; + } +} + +// ButtonGroupTaskMenu +ButtonGroupTaskMenu::ButtonGroupTaskMenu(QButtonGroup *buttonGroup, QObject *parent) : + QObject(parent), + m_buttonGroup(buttonGroup) +{ + m_taskActions.push_back(m_menu.breakGroupAction()); + m_taskActions.push_back(m_menu.selectGroupAction()); +} + +QAction *ButtonGroupTaskMenu::preferredEditAction() const +{ + return m_menu.selectGroupAction(); +} + +QList<QAction*> ButtonGroupTaskMenu::taskActions() const +{ + m_menu.initialize(QDesignerFormWindowInterface::findFormWindow(m_buttonGroup), m_buttonGroup); + return m_taskActions; +} + +// -------- Text area editor +class ButtonTextTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +ButtonTextTaskMenuInlineEditor::ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) : + TaskMenuInlineEditor(button, ValidationMultiLine, QLatin1String("text"), parent) +{ +} + +QRect ButtonTextTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); + QStyleOptionButton opt; + opt.init(w); + return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); +} + +// -------- Command link button description editor +class LinkDescriptionTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LinkDescriptionTaskMenuInlineEditor::LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) : + TaskMenuInlineEditor(button, ValidationMultiLine, QLatin1String("description"), parent) +{ +} + +QRect LinkDescriptionTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); // TODO: What is the exact description area? + QStyleOptionButton opt; + opt.init(w); + return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); +} + +// ----------- ButtonTaskMenu: + +ButtonTaskMenu::ButtonTaskMenu(QAbstractButton *button, QObject *parent) : + QDesignerTaskMenu(button, parent), + m_assignGroupSubMenu(new QMenu), + m_assignActionGroup(0), + m_assignToGroupSubMenuAction(new QAction(tr("Assign to button group"), this)), + m_currentGroupSubMenu(new QMenu), + m_currentGroupSubMenuAction(new QAction(tr("Button group"), this)), + m_createGroupAction(new QAction(tr("New button group"), this)), + m_preferredEditAction(new QAction(tr("Change text..."), this)), + m_removeFromGroupAction(new QAction(tr("None"), this)) +{ + connect(m_createGroupAction, SIGNAL(triggered()), this, SLOT(createGroup())); + TaskMenuInlineEditor *textEditor = new ButtonTextTaskMenuInlineEditor(button, this); + connect(m_preferredEditAction, SIGNAL(triggered()), textEditor, SLOT(editText())); + connect(m_removeFromGroupAction, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + + m_assignToGroupSubMenuAction->setMenu(m_assignGroupSubMenu); + + m_currentGroupSubMenu->addAction(m_groupMenu.breakGroupAction()); + m_currentGroupSubMenu->addAction(m_groupMenu.selectGroupAction()); + m_currentGroupSubMenuAction->setMenu(m_currentGroupSubMenu); + + + m_taskActions.append(m_preferredEditAction); + m_taskActions.append(m_assignToGroupSubMenuAction); + m_taskActions.append(m_currentGroupSubMenuAction); + m_taskActions.append(createSeparator()); +} + +ButtonTaskMenu::~ButtonTaskMenu() +{ + delete m_assignGroupSubMenu; + delete m_currentGroupSubMenu; +} + +QAction *ButtonTaskMenu::preferredEditAction() const +{ + return m_preferredEditAction; +} + +bool ButtonTaskMenu::refreshAssignMenu(const QDesignerFormWindowInterface *fw, int buttonCount, SelectionType st, QButtonGroup *currentGroup) +{ + // clear + if (m_assignActionGroup) { + delete m_assignActionGroup; + m_assignActionGroup = 0; + } + m_assignGroupSubMenu->clear(); + if (st == OtherSelection) + return false; + + + // Assign to new: Need several + const bool canAssignToNewGroup = buttonCount > 1; + m_createGroupAction->setEnabled(canAssignToNewGroup); + if (canAssignToNewGroup) + m_assignGroupSubMenu->addAction(m_createGroupAction); + + // Assign to other + const ButtonGroupList bl = ButtonGroupCommand::managedButtonGroups(fw); + // Groups: Any groups to add to except the current? + const int groupCount = bl.size(); + const bool hasAddGroups = groupCount > 1 || (groupCount == 1 && !bl.contains(currentGroup)); + if (hasAddGroups) { + if (!m_assignGroupSubMenu->isEmpty()) + m_assignGroupSubMenu->addSeparator(); + // Create a new action group + m_assignActionGroup = new QActionGroup(this); + connect(m_assignActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(addToGroup(QAction*))); + + const ButtonGroupList::const_iterator cend = bl.constEnd(); + for (ButtonGroupList::const_iterator it = bl.constBegin(); it != cend; ++it) { + QButtonGroup *bg = *it; + if (*it != currentGroup) { + QAction *a = new QAction(bg->objectName(), m_assignGroupSubMenu); + a->setData(qVariantFromValue(bg)); + m_assignActionGroup->addAction(a); + m_assignGroupSubMenu->addAction(a); + } + } + } + // Can remove: A homogenous selection of another group that does not completely break it. + const bool canRemoveFromGroup = st == GroupedButtonSelection; + m_removeFromGroupAction->setEnabled(canRemoveFromGroup); + if (canRemoveFromGroup) { + if (!m_assignGroupSubMenu->isEmpty()) + m_assignGroupSubMenu->addSeparator(); + m_assignGroupSubMenu->addAction(m_removeFromGroupAction); + } + return !m_assignGroupSubMenu->isEmpty(); +} + +QList<QAction*> ButtonTaskMenu::taskActions() const +{ + ButtonTaskMenu *ncThis = const_cast<ButtonTaskMenu*>(this); + QButtonGroup *buttonGroup; + + QDesignerFormWindowInterface *fw = formWindow(); + const SelectionType st = selectionType(fw->cursor(), &buttonGroup); + + m_groupMenu.initialize(fw, buttonGroup, button()); + const bool hasAssignOptions = ncThis->refreshAssignMenu(fw, fw->cursor()->selectedWidgetCount(), st, buttonGroup); + m_assignToGroupSubMenuAction->setVisible(hasAssignOptions); + // add/remove + switch (st) { + case UngroupedButtonSelection: + case OtherSelection: + m_currentGroupSubMenuAction->setVisible(false); + break; + case GroupedButtonSelection: + m_currentGroupSubMenuAction->setText(tr("Button group '%1'").arg(buttonGroup->objectName())); + m_currentGroupSubMenuAction->setVisible(true); + break; + } + + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + + +void ButtonTaskMenu::insertAction(int index, QAction *a) +{ + m_taskActions.insert(index, a); +} + +/* Create a button list from the cursor selection */ +static ButtonList buttonList(const QDesignerFormWindowCursorInterface *cursor) +{ + ButtonList rc; + const int selectionCount = cursor->selectedWidgetCount(); + for (int i = 0; i < selectionCount; i++) { + QAbstractButton *ab = qobject_cast<QAbstractButton *>(cursor->selectedWidget(i)); + Q_ASSERT(ab); + rc += ab; + } + return rc; +} + +// Create a command to remove the buttons from their group +// If it would leave an empty or 1-member group behind, create a break command instead + +static QUndoCommand *createRemoveButtonsCommand(QDesignerFormWindowInterface *fw, const ButtonList &bl) +{ + + QButtonGroup *bg = bl.front()->group(); + // Complete group or 1-member group? + if (bl.size() >= bg->buttons().size() - 1) { + BreakButtonGroupCommand *breakCmd = new BreakButtonGroupCommand(fw); + if (!breakCmd->init(bg)) { + qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); + delete breakCmd; + return 0; + } + return breakCmd; + } + // Just remove the buttons + + RemoveButtonsFromGroupCommand *removeCmd = new RemoveButtonsFromGroupCommand(fw); + if (!removeCmd->init(bl)) { + qWarning("** WARNING Failed to initialize RemoveButtonsFromGroupCommand!"); + delete removeCmd; + return 0; + } + return removeCmd; +} + +void ButtonTaskMenu::createGroup() +{ + QDesignerFormWindowInterface *fw = formWindow(); + const ButtonList bl = buttonList(fw->cursor()); + // Do we need to remove the buttons from an existing group? + QUndoCommand *removeCmd = 0; + if (bl.front()->group()) { + removeCmd = createRemoveButtonsCommand(fw, bl); + if (!removeCmd) + return; + } + // Add cmd + CreateButtonGroupCommand *addCmd = new CreateButtonGroupCommand(fw); + if (!addCmd->init(bl)) { + qWarning("** WARNING Failed to initialize CreateButtonGroupCommand!"); + delete addCmd; + return; + } + // Need a macro [even if we only have the add command] since the command might trigger additional commands + QUndoStack *history = fw->commandHistory(); + history->beginMacro(addCmd->text()); + if (removeCmd) + history->push(removeCmd); + history->push(addCmd); + history->endMacro(); +} + +QAbstractButton *ButtonTaskMenu::button() const +{ + return qobject_cast<QAbstractButton *>(widget()); +} + +// Figure out if we have a homogenous selections (buttons of the same group or no group) +ButtonTaskMenu::SelectionType ButtonTaskMenu::selectionType(const QDesignerFormWindowCursorInterface *cursor, QButtonGroup **ptrToGroup) const +{ + const int selectionCount = cursor->selectedWidgetCount(); + if (!selectionCount) + return OtherSelection; + + QButtonGroup *commonGroup = 0; + for (int i = 0; i < selectionCount; i++) { + if (const QAbstractButton *ab = qobject_cast<const QAbstractButton *>(cursor->selectedWidget(i))) { + QButtonGroup *buttonGroup = ab->group(); + if (i) { + if (buttonGroup != commonGroup) + return OtherSelection; + } else { + commonGroup = buttonGroup; + } + } else { + return OtherSelection; + } + } + + if (ptrToGroup) + *ptrToGroup = commonGroup; + + return commonGroup ? GroupedButtonSelection : UngroupedButtonSelection; +} + +void ButtonTaskMenu::addToGroup(QAction *a) +{ + QButtonGroup *bg = qvariant_cast<QButtonGroup *>(a->data()); + Q_ASSERT(bg); + + QDesignerFormWindowInterface *fw = formWindow(); + const ButtonList bl = buttonList(fw->cursor()); + // Do we need to remove the buttons from an existing group? + QUndoCommand *removeCmd = 0; + if (bl.front()->group()) { + removeCmd = createRemoveButtonsCommand(fw, bl); + if (!removeCmd) + return; + } + AddButtonsToGroupCommand *addCmd = new AddButtonsToGroupCommand(fw); + addCmd->init(bl, bg); + + QUndoStack *history = fw->commandHistory(); + if (removeCmd) { + history->beginMacro(addCmd->text()); + history->push(removeCmd); + history->push(addCmd); + history->endMacro(); + } else { + history->push(addCmd); + } +} + +void ButtonTaskMenu::removeFromGroup() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (QUndoCommand *cmd = createRemoveButtonsCommand(fw, buttonList(fw->cursor()))) + fw->commandHistory()->push(cmd); +} + +// -------------- CommandLinkButtonTaskMenu + +CommandLinkButtonTaskMenu::CommandLinkButtonTaskMenu(QCommandLinkButton *button, QObject *parent) : + ButtonTaskMenu(button, parent) +{ + TaskMenuInlineEditor *descriptonEditor = new LinkDescriptionTaskMenuInlineEditor(button, this); + QAction *descriptionAction = new QAction(tr("Change description..."), this); + connect(descriptionAction, SIGNAL(triggered()), descriptonEditor, SLOT(editText())); + insertAction(1, descriptionAction); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/button_taskmenu.h b/tools/designer/src/components/taskmenu/button_taskmenu.h new file mode 100644 index 0000000..1681f34 --- /dev/null +++ b/tools/designer/src/components/taskmenu/button_taskmenu.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUTTON_TASKMENU_H +#define BUTTON_TASKMENU_H + +#include <QtGui/QAbstractButton> +#include <QtGui/QCommandLinkButton> +#include <QtGui/QButtonGroup> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QMenu; +class QActionGroup; +class QDesignerFormWindowCursorInterface; + +namespace qdesigner_internal { + +// ButtonGroupMenu: Mixin menu for the 'select members'/'break group' options of +// the task menu of buttons and button group +class ButtonGroupMenu : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonGroupMenu) +public: + ButtonGroupMenu(QObject *parent = 0); + + void initialize(QDesignerFormWindowInterface *formWindow, + QButtonGroup *buttonGroup = 0, + /* Current button for selection in ButtonMode */ + QAbstractButton *currentButton = 0); + + QAction *selectGroupAction() const { return m_selectGroupAction; } + QAction *breakGroupAction() const { return m_breakGroupAction; } + +private slots: + void selectGroup(); + void breakGroup(); + +private: + QAction *m_selectGroupAction; + QAction *m_breakGroupAction; + + QDesignerFormWindowInterface *m_formWindow; + QButtonGroup *m_buttonGroup; + QAbstractButton *m_currentButton; +}; + +// Task menu extension of a QButtonGroup +class ButtonGroupTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonGroupTaskMenu) + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit ButtonGroupTaskMenu(QButtonGroup *buttonGroup, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QButtonGroup *m_buttonGroup; + QList<QAction*> m_taskActions; + mutable ButtonGroupMenu m_menu; +}; + +// Task menu extension of a QAbstractButton +class ButtonTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonTaskMenu) +public: + explicit ButtonTaskMenu(QAbstractButton *button, QObject *parent = 0); + virtual ~ButtonTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + + QAbstractButton *button() const; + +protected: + void insertAction(int index, QAction *a); + +private slots: + void createGroup(); + void addToGroup(QAction *a); + void removeFromGroup(); + +private: + enum SelectionType { + OtherSelection, + UngroupedButtonSelection, + GroupedButtonSelection + }; + + SelectionType selectionType(const QDesignerFormWindowCursorInterface *cursor, QButtonGroup ** ptrToGroup = 0) const; + bool refreshAssignMenu(const QDesignerFormWindowInterface *fw, int buttonCount, SelectionType st, QButtonGroup *currentGroup); + QMenu *createGroupSelectionMenu(const QDesignerFormWindowInterface *fw); + + QList<QAction*> m_taskActions; + mutable ButtonGroupMenu m_groupMenu; + QMenu *m_assignGroupSubMenu; + QActionGroup *m_assignActionGroup; + QAction *m_assignToGroupSubMenuAction; + QMenu *m_currentGroupSubMenu; + QAction *m_currentGroupSubMenuAction; + + QAction *m_createGroupAction; + QAction *m_preferredEditAction; + QAction *m_removeFromGroupAction; +}; + +// Task menu extension of a QCommandLinkButton +class CommandLinkButtonTaskMenu: public ButtonTaskMenu +{ + Q_OBJECT + Q_DISABLE_COPY(CommandLinkButtonTaskMenu) +public: + explicit CommandLinkButtonTaskMenu(QCommandLinkButton *button, QObject *parent = 0); +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QButtonGroup, ButtonGroupTaskMenu> ButtonGroupTaskMenuFactory; +typedef ExtensionFactory<QDesignerTaskMenuExtension, QCommandLinkButton, CommandLinkButtonTaskMenu> CommandLinkButtonTaskMenuFactory; +typedef ExtensionFactory<QDesignerTaskMenuExtension, QAbstractButton, ButtonTaskMenu> ButtonTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUTTON_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp b/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp new file mode 100644 index 0000000..e3364cc --- /dev/null +++ b/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ComboBoxTaskMenu +*/ + +#include "combobox_taskmenu.h" +#include "listwidgeteditor.h" +#include "qdesigner_utils_p.h" +#include <qdesigner_command_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QLineEdit> +#include <QtGui/QFontComboBox> +#include <QtGui/QStyleOption> + +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ComboBoxTaskMenu::ComboBoxTaskMenu(QComboBox *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_comboBox(button) +{ + m_editItemsAction = new QAction(this); + m_editItemsAction->setText(tr("Edit Items...")); + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +ComboBoxTaskMenu::~ComboBoxTaskMenu() +{ +} + +QAction *ComboBoxTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList<QAction*> ComboBoxTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void ComboBoxTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_comboBox); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_comboBox != 0); + + ListWidgetEditor dlg(m_formWindow, m_comboBox->window()); + ListContents oldItems = dlg.fillContentsFromComboBox(m_comboBox); + if (dlg.exec() == QDialog::Accepted) { + ListContents items = dlg.contents(); + if (items != oldItems) { + ChangeListContentsCommand *cmd = new ChangeListContentsCommand(m_formWindow); + cmd->init(m_comboBox, oldItems, items); + cmd->setText(tr("Change Combobox Contents")); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +ComboBoxTaskMenuFactory::ComboBoxTaskMenuFactory(const QString &iid, QExtensionManager *extensionManager) : + ExtensionFactory<QDesignerTaskMenuExtension, QComboBox, ComboBoxTaskMenu>(iid, extensionManager) +{ +} + +QComboBox *ComboBoxTaskMenuFactory::checkObject(QObject *qObject) const +{ + QComboBox *combo = qobject_cast<QComboBox*>(qObject); + if (!combo) + return 0; + if (qobject_cast<QFontComboBox*>(combo)) + return 0; + return combo; +} + +void ComboBoxTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/combobox_taskmenu.h b/tools/designer/src/components/taskmenu/combobox_taskmenu.h new file mode 100644 index 0000000..9f80e40 --- /dev/null +++ b/tools/designer/src/components/taskmenu/combobox_taskmenu.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMBOBOX_TASKMENU_H +#define COMBOBOX_TASKMENU_H + +#include <QtGui/QComboBox> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ComboBoxTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ComboBoxTaskMenu(QComboBox *button, + QObject *parent = 0); + virtual ~ComboBoxTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QComboBox *m_comboBox; + QPointer<QDesignerFormWindowInterface> m_formWindow; + QPointer<QLineEdit> m_editor; + mutable QList<QAction*> m_taskActions; + QAction *m_editItemsAction; +}; + +class ComboBoxTaskMenuFactory : public ExtensionFactory<QDesignerTaskMenuExtension, QComboBox, ComboBoxTaskMenu> +{ +public: + explicit ComboBoxTaskMenuFactory(const QString &iid, QExtensionManager *extensionManager); + +private: + virtual QComboBox *checkObject(QObject *qObject) const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // COMBOBOX_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp new file mode 100644 index 0000000..b182ddf --- /dev/null +++ b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ContainerWidgetTaskMenu +*/ + +#include "containerwidget_taskmenu.h" + + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerContainerExtension> + +#include <qdesigner_command_p.h> +#include <qdesigner_dockwidget_p.h> +#include <promotiontaskmenu_p.h> +#include <widgetdatabase_p.h> + +#include <QtGui/QAction> +#include <QtGui/QMainWindow> +#include <QtGui/QToolBox> +#include <QtGui/QStackedWidget> +#include <QtGui/QTabWidget> +#include <QtGui/QScrollArea> +#include <QtGui/QMdiArea> +#include <QtGui/QWorkspace> +#include <QtGui/QWizard> +#include <QtGui/QMenu> + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +ContainerWidgetTaskMenu::ContainerWidgetTaskMenu(QWidget *widget, ContainerType type, QObject *parent) : + QDesignerTaskMenu(widget, parent), + m_type(type), + m_containerWidget(widget), + m_core(formWindow()->core()), + m_pagePromotionTaskMenu(new PromotionTaskMenu(0, PromotionTaskMenu::ModeSingleWidget, this)), + m_pageMenuAction(new QAction(this)), + m_pageMenu(new QMenu), + m_actionDeletePage(new QAction(tr("Delete"), this)) +{ + Q_ASSERT(m_core); + m_taskActions.append(createSeparator()); + + connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage())); + + QAction *actionInsertPageAfter = new QAction(this); + connect(actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter())); + // Empty Per-Page submenu, deletion and promotion. Updated on demand due to promotion state + switch (m_type) { + case WizardContainer: + case PageContainer: + m_taskActions.append(createSeparator()); // for the browse actions + break; + case MdiContainer: + break; + } + // submenu + m_pageMenuAction->setMenu(m_pageMenu); + m_taskActions.append(m_pageMenuAction); + // Insertion + switch (m_type) { + case WizardContainer: + case PageContainer: { // Before and after in a submenu + QAction *insertMenuAction = new QAction(tr("Insert"), this); + QMenu *insertMenu = new QMenu; + // before + QAction *actionInsertPage = new QAction(tr("Insert Page Before Current Page"), this); + connect(actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage())); + insertMenu->addAction(actionInsertPage); + // after + actionInsertPageAfter->setText(tr("Insert Page After Current Page")); + insertMenu->addAction(actionInsertPageAfter); + + insertMenuAction->setMenu(insertMenu); + m_taskActions.append(insertMenuAction); + } + break; + case MdiContainer: // No concept of order + actionInsertPageAfter->setText(tr("Add Subwindow")); + m_taskActions.append(actionInsertPageAfter); + break; + } +} + +ContainerWidgetTaskMenu::~ContainerWidgetTaskMenu() +{ +} + +QAction *ContainerWidgetTaskMenu::preferredEditAction() const +{ + return 0; +} + +bool ContainerWidgetTaskMenu::canDeletePage() const +{ + switch (pageCount()) { + case 0: + return false; + case 1: + return m_type != PageContainer; // Do not delete last page of page-type container + default: + break; + } + return true; +} + +int ContainerWidgetTaskMenu::pageCount() const +{ + if (const QDesignerContainerExtension *ce = containerExtension()) + return ce->count(); + return 0; +} + +QString ContainerWidgetTaskMenu::pageMenuText(ContainerType ct, int index, int count) +{ + if (ct == MdiContainer) + return tr("Subwindow"); // No concept of order, same text everywhere + if (index < 0) + return tr("Page"); + return tr("Page %1 of %2").arg(index + 1).arg(count); +} + +QList<QAction*> ContainerWidgetTaskMenu::taskActions() const +{ + QList<QAction*> actions = QDesignerTaskMenu::taskActions(); + actions += m_taskActions; + // Update the page submenu, deletion and promotion. Updated on demand due to promotion state. + m_pageMenu->clear(); + m_pageMenu->addAction(m_actionDeletePage); + m_actionDeletePage->setEnabled(canDeletePage()); + const QDesignerContainerExtension *ce = containerExtension(); + const int index = ce->currentIndex(); + m_pageMenuAction->setText(pageMenuText(m_type, index, ce->count())); + if (index != -1) { // Has a page + m_pageMenuAction->setEnabled(true); + m_pagePromotionTaskMenu->setWidget(ce->widget(index)); + m_pagePromotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator|PromotionTaskMenu::SuppressGlobalEdit, m_pageMenu); + } else { // No page + m_pageMenuAction->setEnabled(false); + } + + return actions; +} + +QDesignerFormWindowInterface *ContainerWidgetTaskMenu::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(m_containerWidget); +} + +QDesignerContainerExtension *ContainerWidgetTaskMenu::containerExtension() const +{ + QExtensionManager *mgr = m_core->extensionManager(); + return qt_extension<QDesignerContainerExtension*>(mgr, m_containerWidget); +} + +void ContainerWidgetTaskMenu::removeCurrentPage() +{ + if (QDesignerContainerExtension *c = containerExtension()) { + if (c->currentIndex() == -1) + return; + + QDesignerFormWindowInterface *fw = formWindow(); + DeleteContainerWidgetPageCommand *cmd = new DeleteContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type); + fw->commandHistory()->push(cmd); + } +} + +void ContainerWidgetTaskMenu::addPage() +{ + if (containerExtension()) { + QDesignerFormWindowInterface *fw = formWindow(); + AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type, AddContainerWidgetPageCommand::InsertBefore); + fw->commandHistory()->push(cmd); + } +} + +void ContainerWidgetTaskMenu::addPageAfter() +{ + if (containerExtension()) { + QDesignerFormWindowInterface *fw = formWindow(); + AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type, AddContainerWidgetPageCommand::InsertAfter); + fw->commandHistory()->push(cmd); + } +} + +// -------------- WizardContainerWidgetTaskMenu +WizardContainerWidgetTaskMenu::WizardContainerWidgetTaskMenu(QWizard *w, QObject *parent) : + ContainerWidgetTaskMenu(w, WizardContainer, parent), + m_nextAction(new QAction(tr("Next"), this)), + m_previousAction(new QAction(tr("Back"), this)) +{ + connect(m_nextAction, SIGNAL(triggered()), w, SLOT(next())); + connect(m_previousAction, SIGNAL(triggered()), w, SLOT(back())); + QList<QAction*> &l = containerActions(); + l.push_front(createSeparator()); + l.push_front(m_nextAction); + l.push_front(m_previousAction); + l.push_front(createSeparator()); +} + +QList<QAction*> WizardContainerWidgetTaskMenu::taskActions() const +{ + // Enable + const QDesignerContainerExtension *ce = containerExtension(); + const int index = ce->currentIndex(); + m_previousAction->setEnabled(index > 0); + m_nextAction->setEnabled(index >= 0 && index < (ce->count() - 1)); + return ContainerWidgetTaskMenu::taskActions(); +} + +// -------------- MdiContainerWidgetTaskMenu + +MdiContainerWidgetTaskMenu::MdiContainerWidgetTaskMenu(QMdiArea *m, QObject *parent) : + ContainerWidgetTaskMenu(m, MdiContainer, parent) +{ + initializeActions(); + connect(m_nextAction, SIGNAL(triggered()), m, SLOT( activateNextSubWindow ())); + connect(m_previousAction, SIGNAL(triggered()), m , SLOT(activatePreviousSubWindow())); + connect(m_tileAction, SIGNAL(triggered()), m, SLOT(tileSubWindows())); + connect(m_cascadeAction, SIGNAL(triggered()), m, SLOT(cascadeSubWindows ())); +} + +MdiContainerWidgetTaskMenu::MdiContainerWidgetTaskMenu(QWorkspace *m, QObject *parent) : + ContainerWidgetTaskMenu(m, MdiContainer, parent) +{ + initializeActions(); + connect(m_nextAction, SIGNAL(triggered()), m, SLOT(activateNextWindow())); + connect(m_previousAction, SIGNAL(triggered()), m, SLOT(activatePreviousWindow())); + connect(m_tileAction, SIGNAL(triggered()),m , SLOT(tile())); + connect(m_cascadeAction, SIGNAL(triggered()), m, SLOT(cascade())); +} + +void MdiContainerWidgetTaskMenu::initializeActions() +{ + m_nextAction =new QAction(tr("Next Subwindow"), this); + m_previousAction = new QAction(tr("Previous Subwindow"), this); + m_tileAction = new QAction(tr("Tile"), this); + m_cascadeAction = new QAction(tr("Cascade"), this); + + QList<QAction*> &l = containerActions(); + l.push_front(createSeparator()); + l.push_front(m_tileAction); + l.push_front(m_cascadeAction); + l.push_front(m_previousAction); + l.push_front(m_nextAction); + l.push_front(createSeparator()); +} + +QList<QAction*> MdiContainerWidgetTaskMenu::taskActions() const +{ + const QList<QAction*> rc = ContainerWidgetTaskMenu::taskActions(); + // Enable + const int count = pageCount(); + m_nextAction->setEnabled(count > 1); + m_previousAction->setEnabled(count > 1); + m_tileAction->setEnabled(count); + m_cascadeAction->setEnabled(count); + return rc; +} + +// -------------- ContainerWidgetTaskMenuFactory + +ContainerWidgetTaskMenuFactory::ContainerWidgetTaskMenuFactory(QDesignerFormEditorInterface *core, QExtensionManager *extensionManager) : + QExtensionFactory(extensionManager), + m_core(core) +{ +} + +QObject *ContainerWidgetTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != QLatin1String("QDesignerInternalTaskMenuExtension") || !object->isWidgetType()) + return 0; + + QWidget *widget = qobject_cast<QWidget*>(object); + + if (qobject_cast<QStackedWidget*>(widget) + || qobject_cast<QToolBox*>(widget) + || qobject_cast<QTabWidget*>(widget) + || qobject_cast<QDesignerDockWidget*>(widget) + || qobject_cast<QScrollArea*>(widget) + || qobject_cast<QMainWindow*>(widget)) { + // Are we using Designer's own container extensions and task menus or did + // someone provide an extra one with an addpage method, for example for a QScrollArea? + if (const WidgetDataBase *wb = qobject_cast<const WidgetDataBase *>(m_core->widgetDataBase())) { + const int idx = wb->indexOfObject(widget); + const WidgetDataBaseItem *item = static_cast<const WidgetDataBaseItem *>(wb->item(idx)); + if (item->addPageMethod().isEmpty()) + return 0; + } + } + + if (qt_extension<QDesignerContainerExtension*>(extensionManager(), object) == 0) + return 0; + + if (QMdiArea* ma = qobject_cast<QMdiArea*>(widget)) + return new MdiContainerWidgetTaskMenu(ma, parent); + if (QWorkspace *ws = qobject_cast<QWorkspace*>(widget)) + return new MdiContainerWidgetTaskMenu(ws, parent); + if (QWizard *wz = qobject_cast<QWizard *>(widget)) + return new WizardContainerWidgetTaskMenu(wz, parent); + return new ContainerWidgetTaskMenu(widget, PageContainer, parent); +} + +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/containerwidget_taskmenu.h b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.h new file mode 100644 index 0000000..25e24ed --- /dev/null +++ b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTAINERWIDGER_TASKMENU_H +#define CONTAINERWIDGER_TASKMENU_H + +#include <qdesigner_taskmenu_p.h> +#include <shared_enums_p.h> + +#include <extensionfactory_p.h> + +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QDesignerContainerExtension; +class QAction; +class QMdiArea; +class QWorkspace; +class QMenu; +class QWizard; + +namespace qdesigner_internal { + +class PromotionTaskMenu; + +// ContainerWidgetTaskMenu: Task menu for containers with extension + +class ContainerWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ContainerWidgetTaskMenu(QWidget *widget, ContainerType type, QObject *parent = 0); + virtual ~ContainerWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void removeCurrentPage(); + void addPage(); + void addPageAfter(); + +protected: + QDesignerContainerExtension *containerExtension() const; + QList<QAction*> &containerActions() { return m_taskActions; } + int pageCount() const; + +private: + QDesignerFormWindowInterface *formWindow() const; + +private: + static QString pageMenuText(ContainerType ct, int index, int count); + bool canDeletePage() const; + + const ContainerType m_type; + QWidget *m_containerWidget; + QDesignerFormEditorInterface *m_core; + PromotionTaskMenu *m_pagePromotionTaskMenu; + QAction *m_pageMenuAction; + QMenu *m_pageMenu; + QList<QAction*> m_taskActions; + QAction *m_actionDeletePage; +}; + +// WizardContainerWidgetTaskMenu: Provide next/back since QWizard +// has modes in which the "Back" button is not visible. + +class WizardContainerWidgetTaskMenu : public ContainerWidgetTaskMenu { + Q_OBJECT +public: + explicit WizardContainerWidgetTaskMenu(QWizard *w, QObject *parent = 0); + + virtual QList<QAction*> taskActions() const; + +private: + QAction *m_nextAction; + QAction *m_previousAction; +}; + + +// MdiContainerWidgetTaskMenu: Provide tile/cascade for MDI containers in addition + +class MdiContainerWidgetTaskMenu : public ContainerWidgetTaskMenu { + Q_OBJECT +public: + explicit MdiContainerWidgetTaskMenu(QMdiArea *m, QObject *parent = 0); + explicit MdiContainerWidgetTaskMenu(QWorkspace *m, QObject *parent = 0); + + virtual QList<QAction*> taskActions() const; +private: + void initializeActions(); + + QAction *m_nextAction; + QAction *m_previousAction; + QAction *m_tileAction; + QAction *m_cascadeAction; +}; + +class ContainerWidgetTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + explicit ContainerWidgetTaskMenuFactory(QDesignerFormEditorInterface *core, QExtensionManager *extensionManager = 0); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; + +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // CONTAINERWIDGER_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp b/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp new file mode 100644 index 0000000..bb97342 --- /dev/null +++ b/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::GroupBoxTaskMenu +*/ + +#include "groupbox_taskmenu.h" +#include "inplace_editor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- GroupBoxTaskMenuInlineEditor +class GroupBoxTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + GroupBoxTaskMenuInlineEditor(QGroupBox *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +GroupBoxTaskMenuInlineEditor::GroupBoxTaskMenuInlineEditor(QGroupBox *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationSingleLine, QLatin1String("title"), parent) +{ +} + +QRect GroupBoxTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); + QStyleOption opt; // ## QStyleOptionGroupBox + opt.init(w); + return QRect(QPoint(), QSize(w->width(),20)); +} + +// --------------- GroupBoxTaskMenu + +GroupBoxTaskMenu::GroupBoxTaskMenu(QGroupBox *groupbox, QObject *parent) + : QDesignerTaskMenu(groupbox, parent), + m_editTitleAction(new QAction(tr("Change title..."), this)) + +{ + TaskMenuInlineEditor *editor = new GroupBoxTaskMenuInlineEditor(groupbox, this); + connect(m_editTitleAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editTitleAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QList<QAction*> GroupBoxTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +QAction *GroupBoxTaskMenu::preferredEditAction() const +{ + return m_editTitleAction; +} + +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/groupbox_taskmenu.h b/tools/designer/src/components/taskmenu/groupbox_taskmenu.h new file mode 100644 index 0000000..8e2d36f --- /dev/null +++ b/tools/designer/src/components/taskmenu/groupbox_taskmenu.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GROUPBOX_TASKMENU_H +#define GROUPBOX_TASKMENU_H + +#include <QtGui/QGroupBox> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +class InPlaceEditor; + +class GroupBoxTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit GroupBoxTaskMenu(QGroupBox *groupbox, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QAction *m_editTitleAction; + QList<QAction*> m_taskActions; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QGroupBox, GroupBoxTaskMenu> GroupBoxTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // GROUPBOX_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/inplace_editor.cpp b/tools/designer/src/components/taskmenu/inplace_editor.cpp new file mode 100644 index 0000000..322d1ed --- /dev/null +++ b/tools/designer/src/components/taskmenu/inplace_editor.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindow.h" +#include "inplace_editor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <QtDesigner/QDesignerPropertySheetExtension> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerLanguageExtension> +#include <QtDesigner/QExtensionManager> + +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ----------------- InPlaceEditor + +InPlaceEditor::InPlaceEditor(QWidget *widget, + TextPropertyValidationMode validationMode, + QDesignerFormWindowInterface *fw, + const QString& text, + const QRect& r) : + TextPropertyEditor(widget, EmbeddingInPlace, validationMode), + m_InPlaceWidgetHelper(this, widget, fw) +{ + setAlignment(m_InPlaceWidgetHelper.alignment()); + setObjectName(QLatin1String("__qt__passive_m_editor")); + + setText(text); + selectAll(); + + setGeometry(QRect(widget->mapTo(widget->window(), r.topLeft()), r.size())); + setFocus(); + show(); + + connect(this, SIGNAL(editingFinished()),this, SLOT(close())); +} + + +// -------------- TaskMenuInlineEditor + +TaskMenuInlineEditor::TaskMenuInlineEditor(QWidget *w, TextPropertyValidationMode vm, + const QString &property, QObject *parent) : + QObject(parent), + m_vm(vm), + m_property(property), + m_widget(w), + m_managed(true) +{ +} + +void TaskMenuInlineEditor::editText() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_widget); + if (m_formWindow.isNull()) + return; + m_managed = m_formWindow->isManaged(m_widget); + // Close as soon as a different widget is selected + connect(m_formWindow, SIGNAL(selectionChanged()), this, SLOT(updateSelection())); + + // get old value + QDesignerFormEditorInterface *core = m_formWindow->core(); + const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), m_widget); + const int index = sheet->indexOf(m_property); + if (index == -1) + return; + m_value = qVariantValue<PropertySheetStringValue>(sheet->property(index)); + const QString oldValue = m_value.value(); + + m_editor = new InPlaceEditor(m_widget, m_vm, m_formWindow, oldValue, editRectangle()); + connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(updateText(QString))); +} + +void TaskMenuInlineEditor::updateText(const QString &text) +{ + // In the [rare] event we are invoked on an unmanaged widget, + // do not use the cursor selection + m_value.setValue(text); + if (m_managed) { + m_formWindow->cursor()->setProperty(m_property, qVariantFromValue(m_value)); + } else { + m_formWindow->cursor()->setWidgetProperty(m_widget, m_property, qVariantFromValue(m_value)); + } +} + +void TaskMenuInlineEditor::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/inplace_editor.h b/tools/designer/src/components/taskmenu/inplace_editor.h new file mode 100644 index 0000000..8c59aeb --- /dev/null +++ b/tools/designer/src/components/taskmenu/inplace_editor.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPLACE_EDITOR_H +#define INPLACE_EDITOR_H + +#include <textpropertyeditor_p.h> +#include <shared_enums_p.h> + +#include "inplace_widget_helper.h" +#include <qdesigner_utils_p.h> + +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class InPlaceEditor: public TextPropertyEditor +{ + Q_OBJECT +public: + InPlaceEditor(QWidget *widget, + TextPropertyValidationMode validationMode, + QDesignerFormWindowInterface *fw, + const QString& text, + const QRect& r); +private: + InPlaceWidgetHelper m_InPlaceWidgetHelper; +}; + +// Base class for inline editor helpers to be embedded into a task menu. +// Inline-edits a property on a multi-selection. +// To use it for a particular widget/property, overwrite the method +// returning the edit area. + +class TaskMenuInlineEditor : public QObject { + TaskMenuInlineEditor(const TaskMenuInlineEditor&); + TaskMenuInlineEditor &operator=(const TaskMenuInlineEditor&); + Q_OBJECT + +public slots: + void editText(); + +private slots: + void updateText(const QString &text); + void updateSelection(); + +protected: + TaskMenuInlineEditor(QWidget *w, TextPropertyValidationMode vm, const QString &property, QObject *parent); + // Overwrite to return the area for the inline editor. + virtual QRect editRectangle() const = 0; + QWidget *widget() const { return m_widget; } + +private: + const TextPropertyValidationMode m_vm; + const QString m_property; + QWidget *m_widget; + QPointer<QDesignerFormWindowInterface> m_formWindow; + QPointer<InPlaceEditor> m_editor; + bool m_managed; + qdesigner_internal::PropertySheetStringValue m_value; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // INPLACE_EDITOR_H diff --git a/tools/designer/src/components/taskmenu/inplace_widget_helper.cpp b/tools/designer/src/components/taskmenu/inplace_widget_helper.cpp new file mode 100644 index 0000000..5cf3df1 --- /dev/null +++ b/tools/designer/src/components/taskmenu/inplace_widget_helper.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindow.h" +#include "inplace_widget_helper.h" + +#include <QtGui/QResizeEvent> +#include <QtGui/QPushButton> +#include <QtGui/QToolButton> +#include <QtGui/QShortcut> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + InPlaceWidgetHelper::InPlaceWidgetHelper(QWidget *editorWidget, QWidget *parentWidget, QDesignerFormWindowInterface *fw) + : QObject(0), + m_editorWidget(editorWidget), + m_parentWidget(parentWidget), + m_noChildEvent(m_parentWidget->testAttribute(Qt::WA_NoChildEventsForParent)) + { + m_editorWidget->setAttribute(Qt::WA_DeleteOnClose); + m_editorWidget->setParent(m_parentWidget->window()); + m_parentWidget->installEventFilter(this); + m_editorWidget->installEventFilter(this); + connect(m_editorWidget, SIGNAL(destroyed()), fw->mainContainer(), SLOT(setFocus())); + } + + InPlaceWidgetHelper::~InPlaceWidgetHelper() + { + m_parentWidget->setAttribute(Qt::WA_NoChildEventsForParent, m_noChildEvent); + } + + Qt::Alignment InPlaceWidgetHelper::alignment() const { + if (m_parentWidget->metaObject()->indexOfProperty("alignment") != -1) + return Qt::Alignment(m_parentWidget->property("alignment").toInt()); + + if (qobject_cast<const QPushButton *>(m_parentWidget) + || qobject_cast<const QToolButton *>(m_parentWidget) /* tool needs to be more complex */) + return Qt::AlignHCenter; + + return Qt::AlignJustify; + } + + + bool InPlaceWidgetHelper::eventFilter(QObject *object, QEvent *e) + { + if (object == m_parentWidget) { + if (e->type() == QEvent::Resize) { + const QResizeEvent *event = static_cast<const QResizeEvent*>(e); + const QPoint localPos = m_parentWidget->geometry().topLeft(); + const QPoint globalPos = m_parentWidget->parentWidget() ? m_parentWidget->parentWidget()->mapToGlobal(localPos) : localPos; + const QPoint newPos = (m_editorWidget->parentWidget() ? m_editorWidget->parentWidget()->mapFromGlobal(globalPos) : globalPos) + + m_posOffset; + const QSize newSize = event->size() + m_sizeOffset; + m_editorWidget->setGeometry(QRect(newPos, newSize)); + } + } else if (object == m_editorWidget) { + if (e->type() == QEvent::ShortcutOverride) { + if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { + e->accept(); + return false; + } + } else if (e->type() == QEvent::KeyPress) { + if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { + e->accept(); + m_editorWidget->close(); + return true; + } + } else if (e->type() == QEvent::Show) { + const QPoint localPos = m_parentWidget->geometry().topLeft(); + const QPoint globalPos = m_parentWidget->parentWidget() ? m_parentWidget->parentWidget()->mapToGlobal(localPos) : localPos; + const QPoint newPos = m_editorWidget->parentWidget() ? m_editorWidget->parentWidget()->mapFromGlobal(globalPos) : globalPos; + m_posOffset = m_editorWidget->geometry().topLeft() - newPos; + m_sizeOffset = m_editorWidget->size() - m_parentWidget->size(); + } + } + + return QObject::eventFilter(object, e); + } +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/inplace_widget_helper.h b/tools/designer/src/components/taskmenu/inplace_widget_helper.h new file mode 100644 index 0000000..2b74d57 --- /dev/null +++ b/tools/designer/src/components/taskmenu/inplace_widget_helper.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPLACE_WIDGETHELPER_H +#define INPLACE_WIDGETHELPER_H + + +#include <QtCore/QObject> +#include <QtCore/QPoint> +#include <QtCore/QSize> +#include <qglobal.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + // A helper class to make an editor widget suitable for form inline + // editing. Derive from the editor widget class and make InPlaceWidgetHelper a member. + // + // Sets "destructive close" on the editor widget and + // wires "ESC" to it. + // Installs an event filter on the parent to listen for + // resize events and passes them on to the child. + // You might want to connect editingFinished() to close() of the editor widget. + class InPlaceWidgetHelper: public QObject + { + Q_OBJECT + public: + InPlaceWidgetHelper(QWidget *editorWidget, QWidget *parentWidget, QDesignerFormWindowInterface *fw); + virtual ~InPlaceWidgetHelper(); + + virtual bool eventFilter(QObject *object, QEvent *event); + + // returns a recommended alignment for the editor widget determined from the parent. + Qt::Alignment alignment() const; + private: + QWidget *m_editorWidget; + QWidget *m_parentWidget; + const bool m_noChildEvent; + QPoint m_posOffset; + QSize m_sizeOffset; + }; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // INPLACE_WIDGETHELPER_H diff --git a/tools/designer/src/components/taskmenu/itemlisteditor.cpp b/tools/designer/src/components/taskmenu/itemlisteditor.cpp new file mode 100644 index 0000000..4e6940e --- /dev/null +++ b/tools/designer/src/components/taskmenu/itemlisteditor.cpp @@ -0,0 +1,489 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemlisteditor.h" +#include <abstractformbuilder.h> +#include <iconloader_p.h> +#include <formwindowbase_p.h> +#include <designerpropertymanager.h> + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <qttreepropertybrowser.h> + +#include <QtGui/QSplitter> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class ItemPropertyBrowser : public QtTreePropertyBrowser +{ +public: + ItemPropertyBrowser() + { + setResizeMode(Interactive); + //: Sample string to determinate the width for the first column of the list item property browser + const QString widthSampleString = QCoreApplication::translate("ItemPropertyBrowser", "XX Icon Selected off"); + m_width = fontMetrics().width(widthSampleString); + setSplitterPosition(m_width); + m_width += fontMetrics().width(QLatin1String("/this/is/some/random/path")); + } + + virtual QSize sizeHint() const + { + return QSize(m_width, 1); + } + +private: + int m_width; +}; + +////////////////// Item editor /////////////// +AbstractItemEditor::AbstractItemEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : QDialog(parent), + m_iconCache(qobject_cast<FormWindowBase *>(form)->iconCache()), + m_updatingBrowser(false) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_propertyManager = new DesignerPropertyManager(form->core(), this); + m_editorFactory = new DesignerEditorFactory(form->core(), this); + m_editorFactory->setSpacing(0); + m_propertyBrowser = new ItemPropertyBrowser; + m_propertyBrowser->setFactoryForManager((QtVariantPropertyManager *)m_propertyManager, + m_editorFactory); + + connect(m_editorFactory, SIGNAL(resetProperty(QtProperty*)), + SLOT(resetProperty(QtProperty*))); + connect(m_propertyManager, SIGNAL(valueChanged(QtProperty*,QVariant,bool)), + SLOT(propertyChanged(QtProperty*))); + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +AbstractItemEditor::~AbstractItemEditor() +{ + m_propertyBrowser->unsetFactoryForManager(m_propertyManager); +} + +void AbstractItemEditor::keyPressEvent(QKeyEvent *e) +{ + // Avoid that embedded dialogs react to enter and escape keys. + if (this == window()) + QDialog::keyPressEvent(e); + else + QWidget::keyPressEvent(e); +} + +static const char * const itemFlagNames[] = { + "Selectable", + "Editable", + "DragEnabled", + "DropEnabled", + "UserCheckable", + "Enabled", + "Tristate", + 0 +}; + +static const char * const checkStateNames[] = { + "Unchecked", + "PartiallyChecked", + "Checked", + 0 +}; + +static QStringList c2qStringList(const char * const in[]) +{ + QStringList out; + for (int i = 0; in[i]; i++) + out << QLatin1String(in[i]); + return out; +} + +void AbstractItemEditor::setupProperties(PropertyDefinition *propList) +{ + for (int i = 0; propList[i].name; i++) { + int type = propList[i].typeFunc ? propList[i].typeFunc() : propList[i].type; + int role = propList[i].role; + QtVariantProperty *prop = m_propertyManager->addProperty(type, QLatin1String(propList[i].name)); + Q_ASSERT(prop); + if (role == Qt::ToolTipPropertyRole || role == Qt::WhatsThisPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationRichText); + else if (role == Qt::DisplayPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationMultiLine); + else if (role == Qt::StatusTipPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationSingleLine); + else if (role == ItemFlagsShadowRole) + prop->setAttribute(QLatin1String("flagNames"), c2qStringList(itemFlagNames)); + else if (role == Qt::CheckStateRole) + prop->setAttribute(QLatin1String("enumNames"), c2qStringList(checkStateNames)); + prop->setAttribute(QLatin1String("resettable"), true); + m_properties.append(prop); + m_rootProperties.append(prop); + m_propertyToRole.insert(prop, role); + } +} + +void AbstractItemEditor::setupObject(QWidget *object) +{ + m_propertyManager->setObject(object); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(object); + FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow); + m_editorFactory->setFormWindowBase(fwb); +} + +void AbstractItemEditor::setupEditor(QWidget *object, PropertyDefinition *propList) +{ + setupProperties(propList); + setupObject(object); +} + +void AbstractItemEditor::propertyChanged(QtProperty *property) +{ + if (m_updatingBrowser) + return; + + + BoolBlocker block(m_updatingBrowser); + QtVariantProperty *prop = m_propertyManager->variantProperty(property); + int role; + if ((role = m_propertyToRole.value(prop, -1)) == -1) + // Subproperty + return; + + if ((role == ItemFlagsShadowRole && prop->value().toInt() == (int)QListWidgetItem().flags()) + || (role == Qt::DecorationPropertyRole && !qVariantValue<PropertySheetIconValue>(prop->value()).mask()) + || (role == Qt::FontRole && !qVariantValue<QFont>(prop->value()).resolve())) { + prop->setModified(false); + setItemData(role, QVariant()); + } else { + prop->setModified(true); + setItemData(role, prop->value()); + } + + switch (role) { + case Qt::DecorationPropertyRole: + setItemData(Qt::DecorationRole, qVariantFromValue(iconCache()->icon(qVariantValue<PropertySheetIconValue>(prop->value())))); + break; + case Qt::DisplayPropertyRole: + setItemData(Qt::EditRole, qVariantFromValue(qVariantValue<PropertySheetStringValue>(prop->value()).value())); + break; + case Qt::ToolTipPropertyRole: + setItemData(Qt::ToolTipRole, qVariantFromValue(qVariantValue<PropertySheetStringValue>(prop->value()).value())); + break; + case Qt::StatusTipPropertyRole: + setItemData(Qt::StatusTipRole, qVariantFromValue(qVariantValue<PropertySheetStringValue>(prop->value()).value())); + break; + case Qt::WhatsThisPropertyRole: + setItemData(Qt::WhatsThisRole, qVariantFromValue(qVariantValue<PropertySheetStringValue>(prop->value()).value())); + break; + default: + break; + } + + prop->setValue(getItemData(role)); +} + +void AbstractItemEditor::resetProperty(QtProperty *property) +{ + if (m_propertyManager->resetFontSubProperty(property)) + return; + + if (m_propertyManager->resetIconSubProperty(property)) + return; + + BoolBlocker block(m_updatingBrowser); + + QtVariantProperty *prop = m_propertyManager->variantProperty(property); + int role = m_propertyToRole.value(prop); + if (role == ItemFlagsShadowRole) + prop->setValue(qVariantFromValue((int)QListWidgetItem().flags())); + else + prop->setValue(QVariant(prop->valueType(), (void *)0)); + prop->setModified(false); + + setItemData(role, QVariant()); + if (role == Qt::DecorationPropertyRole) + setItemData(Qt::DecorationRole, qVariantFromValue(QIcon())); + if (role == Qt::DisplayPropertyRole) + setItemData(Qt::EditRole, qVariantFromValue(QString())); + if (role == Qt::ToolTipPropertyRole) + setItemData(Qt::ToolTipRole, qVariantFromValue(QString())); + if (role == Qt::StatusTipPropertyRole) + setItemData(Qt::StatusTipRole, qVariantFromValue(QString())); + if (role == Qt::WhatsThisPropertyRole) + setItemData(Qt::WhatsThisRole, qVariantFromValue(QString())); +} + +void AbstractItemEditor::cacheReloaded() +{ + BoolBlocker block(m_updatingBrowser); + m_propertyManager->reloadResourceProperties(); +} + +void AbstractItemEditor::updateBrowser() +{ + BoolBlocker block(m_updatingBrowser); + foreach (QtVariantProperty *prop, m_properties) { + int role = m_propertyToRole.value(prop); + QVariant val = getItemData(role); + if (!val.isValid()) { + if (role == ItemFlagsShadowRole) + val = qVariantFromValue((int)QListWidgetItem().flags()); + else + val = QVariant((int)prop->value().userType(), (void *)0); + prop->setModified(false); + } else { + prop->setModified(true); + } + prop->setValue(val); + } + + if (m_propertyBrowser->topLevelItems().isEmpty()) + foreach (QtVariantProperty *prop, m_rootProperties) + m_propertyBrowser->addProperty(prop); +} + +void AbstractItemEditor::injectPropertyBrowser(QWidget *parent, QWidget *widget) +{ + // It is impossible to design a splitter with just one widget, so we do it by hand. + m_propertySplitter = new QSplitter; + m_propertySplitter->addWidget(widget); + m_propertySplitter->addWidget(m_propertyBrowser); + m_propertySplitter->setStretchFactor(0, 1); + m_propertySplitter->setStretchFactor(1, 0); + parent->layout()->addWidget(m_propertySplitter); +} + +////////////////// List editor /////////////// +ItemListEditor::ItemListEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : AbstractItemEditor(form, parent), + m_updating(false) +{ + ui.setupUi(this); + + injectPropertyBrowser(this, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + togglePropertyBrowser(); + + QIcon upIcon = createIconSet(QString::fromUtf8("up.png")); + QIcon downIcon = createIconSet(QString::fromUtf8("down.png")); + QIcon minusIcon = createIconSet(QString::fromUtf8("minus.png")); + QIcon plusIcon = createIconSet(QString::fromUtf8("plus.png")); + ui.moveListItemUpButton->setIcon(upIcon); + ui.moveListItemDownButton->setIcon(downIcon); + ui.newListItemButton->setIcon(plusIcon); + ui.deleteListItemButton->setIcon(minusIcon); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +void ItemListEditor::setupEditor(QWidget *object, PropertyDefinition *propList) +{ + AbstractItemEditor::setupEditor(object, propList); + + if (ui.listWidget->count() > 0) + ui.listWidget->setCurrentRow(0); + else + updateEditor(); +} + +void ItemListEditor::setCurrentIndex(int idx) +{ + m_updating = true; + ui.listWidget->setCurrentRow(idx); + m_updating = false; +} + +void ItemListEditor::on_newListItemButton_clicked() +{ + int row = ui.listWidget->currentRow() + 1; + + QListWidgetItem *item = new QListWidgetItem(m_newItemText); + item->setData(Qt::DisplayPropertyRole, qVariantFromValue(PropertySheetStringValue(m_newItemText))); + item->setFlags(item->flags() | Qt::ItemIsEditable); + if (row < ui.listWidget->count()) + ui.listWidget->insertItem(row, item); + else + ui.listWidget->addItem(item); + emit itemInserted(row); + + ui.listWidget->setCurrentItem(item); + ui.listWidget->editItem(item); +} + +void ItemListEditor::on_deleteListItemButton_clicked() +{ + int row = ui.listWidget->currentRow(); + + if (row != -1) { + delete ui.listWidget->takeItem(row); + emit itemDeleted(row); + } + + if (row == ui.listWidget->count()) + row--; + if (row < 0) + updateEditor(); + else + ui.listWidget->setCurrentRow(row); +} + +void ItemListEditor::on_moveListItemUpButton_clicked() +{ + int row = ui.listWidget->currentRow(); + if (row <= 0) + return; // nothing to do + + ui.listWidget->insertItem(row - 1, ui.listWidget->takeItem(row)); + ui.listWidget->setCurrentRow(row - 1); + emit itemMovedUp(row); +} + +void ItemListEditor::on_moveListItemDownButton_clicked() +{ + int row = ui.listWidget->currentRow(); + if (row == -1 || row == ui.listWidget->count() - 1) + return; // nothing to do + + ui.listWidget->insertItem(row + 1, ui.listWidget->takeItem(row)); + ui.listWidget->setCurrentRow(row + 1); + emit itemMovedDown(row); +} + +void ItemListEditor::on_listWidget_currentRowChanged() +{ + updateEditor(); + if (!m_updating) + emit indexChanged(ui.listWidget->currentRow()); +} + +void ItemListEditor::on_listWidget_itemChanged(QListWidgetItem *item) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qVariantValue<PropertySheetStringValue>(item->data(Qt::DisplayPropertyRole)); + val.setValue(item->text()); + BoolBlocker block(m_updatingBrowser); + item->setData(Qt::DisplayPropertyRole, qVariantFromValue(val)); + + // The checkState could change, too, but if this signal is connected, + // checkState is not in the list anyway, as we are editing a header item. + emit itemChanged(ui.listWidget->currentRow(), Qt::DisplayPropertyRole, + qVariantFromValue(val)); + updateBrowser(); +} + +void ItemListEditor::togglePropertyBrowser() +{ + // Always hide in case parent widget is not visible -> on startup + const bool isVisible = + !this->isVisible() ? true : m_propertyBrowser->isVisible(); + if (isVisible) + ui.showPropertiesButton->setText(tr("Properties &<<")); + else + ui.showPropertiesButton->setText(tr("Properties &>>")); + + m_propertyBrowser->setVisible(!isVisible); +} + +void ItemListEditor::setItemData(int role, const QVariant &v) +{ + QListWidgetItem *item = ui.listWidget->currentItem(); + bool reLayout = false; + if ((role == Qt::EditRole && (v.toString().count(QLatin1Char('\n')) != item->data(role).toString().count(QLatin1Char('\n')))) + || role == Qt::FontRole) + reLayout = true; + QVariant newValue = v; + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.listWidget->font(); + QFont newFont = qVariantValue<QFont>(newValue).resolve(oldFont); + newValue = qVariantFromValue(newFont); + item->setData(role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + item->setData(role, newValue); + if (reLayout) + ui.listWidget->doItemsLayout(); + emit itemChanged(ui.listWidget->currentRow(), role, newValue); +} + +QVariant ItemListEditor::getItemData(int role) const +{ + return ui.listWidget->currentItem()->data(role); +} + +void ItemListEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.listWidget); +} + +void ItemListEditor::updateEditor() +{ + bool currentItemEnabled = false; + + bool moveRowUpEnabled = false; + bool moveRowDownEnabled = false; + + QListWidgetItem *item = ui.listWidget->currentItem(); + if (item) { + currentItemEnabled = true; + int currentRow = ui.listWidget->currentRow(); + if (currentRow > 0) + moveRowUpEnabled = true; + if (currentRow < ui.listWidget->count() - 1) + moveRowDownEnabled = true; + } + + ui.moveListItemUpButton->setEnabled(moveRowUpEnabled); + ui.moveListItemDownButton->setEnabled(moveRowDownEnabled); + ui.deleteListItemButton->setEnabled(currentItemEnabled); + + if (item) + updateBrowser(); + else + m_propertyBrowser->clear(); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/itemlisteditor.h b/tools/designer/src/components/taskmenu/itemlisteditor.h new file mode 100644 index 0000000..347dcbb --- /dev/null +++ b/tools/designer/src/components/taskmenu/itemlisteditor.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ITEMLISTEDITOR_H +#define ITEMLISTEDITOR_H + +#include "ui_itemlisteditor.h" + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QtProperty; +class QtVariantProperty; +class QtTreePropertyBrowser; +class QSplitter; + +namespace qdesigner_internal { + +class DesignerIconCache; +class DesignerPropertyManager; +class DesignerEditorFactory; + +// Utility class that ensures a bool is true while in scope. +// Courtesy of QBoolBlocker in qobject_p.h +class BoolBlocker +{ +public: + inline BoolBlocker(bool &b):block(b), reset(b){block = true;} + inline ~BoolBlocker(){block = reset; } +private: + bool █ + bool reset; +}; + +class AbstractItemEditor: public QDialog +{ + Q_OBJECT + +public: + AbstractItemEditor(QDesignerFormWindowInterface *form, QWidget *parent); + ~AbstractItemEditor(); + + DesignerIconCache *iconCache() const { return m_iconCache; } + + struct PropertyDefinition { + int role; + int type; + int (*typeFunc)(); + const char *name; + }; + +private slots: + void propertyChanged(QtProperty *property); + void resetProperty(QtProperty *property); + void cacheReloaded(); + +protected: + void keyPressEvent(QKeyEvent *e); + void setupProperties(PropertyDefinition *propDefs); + void setupObject(QWidget *object); + void setupEditor(QWidget *object, PropertyDefinition *propDefs); + void injectPropertyBrowser(QWidget *parent, QWidget *widget); + void updateBrowser(); + virtual void setItemData(int role, const QVariant &v) = 0; + virtual QVariant getItemData(int role) const = 0; + + DesignerIconCache *m_iconCache; + DesignerPropertyManager *m_propertyManager; + DesignerEditorFactory *m_editorFactory; + QSplitter *m_propertySplitter; + QtTreePropertyBrowser *m_propertyBrowser; + QList<QtVariantProperty*> m_properties; + QList<QtVariantProperty*> m_rootProperties; + QHash<QtVariantProperty*, int> m_propertyToRole; + bool m_updatingBrowser; +}; + +class ItemListEditor: public AbstractItemEditor +{ + Q_OBJECT + +public: + ItemListEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + void setupEditor(QWidget *object, PropertyDefinition *propDefs); + QListWidget *listWidget() const { return ui.listWidget; } + void setNewItemText(const QString &tpl) { m_newItemText = tpl; } + QString newItemText() const { return m_newItemText; } + void setCurrentIndex(int idx); + +signals: + void indexChanged(int idx); + void itemChanged(int idx, int role, const QVariant &v); + void itemInserted(int idx); + void itemDeleted(int idx); + void itemMovedUp(int idx); + void itemMovedDown(int idx); + +private slots: + void on_newListItemButton_clicked(); + void on_deleteListItemButton_clicked(); + void on_moveListItemUpButton_clicked(); + void on_moveListItemDownButton_clicked(); + void on_listWidget_currentRowChanged(); + void on_listWidget_itemChanged(QListWidgetItem * item); + void togglePropertyBrowser(); + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + + void updateEditor(); + Ui::ItemListEditor ui; + bool m_updating; + QString m_newItemText; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ITEMLISTEDITOR_H diff --git a/tools/designer/src/components/taskmenu/itemlisteditor.ui b/tools/designer/src/components/taskmenu/itemlisteditor.ui new file mode 100644 index 0000000..62e5b27 --- /dev/null +++ b/tools/designer/src/components/taskmenu/itemlisteditor.ui @@ -0,0 +1,156 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::ItemListEditor</class> + <widget class="QWidget" name="qdesigner_internal::ItemListEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>550</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle" > + <string/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QWidget" native="1" name="widget" > + <layout class="QVBoxLayout" name="verticalLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QListWidget" name="listWidget" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="toolTip" > + <string>Items List</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="buttonsLayout" > + <item> + <widget class="QToolButton" name="newListItemButton" > + <property name="toolTip" > + <string>New Item</string> + </property> + <property name="text" > + <string>&New</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="deleteListItemButton" > + <property name="toolTip" > + <string>Delete Item</string> + </property> + <property name="text" > + <string>&Delete</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>16</width> + <height>10</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="moveListItemUpButton" > + <property name="toolTip" > + <string>Move Item Up</string> + </property> + <property name="text" > + <string>U</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="moveListItemDownButton" > + <property name="toolTip" > + <string>Move Item Down</string> + </property> + <property name="text" > + <string>D</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="showPropertiesButton" > + <property name="text" > + <string>Properties &>></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/designer/src/components/taskmenu/label_taskmenu.cpp b/tools/designer/src/components/taskmenu/label_taskmenu.cpp new file mode 100644 index 0000000..77e5ed9 --- /dev/null +++ b/tools/designer/src/components/taskmenu/label_taskmenu.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::LabelTaskMenu +*/ + +#include "label_taskmenu.h" +#include "inplace_editor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> +#include <QtGui/QTextDocument> + +static const char *textPropertyC = "text"; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- LabelTaskMenuInlineEditor +class LabelTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LabelTaskMenuInlineEditor(QLabel *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LabelTaskMenuInlineEditor::LabelTaskMenuInlineEditor(QLabel *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationRichText, QLatin1String(textPropertyC), parent) +{ +} + +QRect LabelTaskMenuInlineEditor::editRectangle() const +{ + QStyleOptionButton opt; + opt.init(widget()); + return opt.rect; +} + +// --------------- LabelTaskMenu + +LabelTaskMenu::LabelTaskMenu(QLabel *label, QObject *parent) + : QDesignerTaskMenu(label, parent), + m_label(label), + m_editRichTextAction(new QAction(tr("Change rich text..."), this)), + m_editPlainTextAction(new QAction(tr("Change plain text..."), this)) +{ + LabelTaskMenuInlineEditor *editor = new LabelTaskMenuInlineEditor(label, this); + connect(m_editPlainTextAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editPlainTextAction); + + connect(m_editRichTextAction, SIGNAL(triggered()), this, SLOT(editRichText())); + m_taskActions.append(m_editRichTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QAction *LabelTaskMenu::preferredEditAction() const +{ + if (m_label->textFormat () == Qt::PlainText) return m_editPlainTextAction; + return Qt::mightBeRichText(m_label->text()) ? m_editRichTextAction : m_editPlainTextAction; +} + +QList<QAction*> LabelTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void LabelTaskMenu::editRichText() +{ + changeTextProperty(QLatin1String(textPropertyC), QString(), MultiSelectionMode, m_label->textFormat()); +} + +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/label_taskmenu.h b/tools/designer/src/components/taskmenu/label_taskmenu.h new file mode 100644 index 0000000..0d7722b --- /dev/null +++ b/tools/designer/src/components/taskmenu/label_taskmenu.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LABEL_TASKMENU_H +#define LABEL_TASKMENU_H + +#include <QtGui/QLabel> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class LabelTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit LabelTaskMenu(QLabel *button, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editRichText(); + +private: + QLabel *m_label; + QList<QAction*> m_taskActions; + QAction *m_editRichTextAction; + QAction *m_editPlainTextAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QLabel, LabelTaskMenu> LabelTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LABEL_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/layouttaskmenu.cpp b/tools/designer/src/components/taskmenu/layouttaskmenu.cpp new file mode 100644 index 0000000..4a3aeec --- /dev/null +++ b/tools/designer/src/components/taskmenu/layouttaskmenu.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::LayoutWidgetTaskMenu +*/ + +#include "layouttaskmenu.h" +#include <formlayoutmenu_p.h> +#include <morphmenu_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +// ------------ LayoutWidgetTaskMenu +LayoutWidgetTaskMenu::LayoutWidgetTaskMenu(QLayoutWidget *lw, QObject *parent) : + QObject(parent), + m_widget(lw), + m_morphMenu(new qdesigner_internal::MorphMenu(this)), + m_formLayoutMenu(new qdesigner_internal::FormLayoutMenu(this)) +{ +} + +QAction *LayoutWidgetTaskMenu::preferredEditAction() const +{ + return m_formLayoutMenu->preferredEditAction(m_widget, m_widget->formWindow()); +} + +QList<QAction*> LayoutWidgetTaskMenu::taskActions() const +{ + QList<QAction*> rc; + QDesignerFormWindowInterface *fw = m_widget->formWindow(); + m_morphMenu->populate(m_widget, fw, rc); + m_formLayoutMenu->populate(m_widget, fw, rc); + return rc; +} + +// ------------- SpacerTaskMenu +SpacerTaskMenu::SpacerTaskMenu(Spacer *, QObject *parent) : + QObject(parent) +{ +} + +QAction *SpacerTaskMenu::preferredEditAction() const +{ + return 0; +} + +QList<QAction*> SpacerTaskMenu::taskActions() const +{ + return QList<QAction*>(); +} + +QT_END_NAMESPACE + diff --git a/tools/designer/src/components/taskmenu/layouttaskmenu.h b/tools/designer/src/components/taskmenu/layouttaskmenu.h new file mode 100644 index 0000000..97fde9c --- /dev/null +++ b/tools/designer/src/components/taskmenu/layouttaskmenu.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAYOUTTASKMENU_H +#define LAYOUTTASKMENU_H + +#include <QtDesigner/QDesignerTaskMenuExtension> + +#include <qlayout_widget_p.h> +#include <spacer_widget_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class FormLayoutMenu; + class MorphMenu; +} + +// Morph menu for QLayoutWidget. +class LayoutWidgetTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit LayoutWidgetTaskMenu(QLayoutWidget *w, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QLayoutWidget *m_widget; + qdesigner_internal::MorphMenu *m_morphMenu; + qdesigner_internal::FormLayoutMenu *m_formLayoutMenu; +}; + +// Empty task menu for spacers. +class SpacerTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit SpacerTaskMenu(Spacer *bar, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +}; + +typedef qdesigner_internal::ExtensionFactory<QDesignerTaskMenuExtension, QLayoutWidget, LayoutWidgetTaskMenu> LayoutWidgetTaskMenuFactory; +typedef qdesigner_internal::ExtensionFactory<QDesignerTaskMenuExtension, Spacer, SpacerTaskMenu> SpacerTaskMenuFactory; + +QT_END_NAMESPACE + +#endif // LAYOUTTASKMENU_H diff --git a/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp b/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp new file mode 100644 index 0000000..baf4785 --- /dev/null +++ b/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::LineEditTaskMenu +*/ + +#include "lineedit_taskmenu.h" +#include "inplace_editor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- LineEditTaskMenuInlineEditor +class LineEditTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LineEditTaskMenuInlineEditor(QLineEdit *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LineEditTaskMenuInlineEditor::LineEditTaskMenuInlineEditor(QLineEdit *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationSingleLine, QLatin1String("text"), parent) +{ +} + +QRect LineEditTaskMenuInlineEditor::editRectangle() const +{ + QStyleOption opt; + opt.init(widget()); + return opt.rect; +} + +// --------------- LineEditTaskMenu +LineEditTaskMenu::LineEditTaskMenu(QLineEdit *lineEdit, QObject *parent) : + QDesignerTaskMenu(lineEdit, parent), + m_editTextAction(new QAction(tr("Change text..."), this)) +{ + TaskMenuInlineEditor *editor = new LineEditTaskMenuInlineEditor(lineEdit, this); + connect(m_editTextAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QAction *LineEditTaskMenu::preferredEditAction() const +{ + return m_editTextAction; +} + +QList<QAction*> LineEditTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/lineedit_taskmenu.h b/tools/designer/src/components/taskmenu/lineedit_taskmenu.h new file mode 100644 index 0000000..f37fad8 --- /dev/null +++ b/tools/designer/src/components/taskmenu/lineedit_taskmenu.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LINEEDIT_TASKMENU_H +#define LINEEDIT_TASKMENU_H + +#include <QtGui/QLineEdit> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class LineEditTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit LineEditTaskMenu(QLineEdit *button, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QList<QAction*> m_taskActions; + QAction *m_editTextAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QLineEdit, LineEditTaskMenu> LineEditTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LINEEDIT_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp new file mode 100644 index 0000000..1a9ba36 --- /dev/null +++ b/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ListWidgetTaskMenu +*/ + +#include "listwidget_taskmenu.h" +#include "listwidgeteditor.h" +#include "qdesigner_utils_p.h" +#include <qdesigner_command_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QLineEdit> +#include <QtGui/QStyleOption> + +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ListWidgetTaskMenu::ListWidgetTaskMenu(QListWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_listWidget(button) +{ + m_editItemsAction = new QAction(this); + m_editItemsAction->setText(tr("Edit Items...")); + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +ListWidgetTaskMenu::~ListWidgetTaskMenu() +{ +} + +QAction *ListWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList<QAction*> ListWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void ListWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_listWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_listWidget != 0); + + ListWidgetEditor dlg(m_formWindow, m_listWidget->window()); + ListContents oldItems = dlg.fillContentsFromListWidget(m_listWidget); + if (dlg.exec() == QDialog::Accepted) { + ListContents items = dlg.contents(); + if (items != oldItems) { + ChangeListContentsCommand *cmd = new ChangeListContentsCommand(m_formWindow); + cmd->init(m_listWidget, oldItems, items); + cmd->setText(tr("Change List Contents")); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void ListWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/listwidget_taskmenu.h b/tools/designer/src/components/taskmenu/listwidget_taskmenu.h new file mode 100644 index 0000000..6f730a2 --- /dev/null +++ b/tools/designer/src/components/taskmenu/listwidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LISTWIDGET_TASKMENU_H +#define LISTWIDGET_TASKMENU_H + +#include <QtGui/QListWidget> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ListWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ListWidgetTaskMenu(QListWidget *button, QObject *parent = 0); + virtual ~ListWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QListWidget *m_listWidget; + QPointer<QDesignerFormWindowInterface> m_formWindow; + QPointer<QLineEdit> m_editor; + mutable QList<QAction*> m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QListWidget, ListWidgetTaskMenu> ListWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LISTWIDGET_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/listwidgeteditor.cpp b/tools/designer/src/components/taskmenu/listwidgeteditor.cpp new file mode 100644 index 0000000..2a8de52 --- /dev/null +++ b/tools/designer/src/components/taskmenu/listwidgeteditor.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ListWidgetEditor +*/ + +#include "listwidgeteditor.h" +#include <designerpropertymanager.h> +#include <abstractformbuilder.h> + +#include <QtDesigner/private/abstractsettings_p.h> +#include <QtDesigner/QDesignerFormEditorInterface> + +#include <QtGui/QComboBox> +#include <QtGui/QGroupBox> +#include <QtGui/QDialogButtonBox> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ListWidgetEditor::ListWidgetEditor(QDesignerFormWindowInterface *form, + QWidget *parent) + : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QDialogButtonBox *buttonBox = new QDialogButtonBox; + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); + + m_itemsEditor = new ItemListEditor(form, 0); + m_itemsEditor->layout()->setMargin(0); + m_itemsEditor->setNewItemText(tr("New Item")); + + QFrame *sep = new QFrame; + sep->setFrameStyle(QFrame::HLine | QFrame::Sunken); + + QBoxLayout *box = new QVBoxLayout(this); + box->addWidget(m_itemsEditor); + box->addWidget(sep); + box->addWidget(buttonBox); + + // Numbers copied from itemlisteditor.ui + // (Automatic resizing doesn't work because ui has parent). + resize(550, 360); +} + +static AbstractItemEditor::PropertyDefinition listBoxPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +ListContents ListWidgetEditor::fillContentsFromListWidget(QListWidget *listWidget) +{ + setWindowTitle(tr("Edit List Widget")); + + ListContents retVal; + retVal.createFromListWidget(listWidget, false); + retVal.applyToListWidget(m_itemsEditor->listWidget(), m_itemsEditor->iconCache(), true); + + m_itemsEditor->setupEditor(listWidget, listBoxPropList); + + return retVal; +} + +static AbstractItemEditor::PropertyDefinition comboBoxPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { 0, 0, 0, 0 } +}; + +ListContents ListWidgetEditor::fillContentsFromComboBox(QComboBox *comboBox) +{ + setWindowTitle(tr("Edit Combobox")); + + ListContents retVal; + retVal.createFromComboBox(comboBox); + retVal.applyToListWidget(m_itemsEditor->listWidget(), m_itemsEditor->iconCache(), true); + + m_itemsEditor->setupEditor(comboBox, comboBoxPropList); + + return retVal; +} + +ListContents ListWidgetEditor::contents() const +{ + ListContents retVal; + retVal.createFromListWidget(m_itemsEditor->listWidget(), true); + return retVal; +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/listwidgeteditor.h b/tools/designer/src/components/taskmenu/listwidgeteditor.h new file mode 100644 index 0000000..c7fcdea --- /dev/null +++ b/tools/designer/src/components/taskmenu/listwidgeteditor.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LISTWIDGETEDITOR_H +#define LISTWIDGETEDITOR_H + +#include "itemlisteditor.h" +#include <qdesigner_command_p.h> + +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QListWidget; +class QComboBox; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ListWidgetEditor: public QDialog +{ + Q_OBJECT + +public: + ListWidgetEditor(QDesignerFormWindowInterface *form, + QWidget *parent); + + ListContents fillContentsFromListWidget(QListWidget *listWidget); + ListContents fillContentsFromComboBox(QComboBox *comboBox); + ListContents contents() const; + +private: + ItemListEditor *m_itemsEditor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LISTWIDGETEDITOR_H diff --git a/tools/designer/src/components/taskmenu/menutaskmenu.cpp b/tools/designer/src/components/taskmenu/menutaskmenu.cpp new file mode 100644 index 0000000..52320ac --- /dev/null +++ b/tools/designer/src/components/taskmenu/menutaskmenu.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::MenuTaskMenu +*/ + +#include "menutaskmenu.h" + +#include <promotiontaskmenu_p.h> + +#include <QtGui/QAction> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + // ------------ MenuTaskMenu + MenuTaskMenu::MenuTaskMenu(QDesignerMenu *menu, QObject *parent) : + QObject(parent), + m_menu(menu), + m_removeAction(new QAction(tr("Remove"), this)), + m_promotionTaskMenu(new PromotionTaskMenu(menu, PromotionTaskMenu::ModeSingleWidget, this)) + { + connect(m_removeAction, SIGNAL(triggered()), this, SLOT(removeMenu())); + } + + QAction *MenuTaskMenu::preferredEditAction() const + { + return 0; + } + + QList<QAction*> MenuTaskMenu::taskActions() const + { + QList<QAction*> rc; + rc.push_back(m_removeAction); + m_promotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator, rc); + return rc; + } + + void MenuTaskMenu::removeMenu() + { + // Are we on a menu bar or on a menu? + QWidget *pw = m_menu->parentWidget(); + if (QDesignerMenuBar *mb = qobject_cast<QDesignerMenuBar *>(pw)) { + mb->deleteMenuAction(m_menu->menuAction()); + return; + } + if (QDesignerMenu *m = qobject_cast<QDesignerMenu *>(pw)) { + m->deleteAction(m_menu->menuAction()); + } + } + + // ------------- MenuBarTaskMenu + MenuBarTaskMenu::MenuBarTaskMenu(QDesignerMenuBar *bar, QObject *parent) : + QObject(parent), + m_bar(bar) + { + } + + QAction *MenuBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList<QAction*> MenuBarTaskMenu::taskActions() const + { + return m_bar->contextMenuActions(); + } +} + +QT_END_NAMESPACE + diff --git a/tools/designer/src/components/taskmenu/menutaskmenu.h b/tools/designer/src/components/taskmenu/menutaskmenu.h new file mode 100644 index 0000000..98ae3e1 --- /dev/null +++ b/tools/designer/src/components/taskmenu/menutaskmenu.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MENUTASKMENU_H +#define MENUTASKMENU_H + +#include <QtDesigner/QDesignerTaskMenuExtension> + +#include <qdesigner_menu_p.h> +#include <qdesigner_menubar_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + class PromotionTaskMenu; + +// The QMenu task menu provides promotion and a remove option. The actual +// menu context options are not forwarded since they make only sense +// when a menu is being edited/visible. + +class MenuTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit MenuTaskMenu(QDesignerMenu *menu, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void removeMenu(); + +private: + QDesignerMenu *m_menu; + QAction *m_removeAction; + PromotionTaskMenu *m_promotionTaskMenu; +}; + +// The QMenuBar task menu forwards the actions of QDesignerMenuBar, +// making them available in the object inspector. + +class MenuBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit MenuBarTaskMenu(QDesignerMenuBar *bar, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QDesignerMenuBar *m_bar; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QDesignerMenu, MenuTaskMenu> MenuTaskMenuFactory; +typedef ExtensionFactory<QDesignerTaskMenuExtension, QDesignerMenuBar, MenuBarTaskMenu> MenuBarTaskMenuFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // MENUTASKMENU_H diff --git a/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp new file mode 100644 index 0000000..5ef1f9c --- /dev/null +++ b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TableWidgetTaskMenu +*/ + +#include "tablewidget_taskmenu.h" +#include "tablewidgeteditor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QTableWidget> +#include <QtGui/QAction> +#include <QtGui/QLineEdit> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> + +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TableWidgetTaskMenu::TableWidgetTaskMenu(QTableWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_tableWidget(button), + m_editItemsAction(new QAction(tr("Edit Items..."), this)) +{ + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + + +TableWidgetTaskMenu::~TableWidgetTaskMenu() +{ +} + +QAction *TableWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList<QAction*> TableWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TableWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_tableWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_tableWidget != 0); + + TableWidgetEditor dlg(m_formWindow, m_tableWidget->window()); + TableWidgetContents oldCont = dlg.fillContentsFromTableWidget(m_tableWidget); + if (dlg.exec() == QDialog::Accepted) { + TableWidgetContents newCont = dlg.contents(); + if (newCont != oldCont) { + ChangeTableContentsCommand *cmd = new ChangeTableContentsCommand(m_formWindow); + cmd->init(m_tableWidget, oldCont, newCont); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void TableWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/tablewidget_taskmenu.h b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.h new file mode 100644 index 0000000..6ee9c26 --- /dev/null +++ b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABLEWIDGET_TASKMENU_H +#define TABLEWIDGET_TASKMENU_H + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +#include <QtGui/QTableWidget> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TableWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TableWidgetTaskMenu(QTableWidget *button, QObject *parent = 0); + virtual ~TableWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QTableWidget *m_tableWidget; + QPointer<QDesignerFormWindowInterface> m_formWindow; + QPointer<QLineEdit> m_editor; + mutable QList<QAction*> m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QTableWidget, TableWidgetTaskMenu> TableWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABLEWIDGET_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp b/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp new file mode 100644 index 0000000..0863847 --- /dev/null +++ b/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TableWidgetEditor +*/ + +#include "tablewidgeteditor.h" +#include <abstractformbuilder.h> +#include <iconloader_p.h> +#include <qdesigner_command_p.h> +#include "formwindowbase_p.h" +#include "qdesigner_utils_p.h" +#include <designerpropertymanager.h> +#include <qttreepropertybrowser.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerIconCacheInterface> +#include <QtCore/QDir> +#include <QtCore/QQueue> +#include <QtCore/QTextStream> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TableWidgetEditor::TableWidgetEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : AbstractItemEditor(form, parent), m_updatingBrowser(false) +{ + m_columnEditor = new ItemListEditor(form, this); + m_columnEditor->setObjectName(QLatin1String("columnEditor")); + m_columnEditor->setNewItemText(tr("New Column")); + m_rowEditor = new ItemListEditor(form, this); + m_rowEditor->setObjectName(QLatin1String("rowEditor")); + m_rowEditor->setNewItemText(tr("New Row")); + ui.setupUi(this); + + injectPropertyBrowser(ui.itemsTab, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + togglePropertyBrowser(); + + ui.tabWidget->insertTab(0, m_columnEditor, tr("&Columns")); + ui.tabWidget->insertTab(1, m_rowEditor, tr("&Rows")); + ui.tabWidget->setCurrentIndex(0); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +static AbstractItemEditor::PropertyDefinition tableHeaderPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, +// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Color, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition tableItemPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, +// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +TableWidgetContents TableWidgetEditor::fillContentsFromTableWidget(QTableWidget *tableWidget) +{ + TableWidgetContents tblCont; + tblCont.fromTableWidget(tableWidget, false); + tblCont.applyToTableWidget(ui.tableWidget, iconCache(), true); + + tblCont.m_verticalHeader.applyToListWidget(m_rowEditor->listWidget(), iconCache(), true); + m_rowEditor->setupEditor(tableWidget, tableHeaderPropList); + + tblCont.m_horizontalHeader.applyToListWidget(m_columnEditor->listWidget(), iconCache(), true); + m_columnEditor->setupEditor(tableWidget, tableHeaderPropList); + + setupEditor(tableWidget, tableItemPropList); + if (ui.tableWidget->columnCount() > 0 && ui.tableWidget->rowCount() > 0) + ui.tableWidget->setCurrentCell(0, 0); + + updateEditor(); + + return tblCont; +} + +TableWidgetContents TableWidgetEditor::contents() const +{ + TableWidgetContents retVal; + retVal.fromTableWidget(ui.tableWidget, true); + return retVal; +} + +void TableWidgetEditor::setItemData(int role, const QVariant &v) +{ + QTableWidgetItem *item = ui.tableWidget->currentItem(); + BoolBlocker block(m_updatingBrowser); + if (!item) { + item = new QTableWidgetItem; + ui.tableWidget->setItem(ui.tableWidget->currentRow(), ui.tableWidget->currentColumn(), item); + } + QVariant newValue = v; + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.tableWidget->font(); + QFont newFont = qVariantValue<QFont>(newValue).resolve(oldFont); + newValue = qVariantFromValue(newFont); + item->setData(role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + item->setData(role, newValue); +} + +QVariant TableWidgetEditor::getItemData(int role) const +{ + QTableWidgetItem *item = ui.tableWidget->currentItem(); + if (!item) + return QVariant(); + return item->data(role); +} + +void TableWidgetEditor::on_tableWidget_currentCellChanged(int currentRow, int currentCol, int, int /* XXX remove me */) +{ + m_rowEditor->setCurrentIndex(currentRow); + m_columnEditor->setCurrentIndex(currentCol); + updateBrowser(); +} + +void TableWidgetEditor::on_tableWidget_itemChanged(QTableWidgetItem *item) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qVariantValue<PropertySheetStringValue>(item->data(Qt::DisplayPropertyRole)); + val.setValue(item->text()); + BoolBlocker block(m_updatingBrowser); + item->setData(Qt::DisplayPropertyRole, qVariantFromValue(val)); + + updateBrowser(); +} + +void TableWidgetEditor::on_columnEditor_indexChanged(int col) +{ + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), col); +} + +void TableWidgetEditor::on_columnEditor_itemChanged(int idx, int role, const QVariant &v) +{ + ui.tableWidget->horizontalHeaderItem(idx)->setData(role, v); +} + +void TableWidgetEditor::on_rowEditor_indexChanged(int col) +{ + ui.tableWidget->setCurrentCell(col, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::on_rowEditor_itemChanged(int idx, int role, const QVariant &v) +{ + ui.tableWidget->verticalHeaderItem(idx)->setData(role, v); +} + +void TableWidgetEditor::togglePropertyBrowser() +{ + // Always hide in case parent widget is not visible -> on startup + const bool isVisible = + !this->isVisible() ? true : m_propertyBrowser->isVisible(); + if (isVisible) + ui.showPropertiesButton->setText(tr("Properties &<<")); + else + ui.showPropertiesButton->setText(tr("Properties &>>")); + m_propertyBrowser->setVisible(!isVisible); +} + +void TableWidgetEditor::updateEditor() +{ + const bool wasEnabled = ui.tabWidget->isTabEnabled(2); + const bool isEnabled = ui.tableWidget->columnCount() && ui.tableWidget->rowCount(); + ui.tabWidget->setTabEnabled(2, isEnabled); + if (!wasEnabled && isEnabled) + ui.tableWidget->setCurrentCell(0, 0); + + QMetaObject::invokeMethod(ui.tableWidget, "updateGeometries"); + ui.tableWidget->viewport()->update(); +} + +void TableWidgetEditor::moveColumnsLeft(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(toColumn); + for (int i = toColumn; i > fromColumn; i--) { + ui.tableWidget->setHorizontalHeaderItem(i, + ui.tableWidget->takeHorizontalHeaderItem(i - 1)); + } + ui.tableWidget->setHorizontalHeaderItem(fromColumn, lastItem); + + for (int i = 0; i < ui.tableWidget->rowCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(i, toColumn); + for (int j = toColumn; j > fromColumn; j--) + ui.tableWidget->setItem(i, j, ui.tableWidget->takeItem(i, j - 1)); + ui.tableWidget->setItem(i, fromColumn, lastItem); + } +} + +void TableWidgetEditor::moveColumnsRight(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(fromColumn); + for (int i = fromColumn; i < toColumn; i++) { + ui.tableWidget->setHorizontalHeaderItem(i, + ui.tableWidget->takeHorizontalHeaderItem(i + 1)); + } + ui.tableWidget->setHorizontalHeaderItem(toColumn, lastItem); + + for (int i = 0; i < ui.tableWidget->rowCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(i, fromColumn); + for (int j = fromColumn; j < toColumn; j++) + ui.tableWidget->setItem(i, j, ui.tableWidget->takeItem(i, j + 1)); + ui.tableWidget->setItem(i, toColumn, lastItem); + } +} + +void TableWidgetEditor::moveRowsDown(int fromRow, int toRow) +{ + if (fromRow >= toRow) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(toRow); + for (int i = toRow; i > fromRow; i--) { + ui.tableWidget->setVerticalHeaderItem(i, + ui.tableWidget->takeVerticalHeaderItem(i - 1)); + } + ui.tableWidget->setVerticalHeaderItem(fromRow, lastItem); + + for (int i = 0; i < ui.tableWidget->columnCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(toRow, i); + for (int j = toRow; j > fromRow; j--) + ui.tableWidget->setItem(j, i, ui.tableWidget->takeItem(j - 1, i)); + ui.tableWidget->setItem(fromRow, i, lastItem); + } +} + +void TableWidgetEditor::moveRowsUp(int fromRow, int toRow) +{ + if (fromRow >= toRow) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(fromRow); + for (int i = fromRow; i < toRow; i++) { + ui.tableWidget->setVerticalHeaderItem(i, + ui.tableWidget->takeVerticalHeaderItem(i + 1)); + } + ui.tableWidget->setVerticalHeaderItem(toRow, lastItem); + + for (int i = 0; i < ui.tableWidget->columnCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(fromRow, i); + for (int j = fromRow; j < toRow; j++) + ui.tableWidget->setItem(j, i, ui.tableWidget->takeItem(j + 1, i)); + ui.tableWidget->setItem(toRow, i, lastItem); + } +} + +void TableWidgetEditor::on_columnEditor_itemInserted(int idx) +{ + const int columnCount = ui.tableWidget->columnCount(); + ui.tableWidget->setColumnCount(columnCount + 1); + + QTableWidgetItem *newItem = new QTableWidgetItem(m_columnEditor->newItemText()); + newItem->setData(Qt::DisplayPropertyRole, qVariantFromValue(PropertySheetStringValue(m_columnEditor->newItemText()))); + ui.tableWidget->setHorizontalHeaderItem(columnCount, newItem); + + moveColumnsLeft(idx, columnCount); + + int row = ui.tableWidget->currentRow(); + if (row >= 0) + ui.tableWidget->setCurrentCell(row, idx); + + updateEditor(); +} + +void TableWidgetEditor::on_columnEditor_itemDeleted(int idx) +{ + const int columnCount = ui.tableWidget->columnCount(); + + moveColumnsRight(idx, columnCount - 1); + ui.tableWidget->setColumnCount(columnCount - 1); + + updateEditor(); +} + +void TableWidgetEditor::on_columnEditor_itemMovedUp(int idx) +{ + moveColumnsRight(idx - 1, idx); + + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), idx - 1); +} + +void TableWidgetEditor::on_columnEditor_itemMovedDown(int idx) +{ + moveColumnsLeft(idx, idx + 1); + + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), idx + 1); +} + +void TableWidgetEditor::on_rowEditor_itemInserted(int idx) +{ + const int rowCount = ui.tableWidget->rowCount(); + ui.tableWidget->setRowCount(rowCount + 1); + + QTableWidgetItem *newItem = new QTableWidgetItem(m_rowEditor->newItemText()); + newItem->setData(Qt::DisplayPropertyRole, qVariantFromValue(PropertySheetStringValue(m_rowEditor->newItemText()))); + ui.tableWidget->setVerticalHeaderItem(rowCount, newItem); + + moveRowsDown(idx, rowCount); + + int col = ui.tableWidget->currentColumn(); + if (col >= 0) + ui.tableWidget->setCurrentCell(idx, col); + + updateEditor(); +} + +void TableWidgetEditor::on_rowEditor_itemDeleted(int idx) +{ + const int rowCount = ui.tableWidget->rowCount(); + + moveRowsUp(idx, rowCount - 1); + ui.tableWidget->setRowCount(rowCount - 1); + + updateEditor(); +} + +void TableWidgetEditor::on_rowEditor_itemMovedUp(int idx) +{ + moveRowsUp(idx - 1, idx); + + ui.tableWidget->setCurrentCell(idx - 1, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::on_rowEditor_itemMovedDown(int idx) +{ + moveRowsDown(idx, idx + 1); + + ui.tableWidget->setCurrentCell(idx + 1, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.tableWidget); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/tablewidgeteditor.h b/tools/designer/src/components/taskmenu/tablewidgeteditor.h new file mode 100644 index 0000000..a4f0b52 --- /dev/null +++ b/tools/designer/src/components/taskmenu/tablewidgeteditor.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABLEWIDGETEDITOR_H +#define TABLEWIDGETEDITOR_H + +#include "ui_tablewidgeteditor.h" + +#include "listwidgeteditor.h" + +QT_BEGIN_NAMESPACE + +class QTableWidget; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class FormWindowBase; +class PropertySheetIconValue; + +class TableWidgetEditor: public AbstractItemEditor +{ + Q_OBJECT +public: + TableWidgetEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + TableWidgetContents fillContentsFromTableWidget(QTableWidget *tableWidget); + TableWidgetContents contents() const; + +private slots: + + void on_tableWidget_currentCellChanged(int currentRow, int currnetCol, int, int); + void on_tableWidget_itemChanged(QTableWidgetItem *item); + + void on_columnEditor_indexChanged(int idx); + void on_columnEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_columnEditor_itemInserted(int idx); + void on_columnEditor_itemDeleted(int idx); + void on_columnEditor_itemMovedUp(int idx); + void on_columnEditor_itemMovedDown(int idx); + + void on_rowEditor_indexChanged(int idx); + void on_rowEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_rowEditor_itemInserted(int idx); + void on_rowEditor_itemDeleted(int idx); + void on_rowEditor_itemMovedUp(int idx); + void on_rowEditor_itemMovedDown(int idx); + + void togglePropertyBrowser(); + + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + +private: + void updateEditor(); + void moveColumnsLeft(int fromColumn, int toColumn); + void moveColumnsRight(int fromColumn, int toColumn); + void moveRowsUp(int fromRow, int toRow); + void moveRowsDown(int fromRow, int toRow); + + Ui::TableWidgetEditor ui; + ItemListEditor *m_rowEditor; + ItemListEditor *m_columnEditor; + bool m_updatingBrowser; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABLEWIDGETEDITOR_H diff --git a/tools/designer/src/components/taskmenu/tablewidgeteditor.ui b/tools/designer/src/components/taskmenu/tablewidgeteditor.ui new file mode 100644 index 0000000..be59fd2 --- /dev/null +++ b/tools/designer/src/components/taskmenu/tablewidgeteditor.ui @@ -0,0 +1,157 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::TableWidgetEditor</class> + <widget class="QDialog" name="qdesigner_internal::TableWidgetEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>550</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle" > + <string>Edit Table Widget</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QTabWidget" name="tabWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="itemsTab" > + <attribute name="title" > + <string>&Items</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QWidget" native="1" name="widget" > + <layout class="QVBoxLayout" name="verticalLayout_3" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QTableWidget" name="tableWidget" > + <property name="toolTip" > + <string>Table Items</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="buttonsLayout" > + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="showPropertiesButton" > + <property name="text" > + <string>Properties &>></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </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>qdesigner_internal::TableWidgetEditor</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>431</x> + <y>351</y> + </hint> + <hint type="destinationlabel" > + <x>373</x> + <y>362</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>qdesigner_internal::TableWidgetEditor</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>547</x> + <y>354</y> + </hint> + <hint type="destinationlabel" > + <x>562</x> + <y>362</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/taskmenu/taskmenu.pri b/tools/designer/src/components/taskmenu/taskmenu.pri new file mode 100644 index 0000000..066b929 --- /dev/null +++ b/tools/designer/src/components/taskmenu/taskmenu.pri @@ -0,0 +1,50 @@ +INCLUDEPATH += $$PWD \ + ../propertyeditor \ + $$QT_BUILD_TREE/tools/designer/src/components/taskmenu \ + $$QT_SOURCE_TREE/tools/shared/qtpropertybrowser + +FORMS += $$PWD/itemlisteditor.ui \ + $$PWD/treewidgeteditor.ui \ + $$PWD/tablewidgeteditor.ui + +HEADERS += $$PWD/button_taskmenu.h \ + $$PWD/groupbox_taskmenu.h \ + $$PWD/label_taskmenu.h \ + $$PWD/lineedit_taskmenu.h \ + $$PWD/listwidget_taskmenu.h \ + $$PWD/treewidget_taskmenu.h \ + $$PWD/tablewidget_taskmenu.h \ + $$PWD/combobox_taskmenu.h \ + $$PWD/textedit_taskmenu.h \ + $$PWD/toolbar_taskmenu.h \ + $$PWD/containerwidget_taskmenu.h \ + $$PWD/inplace_editor.h \ + $$PWD/taskmenu_component.h \ + $$PWD/itemlisteditor.h \ + $$PWD/listwidgeteditor.h \ + $$PWD/treewidgeteditor.h \ + $$PWD/tablewidgeteditor.h \ + $$PWD/inplace_widget_helper.h \ + $$PWD/menutaskmenu.h \ + $$PWD/layouttaskmenu.h + +SOURCES += $$PWD/button_taskmenu.cpp \ + $$PWD/groupbox_taskmenu.cpp \ + $$PWD/label_taskmenu.cpp \ + $$PWD/lineedit_taskmenu.cpp \ + $$PWD/listwidget_taskmenu.cpp \ + $$PWD/treewidget_taskmenu.cpp \ + $$PWD/tablewidget_taskmenu.cpp \ + $$PWD/combobox_taskmenu.cpp \ + $$PWD/textedit_taskmenu.cpp \ + $$PWD/toolbar_taskmenu.cpp \ + $$PWD/containerwidget_taskmenu.cpp \ + $$PWD/inplace_editor.cpp \ + $$PWD/taskmenu_component.cpp \ + $$PWD/itemlisteditor.cpp \ + $$PWD/listwidgeteditor.cpp \ + $$PWD/treewidgeteditor.cpp \ + $$PWD/tablewidgeteditor.cpp \ + $$PWD/inplace_widget_helper.cpp \ + $$PWD/menutaskmenu.cpp \ + $$PWD/layouttaskmenu.cpp diff --git a/tools/designer/src/components/taskmenu/taskmenu_component.cpp b/tools/designer/src/components/taskmenu/taskmenu_component.cpp new file mode 100644 index 0000000..629fc8a --- /dev/null +++ b/tools/designer/src/components/taskmenu/taskmenu_component.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "taskmenu_component.h" +#include "button_taskmenu.h" +#include "groupbox_taskmenu.h" +#include "label_taskmenu.h" +#include "lineedit_taskmenu.h" +#include "listwidget_taskmenu.h" +#include "treewidget_taskmenu.h" +#include "tablewidget_taskmenu.h" +#include "containerwidget_taskmenu.h" +#include "combobox_taskmenu.h" +#include "textedit_taskmenu.h" +#include "menutaskmenu.h" +#include "toolbar_taskmenu.h" +#include "layouttaskmenu.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QExtensionManager> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TaskMenuComponent::TaskMenuComponent(QDesignerFormEditorInterface *core, QObject *parent) + : QObject(parent), + m_core(core) +{ + Q_ASSERT(m_core != 0); + + QExtensionManager *mgr = core->extensionManager(); + const QString taskMenuId = QLatin1String("QDesignerInternalTaskMenuExtension"); + + ButtonTaskMenuFactory::registerExtension(mgr, taskMenuId); + CommandLinkButtonTaskMenuFactory::registerExtension(mgr, taskMenuId); // Order! + ButtonGroupTaskMenuFactory::registerExtension(mgr, taskMenuId); + + GroupBoxTaskMenuFactory::registerExtension(mgr, taskMenuId); + LabelTaskMenuFactory::registerExtension(mgr, taskMenuId); + LineEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + ListWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TreeWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TableWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TextEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + PlainTextEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + MenuTaskMenuFactory::registerExtension(mgr, taskMenuId); + MenuBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + ToolBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + StatusBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + LayoutWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + SpacerTaskMenuFactory::registerExtension(mgr, taskMenuId); + + mgr->registerExtensions(new ContainerWidgetTaskMenuFactory(core, mgr), taskMenuId); + mgr->registerExtensions(new ComboBoxTaskMenuFactory(taskMenuId, mgr), taskMenuId); +} + +TaskMenuComponent::~TaskMenuComponent() +{ +} + +QDesignerFormEditorInterface *TaskMenuComponent::core() const +{ + return m_core; + +} +QT_END_NAMESPACE + diff --git a/tools/designer/src/components/taskmenu/taskmenu_component.h b/tools/designer/src/components/taskmenu/taskmenu_component.h new file mode 100644 index 0000000..56f3eaf --- /dev/null +++ b/tools/designer/src/components/taskmenu/taskmenu_component.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TASKMENU_COMPONENT_H +#define TASKMENU_COMPONENT_H + +#include "taskmenu_global.h" +#include <QtDesigner/taskmenu.h> + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QT_TASKMENU_EXPORT TaskMenuComponent: public QObject +{ + Q_OBJECT +public: + explicit TaskMenuComponent(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~TaskMenuComponent(); + + QDesignerFormEditorInterface *core() const; + +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TASKMENU_COMPONENT_H diff --git a/tools/designer/src/components/taskmenu/taskmenu_global.h b/tools/designer/src/components/taskmenu/taskmenu_global.h new file mode 100644 index 0000000..418c849 --- /dev/null +++ b/tools/designer/src/components/taskmenu/taskmenu_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TASKMENU_GLOBAL_H +#define TASKMENU_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_TASKMENU_LIBRARY +# define QT_TASKMENU_EXPORT +#else +# define QT_TASKMENU_EXPORT +#endif +#else +#define QT_TASKMENU_EXPORT +#endif + +#endif // TASKMENU_GLOBAL_H diff --git a/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp b/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp new file mode 100644 index 0000000..feaec2c --- /dev/null +++ b/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TextEditTaskMenu +*/ + +#include "textedit_taskmenu.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtCore/QEvent> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +TextEditTaskMenu::TextEditTaskMenu(QTextEdit *textEdit, QObject *parent) : + QDesignerTaskMenu(textEdit, parent), + m_format(Qt::RichText), + m_property(QLatin1String("html")), + m_windowTitle(tr("Edit HTML")), + m_editTextAction(new QAction(tr("Change HTML..."), this)) +{ + initialize(); +} + +TextEditTaskMenu::TextEditTaskMenu(QPlainTextEdit *textEdit, QObject *parent) : + QDesignerTaskMenu(textEdit, parent), + m_format(Qt::PlainText), + m_property(QLatin1String("plainText")), + m_windowTitle(tr("Edit Text")), + m_editTextAction(new QAction(tr("Change Plain Text..."), this)) +{ + initialize(); +} + + +void TextEditTaskMenu::initialize() +{ + connect(m_editTextAction, SIGNAL(triggered()), this, SLOT(editText())); + m_taskActions.append(m_editTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +TextEditTaskMenu::~TextEditTaskMenu() +{ +} + +QAction *TextEditTaskMenu::preferredEditAction() const +{ + return m_editTextAction; +} + +QList<QAction*> TextEditTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TextEditTaskMenu::editText() +{ + changeTextProperty(m_property, m_windowTitle, MultiSelectionMode, m_format); +} + +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/textedit_taskmenu.h b/tools/designer/src/components/taskmenu/textedit_taskmenu.h new file mode 100644 index 0000000..939e3ec --- /dev/null +++ b/tools/designer/src/components/taskmenu/textedit_taskmenu.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTEDIT_TASKMENU_H +#define TEXTEDIT_TASKMENU_H + +#include <QtGui/QTextEdit> +#include <QtGui/QPlainTextEdit> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TextEditTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TextEditTaskMenu(QTextEdit *button, QObject *parent = 0); + explicit TextEditTaskMenu(QPlainTextEdit *button, QObject *parent = 0); + + virtual ~TextEditTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editText(); + +private: + void initialize(); + + const Qt::TextFormat m_format; + const QString m_property; + const QString m_windowTitle; + + mutable QList<QAction*> m_taskActions; + QAction *m_editTextAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QTextEdit, TextEditTaskMenu> TextEditTaskMenuFactory; +typedef ExtensionFactory<QDesignerTaskMenuExtension, QPlainTextEdit, TextEditTaskMenu> PlainTextEditTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TEXTEDIT_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp b/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp new file mode 100644 index 0000000..a15cd8a --- /dev/null +++ b/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ToolBarTaskMenu +*/ + +#include "toolbar_taskmenu.h" +#include "qdesigner_toolbar_p.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <promotiontaskmenu_p.h> +#include <qdesigner_command_p.h> + +#include <QtGui/QAction> +#include <QtGui/QUndoStack> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + // ------------ ToolBarTaskMenu + ToolBarTaskMenu::ToolBarTaskMenu(QToolBar *tb, QObject *parent) : + QObject(parent), + m_toolBar(tb) + { + } + + QAction *ToolBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList<QAction*> ToolBarTaskMenu::taskActions() const + { + if (ToolBarEventFilter *ef = ToolBarEventFilter::eventFilterOf(m_toolBar)) + return ef->contextMenuActions(); + return QList<QAction*>(); + } + + // ------------ StatusBarTaskMenu + StatusBarTaskMenu::StatusBarTaskMenu(QStatusBar *sb, QObject *parent) : + QObject(parent), + m_statusBar(sb), + m_removeAction(new QAction(tr("Remove"), this)), + m_promotionTaskMenu(new PromotionTaskMenu(sb, PromotionTaskMenu::ModeSingleWidget, this)) + { + connect(m_removeAction, SIGNAL(triggered()), this, SLOT(removeStatusBar())); + } + + QAction *StatusBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList<QAction*> StatusBarTaskMenu::taskActions() const + { + QList<QAction*> rc; + rc.push_back(m_removeAction); + m_promotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator, rc); + return rc; + } + + void StatusBarTaskMenu::removeStatusBar() + { + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_statusBar)) { + DeleteStatusBarCommand *cmd = new DeleteStatusBarCommand(fw); + cmd->init(m_statusBar); + fw->commandHistory()->push(cmd); + } + } +} + +QT_END_NAMESPACE + diff --git a/tools/designer/src/components/taskmenu/toolbar_taskmenu.h b/tools/designer/src/components/taskmenu/toolbar_taskmenu.h new file mode 100644 index 0000000..4ae1994 --- /dev/null +++ b/tools/designer/src/components/taskmenu/toolbar_taskmenu.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOOLBAR_TASKMENU_H +#define TOOLBAR_TASKMENU_H + +#include <QtDesigner/QDesignerTaskMenuExtension> + +#include <extensionfactory_p.h> + +#include <QtGui/QToolBar> +#include <QtGui/QStatusBar> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class PromotionTaskMenu; + +// ToolBarTaskMenu forwards the actions of ToolBarEventFilter +class ToolBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit ToolBarTaskMenu(QToolBar *tb, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private: + QToolBar *m_toolBar; +}; + +// StatusBarTaskMenu provides promotion and deletion +class StatusBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit StatusBarTaskMenu(QStatusBar *tb, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void removeStatusBar(); + +private: + QStatusBar *m_statusBar; + QAction *m_removeAction; + PromotionTaskMenu *m_promotionTaskMenu; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QToolBar, ToolBarTaskMenu> ToolBarTaskMenuFactory; +typedef ExtensionFactory<QDesignerTaskMenuExtension, QStatusBar, StatusBarTaskMenu> StatusBarTaskMenuFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TOOLBAR_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp new file mode 100644 index 0000000..b1c8c28 --- /dev/null +++ b/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TreeWidgetTaskMenu +*/ + +#include "treewidget_taskmenu.h" +#include "treewidgeteditor.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtGui/QStyle> +#include <QtGui/QLineEdit> +#include <QtGui/QStyleOption> + +#include <QtCore/QEvent> +#include <QtCore/QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TreeWidgetTaskMenu::TreeWidgetTaskMenu(QTreeWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_treeWidget(button), + m_editItemsAction(new QAction(tr("Edit Items..."), this)) +{ + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + + +TreeWidgetTaskMenu::~TreeWidgetTaskMenu() +{ +} + +QAction *TreeWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList<QAction*> TreeWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TreeWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_treeWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_treeWidget != 0); + + TreeWidgetEditor dlg(m_formWindow, m_treeWidget->window()); + TreeWidgetContents oldCont = dlg.fillContentsFromTreeWidget(m_treeWidget); + if (dlg.exec() == QDialog::Accepted) { + TreeWidgetContents newCont = dlg.contents(); + if (newCont != oldCont) { + ChangeTreeContentsCommand *cmd = new ChangeTreeContentsCommand(m_formWindow); + cmd->init(m_treeWidget, oldCont, newCont); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void TreeWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/treewidget_taskmenu.h b/tools/designer/src/components/taskmenu/treewidget_taskmenu.h new file mode 100644 index 0000000..dac4c20 --- /dev/null +++ b/tools/designer/src/components/taskmenu/treewidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEWIDGET_TASKMENU_H +#define TREEWIDGET_TASKMENU_H + +#include <QtGui/QTreeWidget> +#include <QtCore/QPointer> + +#include <qdesigner_taskmenu_p.h> +#include <extensionfactory_p.h> + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TreeWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TreeWidgetTaskMenu(QTreeWidget *button, QObject *parent = 0); + virtual ~TreeWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList<QAction*> taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QTreeWidget *m_treeWidget; + QPointer<QDesignerFormWindowInterface> m_formWindow; + QPointer<QLineEdit> m_editor; + mutable QList<QAction*> m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory<QDesignerTaskMenuExtension, QTreeWidget, TreeWidgetTaskMenu> TreeWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TREEWIDGET_TASKMENU_H diff --git a/tools/designer/src/components/taskmenu/treewidgeteditor.cpp b/tools/designer/src/components/taskmenu/treewidgeteditor.cpp new file mode 100644 index 0000000..faf00f2 --- /dev/null +++ b/tools/designer/src/components/taskmenu/treewidgeteditor.cpp @@ -0,0 +1,607 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::TreeWidgetEditor +*/ + +#include "treewidgeteditor.h" +#include <formwindowbase_p.h> +#include <iconloader_p.h> +#include <qdesigner_command_p.h> +#include <qdesigner_utils_p.h> +#include <abstractformbuilder.h> +#include <designerpropertymanager.h> +#include <qttreepropertybrowser.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerIconCacheInterface> +#include <QtCore/QDir> +#include <QtCore/QQueue> +#include <QtGui/QHeaderView> +#include <QtGui/QTreeWidgetItemIterator> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +TreeWidgetEditor::TreeWidgetEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : AbstractItemEditor(form, parent), m_updatingBrowser(false) +{ + m_columnEditor = new ItemListEditor(form, this); + m_columnEditor->setObjectName(QLatin1String("columnEditor")); + m_columnEditor->setNewItemText(tr("New Column")); + ui.setupUi(this); + + injectPropertyBrowser(ui.itemsTab, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + togglePropertyBrowser(); + + ui.tabWidget->insertTab(0, m_columnEditor, tr("&Columns")); + ui.tabWidget->setCurrentIndex(0); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.newItemButton->setIcon(createIconSet(QString::fromUtf8("plus.png"))); + ui.newSubItemButton->setIcon(createIconSet(QString::fromUtf8("downplus.png"))); + ui.deleteItemButton->setIcon(createIconSet(QString::fromUtf8("minus.png"))); + ui.moveItemUpButton->setIcon(createIconSet(QString::fromUtf8("up.png"))); + ui.moveItemDownButton->setIcon(createIconSet(QString::fromUtf8("down.png"))); + ui.moveItemRightButton->setIcon(createIconSet(QString::fromUtf8("leveldown.png"))); + ui.moveItemLeftButton->setIcon(createIconSet(QString::fromUtf8("levelup.png"))); + + ui.treeWidget->header()->setMovable(false); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +static AbstractItemEditor::PropertyDefinition treeHeaderPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Color, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition treeItemColumnPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition treeItemCommonPropList[] = { + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { 0, 0, 0, 0 } +}; + +QtVariantProperty *TreeWidgetEditor::setupPropertyGroup(const QString &title, PropertyDefinition *propDefs) +{ + setupProperties(propDefs); + QtVariantProperty *groupProp = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), title); + foreach (QtVariantProperty *prop, m_rootProperties) + groupProp->addSubProperty(prop); + m_rootProperties.clear(); + return groupProp; +} + +TreeWidgetContents TreeWidgetEditor::fillContentsFromTreeWidget(QTreeWidget *treeWidget) +{ + TreeWidgetContents treeCont; + treeCont.fromTreeWidget(treeWidget, false); + treeCont.applyToTreeWidget(ui.treeWidget, iconCache(), true); + + treeCont.m_headerItem.applyToListWidget(m_columnEditor->listWidget(), iconCache(), true); + m_columnEditor->setupEditor(treeWidget, treeHeaderPropList); + + QList<QtVariantProperty*> rootProperties; + rootProperties.append(setupPropertyGroup(tr("Per column properties"), treeItemColumnPropList)); + rootProperties.append(setupPropertyGroup(tr("Common properties"), treeItemCommonPropList)); + m_rootProperties = rootProperties; + m_propertyBrowser->setPropertiesWithoutValueMarked(true); + m_propertyBrowser->setRootIsDecorated(false); + setupObject(treeWidget); + + if (ui.treeWidget->topLevelItemCount() > 0) + ui.treeWidget->setCurrentItem(ui.treeWidget->topLevelItem(0)); + + updateEditor(); + + return treeCont; +} + +TreeWidgetContents TreeWidgetEditor::contents() const +{ + TreeWidgetContents retVal; + retVal.fromTreeWidget(ui.treeWidget, true); + return retVal; +} + +void TreeWidgetEditor::setItemData(int role, const QVariant &v) +{ + const int col = (role == ItemFlagsShadowRole) ? 0 : ui.treeWidget->currentColumn(); + QVariant newValue = v; + BoolBlocker block(m_updatingBrowser); + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.treeWidget->font(); + QFont newFont = qVariantValue<QFont>(newValue).resolve(oldFont); + newValue = qVariantFromValue(newFont); + ui.treeWidget->currentItem()->setData(col, role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + ui.treeWidget->currentItem()->setData(col, role, newValue); +} + +QVariant TreeWidgetEditor::getItemData(int role) const +{ + const int col = (role == ItemFlagsShadowRole) ? 0 : ui.treeWidget->currentColumn(); + return ui.treeWidget->currentItem()->data(col, role); +} + +void TreeWidgetEditor::on_newItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + QTreeWidgetItem *newItem = 0; + ui.treeWidget->blockSignals(true); + if (curItem) { + if (curItem->parent()) + newItem = new QTreeWidgetItem(curItem->parent(), curItem); + else + newItem = new QTreeWidgetItem(ui.treeWidget, curItem); + } else + newItem = new QTreeWidgetItem(ui.treeWidget); + const QString newItemText = tr("New Item"); + newItem->setText(0, newItemText); + newItem->setData(0, Qt::DisplayPropertyRole, qVariantFromValue(PropertySheetStringValue(newItemText))); + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(newItem, qMax(ui.treeWidget->currentColumn(), 0)); + updateEditor(); + ui.treeWidget->editItem(newItem, ui.treeWidget->currentColumn()); +} + +void TreeWidgetEditor::on_newSubItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + ui.treeWidget->blockSignals(true); + QTreeWidgetItem *newItem = new QTreeWidgetItem(curItem); + const QString newItemText = tr("New Subitem"); + newItem->setText(0, newItemText); + newItem->setData(0, Qt::DisplayPropertyRole, qVariantFromValue(PropertySheetStringValue(newItemText))); + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(newItem, ui.treeWidget->currentColumn()); + updateEditor(); + ui.treeWidget->editItem(newItem, ui.treeWidget->currentColumn()); +} + +void TreeWidgetEditor::on_deleteItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + QTreeWidgetItem *nextCurrent = 0; + if (curItem->parent()) { + int idx = curItem->parent()->indexOfChild(curItem); + if (idx == curItem->parent()->childCount() - 1) + idx--; + else + idx++; + if (idx < 0) + nextCurrent = curItem->parent(); + else + nextCurrent = curItem->parent()->child(idx); + } else { + int idx = ui.treeWidget->indexOfTopLevelItem(curItem); + if (idx == ui.treeWidget->topLevelItemCount() - 1) + idx--; + else + idx++; + if (idx >= 0) + nextCurrent = ui.treeWidget->topLevelItem(idx); + } + closeEditors(); + ui.treeWidget->blockSignals(true); + delete curItem; + ui.treeWidget->blockSignals(false); + + if (nextCurrent) + ui.treeWidget->setCurrentItem(nextCurrent, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemUpButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx; + if (curItem->parent()) + idx = curItem->parent()->indexOfChild(curItem); + else + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + if (idx == 0) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent(); + takenItem = parentItem->takeChild(idx); + parentItem->insertChild(idx - 1, takenItem); + } else { + takenItem = ui.treeWidget->takeTopLevelItem(idx); + ui.treeWidget->insertTopLevelItem(idx - 1, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemDownButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx, idxCount; + if (curItem->parent()) { + idx = curItem->parent()->indexOfChild(curItem); + idxCount = curItem->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx == idxCount - 1) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent(); + takenItem = parentItem->takeChild(idx); + parentItem->insertChild(idx + 1, takenItem); + } else { + takenItem = ui.treeWidget->takeTopLevelItem(idx); + ui.treeWidget->insertTopLevelItem(idx + 1, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemLeftButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + QTreeWidgetItem *parentItem = curItem->parent(); + if (!parentItem) + return; + + ui.treeWidget->blockSignals(true); + QTreeWidgetItem *takenItem = parentItem->takeChild(parentItem->indexOfChild(curItem)); + if (parentItem->parent()) { + int idx = parentItem->parent()->indexOfChild(parentItem); + parentItem->parent()->insertChild(idx, takenItem); + } else { + int idx = ui.treeWidget->indexOfTopLevelItem(parentItem); + ui.treeWidget->insertTopLevelItem(idx, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemRightButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx, idxCount; + if (curItem->parent()) { + idx = curItem->parent()->indexOfChild(curItem); + idxCount = curItem->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx == idxCount - 1) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent()->child(idx + 1); + takenItem = curItem->parent()->takeChild(idx); + parentItem->insertChild(0, takenItem); + } else { + QTreeWidgetItem *parentItem = ui.treeWidget->topLevelItem(idx + 1); + takenItem = ui.treeWidget->takeTopLevelItem(idx); + parentItem->insertChild(0, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::togglePropertyBrowser() +{ + // Always hide in case parent widget is not visible -> on startup + const bool isVisible = + !this->isVisible() ? true : m_propertyBrowser->isVisible(); + if (isVisible) + ui.showPropertiesButton->setText(tr("Properties &<<")); + else + ui.showPropertiesButton->setText(tr("Properties &>>")); + + m_propertyBrowser->setVisible(!isVisible); +} + +void TreeWidgetEditor::on_treeWidget_currentItemChanged() +{ + m_columnEditor->setCurrentIndex(ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_treeWidget_itemChanged(QTreeWidgetItem *item, int column) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qVariantValue<PropertySheetStringValue>(item->data(column, Qt::DisplayPropertyRole)); + val.setValue(item->text(column)); + BoolBlocker block(m_updatingBrowser); + item->setData(column, Qt::DisplayPropertyRole, qVariantFromValue(val)); + + updateBrowser(); +} + +void TreeWidgetEditor::on_columnEditor_indexChanged(int idx) +{ + if (QTreeWidgetItem *item = ui.treeWidget->currentItem()) + ui.treeWidget->setCurrentItem(item, idx); +} + +void TreeWidgetEditor::on_columnEditor_itemChanged(int idx, int role, const QVariant &v) +{ + if (role == Qt::DisplayPropertyRole) + ui.treeWidget->headerItem()->setData(idx, Qt::EditRole, qVariantValue<PropertySheetStringValue>(v).value()); + ui.treeWidget->headerItem()->setData(idx, role, v); +} + +void TreeWidgetEditor::updateEditor() +{ + QTreeWidgetItem *current = ui.treeWidget->currentItem(); + + bool itemsEnabled = false; + bool currentItemEnabled = false; + bool moveItemUpEnabled = false; + bool moveItemDownEnabled = false; + bool moveItemRightEnabled = false; + bool moveItemLeftEnabled = false; + + if (ui.treeWidget->columnCount() > 0) { + itemsEnabled = true; + if (current) { + int idx; + int idxCount; + currentItemEnabled = true; + if (current->parent()) { + moveItemLeftEnabled = true; + idx = current->parent()->indexOfChild(current); + idxCount = current->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(current); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx > 0) + moveItemUpEnabled = true; + if (idx < idxCount - 1) { + moveItemDownEnabled = true; + moveItemRightEnabled = true; + } + } + } + ui.tabWidget->setTabEnabled(1, itemsEnabled); + ui.newSubItemButton->setEnabled(currentItemEnabled); + ui.deleteItemButton->setEnabled(currentItemEnabled); + + ui.moveItemUpButton->setEnabled(moveItemUpEnabled); + ui.moveItemDownButton->setEnabled(moveItemDownEnabled); + ui.moveItemRightButton->setEnabled(moveItemRightEnabled); + ui.moveItemLeftButton->setEnabled(moveItemLeftEnabled); + + if (current) + updateBrowser(); + else + m_propertyBrowser->clear(); +} + +void TreeWidgetEditor::moveColumnItems(const PropertyDefinition *propList, + QTreeWidgetItem *item, int fromColumn, int toColumn, int step) +{ + BoolBlocker block(m_updatingBrowser); + + QList<QVariant> saveCol; + for (int j = 0; propList[j].name; j++) + saveCol.append(item->data(toColumn, propList[j].role)); + QVariant editVariant = item->data(toColumn, Qt::EditRole); + QVariant toolTipVariant = item->data(toColumn, Qt::ToolTipRole); + QVariant statusTipVariant = item->data(toColumn, Qt::StatusTipRole); + QVariant whatsThisVariant = item->data(toColumn, Qt::WhatsThisRole); + QVariant decorationVariant = item->data(toColumn, Qt::DecorationRole); + for (int i = toColumn; i != fromColumn; i += step) { + for (int j = 0; propList[j].name; j++) + item->setData(i, propList[j].role, item->data(i + step, propList[j].role)); + item->setData(i, Qt::EditRole, item->data(i + step, Qt::EditRole)); + item->setData(i, Qt::ToolTipRole, item->data(i + step, Qt::ToolTipRole)); + item->setData(i, Qt::StatusTipRole, item->data(i + step, Qt::StatusTipRole)); + item->setData(i, Qt::WhatsThisRole, item->data(i + step, Qt::WhatsThisRole)); + item->setData(i, Qt::DecorationRole, item->data(i + step, Qt::DecorationRole)); + } + for (int j = 0; propList[j].name; j++) + item->setData(fromColumn, propList[j].role, saveCol[j]); + item->setData(fromColumn, Qt::EditRole, editVariant); + item->setData(fromColumn, Qt::ToolTipRole, toolTipVariant); + item->setData(fromColumn, Qt::StatusTipRole, statusTipVariant); + item->setData(fromColumn, Qt::WhatsThisRole, whatsThisVariant); + item->setData(fromColumn, Qt::DecorationRole, decorationVariant); +} + +void TreeWidgetEditor::moveColumns(int fromColumn, int toColumn, int step) +{ + ui.treeWidget->blockSignals(true); + + moveColumnItems(treeHeaderPropList, ui.treeWidget->headerItem(), fromColumn, toColumn, step); + + QQueue<QTreeWidgetItem *> pendingQueue; + for (int i = 0; i < ui.treeWidget->topLevelItemCount(); i++) + pendingQueue.enqueue(ui.treeWidget->topLevelItem(i)); + + while (!pendingQueue.isEmpty()) { + QTreeWidgetItem *item = pendingQueue.dequeue(); + for (int i = 0; i < item->childCount(); i++) + pendingQueue.enqueue(item->child(i)); + + moveColumnItems(treeItemColumnPropList, item, fromColumn, toColumn, step); + } + + ui.treeWidget->blockSignals(false); +} + +void TreeWidgetEditor::moveColumnsLeft(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + moveColumns(fromColumn, toColumn, -1); +} + +void TreeWidgetEditor::moveColumnsRight(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + moveColumns(toColumn, fromColumn, 1); +} + +void TreeWidgetEditor::on_columnEditor_itemInserted(int idx) +{ + int columnCount = ui.treeWidget->columnCount(); + ui.treeWidget->setColumnCount(columnCount + 1); + ui.treeWidget->headerItem()->setText(columnCount, m_columnEditor->newItemText()); + moveColumnsLeft(idx, columnCount); + + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemDeleted(int idx) +{ + closeEditors(); + + int columnCount = ui.treeWidget->columnCount() - 1; + if (!columnCount) + ui.treeWidget->clear(); + else + moveColumnsRight(idx, columnCount); + ui.treeWidget->setColumnCount(columnCount); + + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemMovedUp(int idx) +{ + moveColumnsRight(idx - 1, idx); + + ui.treeWidget->setCurrentItem(ui.treeWidget->currentItem(), idx - 1); + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemMovedDown(int idx) +{ + moveColumnsLeft(idx, idx + 1); + + ui.treeWidget->setCurrentItem(ui.treeWidget->currentItem(), idx + 1); + updateEditor(); +} + +void TreeWidgetEditor::closeEditors() +{ + if (QTreeWidgetItem *cur = ui.treeWidget->currentItem() ) { + const int numCols = cur->columnCount (); + for (int i = 0; i < numCols; i++) + ui.treeWidget->closePersistentEditor (cur, i); + } +} + +void TreeWidgetEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.treeWidget); +} + +} +QT_END_NAMESPACE diff --git a/tools/designer/src/components/taskmenu/treewidgeteditor.h b/tools/designer/src/components/taskmenu/treewidgeteditor.h new file mode 100644 index 0000000..f4abc78 --- /dev/null +++ b/tools/designer/src/components/taskmenu/treewidgeteditor.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEWIDGETEDITOR_H +#define TREEWIDGETEDITOR_H + +#include "ui_treewidgeteditor.h" + +#include "listwidgeteditor.h" + +QT_BEGIN_NAMESPACE + +class QTreeWidget; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class FormWindowBase; +class PropertySheetIconValue; + +class TreeWidgetEditor: public AbstractItemEditor +{ + Q_OBJECT +public: + TreeWidgetEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + TreeWidgetContents fillContentsFromTreeWidget(QTreeWidget *treeWidget); + TreeWidgetContents contents() const; + +private slots: + void on_newItemButton_clicked(); + void on_newSubItemButton_clicked(); + void on_deleteItemButton_clicked(); + void on_moveItemUpButton_clicked(); + void on_moveItemDownButton_clicked(); + void on_moveItemRightButton_clicked(); + void on_moveItemLeftButton_clicked(); + + void on_treeWidget_currentItemChanged(); + void on_treeWidget_itemChanged(QTreeWidgetItem *item, int column); + + void on_columnEditor_indexChanged(int idx); + void on_columnEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_columnEditor_itemInserted(int idx); + void on_columnEditor_itemDeleted(int idx); + void on_columnEditor_itemMovedUp(int idx); + void on_columnEditor_itemMovedDown(int idx); + + void togglePropertyBrowser(); + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + +private: + QtVariantProperty *setupPropertyGroup(const QString &title, PropertyDefinition *propDefs); + void updateEditor(); + void moveColumnItems(const PropertyDefinition *propList, QTreeWidgetItem *item, int fromColumn, int toColumn, int step); + void moveColumns(int fromColumn, int toColumn, int step); + void moveColumnsLeft(int fromColumn, int toColumn); + void moveColumnsRight(int fromColumn, int toColumn); + void closeEditors(); + + Ui::TreeWidgetEditor ui; + ItemListEditor *m_columnEditor; + bool m_updatingBrowser; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TREEWIDGETEDITOR_H diff --git a/tools/designer/src/components/taskmenu/treewidgeteditor.ui b/tools/designer/src/components/taskmenu/treewidgeteditor.ui new file mode 100644 index 0000000..d72b152 --- /dev/null +++ b/tools/designer/src/components/taskmenu/treewidgeteditor.ui @@ -0,0 +1,257 @@ +<ui version="4.0" > + <comment>********************************************************************* +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <class>qdesigner_internal::TreeWidgetEditor</class> + <widget class="QDialog" name="qdesigner_internal::TreeWidgetEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>700</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle" > + <string>Edit Tree Widget</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QTabWidget" name="tabWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="itemsTab" > + <attribute name="title" > + <string>&Items</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <item> + <widget class="QWidget" native="1" name="widget" > + <layout class="QVBoxLayout" name="verticalLayout_2" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QTreeWidget" name="treeWidget" > + <property name="focusPolicy" > + <enum>Qt::WheelFocus</enum> + </property> + <property name="toolTip" > + <string>Tree Items</string> + </property> + <column> + <property name="text" > + <string>1</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="buttonsLayout" > + <item> + <widget class="QToolButton" name="newItemButton" > + <property name="toolTip" > + <string>New Item</string> + </property> + <property name="text" > + <string>&New</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="newSubItemButton" > + <property name="toolTip" > + <string>New Subitem</string> + </property> + <property name="text" > + <string>New &Subitem</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="deleteItemButton" > + <property name="toolTip" > + <string>Delete Item</string> + </property> + <property name="text" > + <string>&Delete</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>28</width> + <height>23</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="moveItemLeftButton" > + <property name="toolTip" > + <string>Move Item Left (before Parent Item)</string> + </property> + <property name="text" > + <string>L</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="moveItemRightButton" > + <property name="toolTip" > + <string>Move Item Right (as a First Subitem of the Next Sibling Item)</string> + </property> + <property name="text" > + <string>R</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="moveItemUpButton" > + <property name="toolTip" > + <string>Move Item Up</string> + </property> + <property name="text" > + <string>U</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="moveItemDownButton" > + <property name="toolTip" > + <string>Move Item Down</string> + </property> + <property name="text" > + <string>D</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="showPropertiesButton" > + <property name="text" > + <string>Properties &>></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </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>qdesigner_internal::TreeWidgetEditor</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>440</x> + <y>335</y> + </hint> + <hint type="destinationlabel" > + <x>373</x> + <y>362</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>qdesigner_internal::TreeWidgetEditor</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>556</x> + <y>335</y> + </hint> + <hint type="destinationlabel" > + <x>562</x> + <y>362</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/widgetbox/widgetbox.cpp b/tools/designer/src/components/widgetbox/widgetbox.cpp new file mode 100644 index 0000000..d8c6aa3 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox.h" +#include "widgetboxtreewidget.h" +#include "widgetbox_dnditem.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <iconloader_p.h> +#include <qdesigner_utils_p.h> +#include <filterwidget_p.h> + +#include <QtGui/QDropEvent> +#include <QtGui/QVBoxLayout> +#include <QtGui/QApplication> +#include <QtGui/QToolBar> +#include <QtGui/QIcon> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +WidgetBox::WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) + : QDesignerWidgetBox(parent, flags), + m_core(core), + m_view(new WidgetBoxTreeWidget(m_core)) +{ + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + // Prevent the filter from grabbing focus since Our view has Qt::NoFocus + FilterWidget *filterWidget = new FilterWidget(0, FilterWidget::LayoutAlignNone); + filterWidget->setRefuseFocus(true); + connect(filterWidget, SIGNAL(filterChanged(QString)), m_view, SLOT(filter(QString))); + l->addWidget(filterWidget); + + // View + connect(m_view, SIGNAL(pressed(QString,QString,QPoint)), + this, SLOT(handleMousePress(QString,QString,QPoint))); + l->addWidget(m_view); + + setAcceptDrops (true); +} + +WidgetBox::~WidgetBox() +{ +} + +QDesignerFormEditorInterface *WidgetBox::core() const +{ + return m_core; +} + +void WidgetBox::handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos) +{ + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + DomUI *ui = xmlToUi(name, xml, true); + if (ui == 0) + return; + QList<QDesignerDnDItemInterface*> item_list; + item_list.append(new WidgetBoxDnDItem(core(), ui, global_mouse_pos)); + m_core->formWindowManager()->dragItems(item_list); +} + +int WidgetBox::categoryCount() const +{ + return m_view->categoryCount(); +} + +QDesignerWidgetBoxInterface::Category WidgetBox::category(int cat_idx) const +{ + return m_view->category(cat_idx); +} + +void WidgetBox::addCategory(const Category &cat) +{ + m_view->addCategory(cat); +} + +void WidgetBox::removeCategory(int cat_idx) +{ + m_view->removeCategory(cat_idx); +} + +int WidgetBox::widgetCount(int cat_idx) const +{ + return m_view->widgetCount(cat_idx); +} + +QDesignerWidgetBoxInterface::Widget WidgetBox::widget(int cat_idx, int wgt_idx) const +{ + return m_view->widget(cat_idx, wgt_idx); +} + +void WidgetBox::addWidget(int cat_idx, const Widget &wgt) +{ + m_view->addWidget(cat_idx, wgt); +} + +void WidgetBox::removeWidget(int cat_idx, int wgt_idx) +{ + m_view->removeWidget(cat_idx, wgt_idx); +} + +void WidgetBox::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, const QPoint&) +{ + m_view->dropWidgets(item_list); +} + +void WidgetBox::setFileName(const QString &file_name) +{ + m_view->setFileName(file_name); +} + +QString WidgetBox::fileName() const +{ + return m_view->fileName(); +} + +bool WidgetBox::load() +{ + return m_view->load(loadMode()); +} + +bool WidgetBox::loadContents(const QString &contents) +{ + return m_view->loadContents(contents); +} + +bool WidgetBox::save() +{ + return m_view->save(); +} + +static const QDesignerMimeData *checkDragEvent(QDropEvent * event, + bool acceptEventsFromWidgetBox) +{ + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(event->mimeData()); + if (!mimeData) { + event->ignore(); + return 0; + } + // If desired, ignore a widget box drag and drop, where widget==0. + if (!acceptEventsFromWidgetBox) { + const bool fromWidgetBox = !mimeData->items().first()->widget(); + if (fromWidgetBox) { + event->ignore(); + return 0; + } + } + + mimeData->acceptEvent(event); + return mimeData; +} + +void WidgetBox::dragEnterEvent (QDragEnterEvent * event) +{ + // We accept event originating from the widget box also here, + // because otherwise Windows will not show the DnD pixmap. + checkDragEvent(event, true); +} + +void WidgetBox::dragMoveEvent(QDragMoveEvent * event) +{ + checkDragEvent(event, true); +} + +void WidgetBox::dropEvent(QDropEvent * event) +{ + const QDesignerMimeData *mimeData = checkDragEvent(event, false); + if (!mimeData) + return; + + dropWidgets(mimeData->items(), event->pos()); + QDesignerMimeData::removeMovedWidgetsFromSourceForm(mimeData->items()); +} + +QIcon WidgetBox::iconForWidget(const QString &className, const QString &category) const +{ + Widget widgetData; + if (!findWidget(this, className, category, &widgetData)) + return QIcon(); + return m_view->iconForWidget(widgetData.iconName()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetbox.h b/tools/designer/src/components/widgetbox/widgetbox.h new file mode 100644 index 0000000..e77c0ed --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_H +#define WIDGETBOX_H + +#include "widgetbox_global.h" +#include <qdesigner_widgetbox_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class WidgetBoxTreeWidget; + +class QT_WIDGETBOX_EXPORT WidgetBox : public QDesignerWidgetBox +{ + Q_OBJECT +public: + explicit WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~WidgetBox(); + + QDesignerFormEditorInterface *core() const; + + virtual int categoryCount() const; + virtual Category category(int cat_idx) const; + virtual void addCategory(const Category &cat); + virtual void removeCategory(int cat_idx); + + virtual int widgetCount(int cat_idx) const; + virtual Widget widget(int cat_idx, int wgt_idx) const; + virtual void addWidget(int cat_idx, const Widget &wgt); + virtual void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, const QPoint &global_mouse_pos); + + virtual void setFileName(const QString &file_name); + virtual QString fileName() const; + virtual bool load(); + virtual bool save(); + + virtual bool loadContents(const QString &contents); + virtual QIcon iconForWidget(const QString &className, const QString &category = QString()) const; + +protected: + virtual void dragEnterEvent (QDragEnterEvent * event); + virtual void dragMoveEvent(QDragMoveEvent * event); + virtual void dropEvent (QDropEvent * event); + +private slots: + void handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos); + +private: + QDesignerFormEditorInterface *m_core; + WidgetBoxTreeWidget *m_view; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_H diff --git a/tools/designer/src/components/widgetbox/widgetbox.pri b/tools/designer/src/components/widgetbox/widgetbox.pri new file mode 100644 index 0000000..dd8ad00 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.pri @@ -0,0 +1,14 @@ + +INCLUDEPATH += $$PWD + +SOURCES += $$PWD/widgetboxcategorylistview.cpp \ + $$PWD/widgetboxtreewidget.cpp \ + $$PWD/widgetbox.cpp \ + $$PWD/widgetbox_dnditem.cpp +HEADERS += $$PWD/widgetboxcategorylistview.h \ + $$PWD/widgetboxtreewidget.h \ + $$PWD/widgetbox.h \ + $$PWD/widgetbox_global.h \ + $$PWD/widgetbox_dnditem.h + +RESOURCES += $$PWD/widgetbox.qrc diff --git a/tools/designer/src/components/widgetbox/widgetbox.qrc b/tools/designer/src/components/widgetbox/widgetbox.qrc new file mode 100644 index 0000000..7ecf78c --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/trolltech/widgetbox"> + <file>widgetbox.xml</file> + </qresource> +</RCC> diff --git a/tools/designer/src/components/widgetbox/widgetbox.xml b/tools/designer/src/components/widgetbox/widgetbox.xml new file mode 100644 index 0000000..462ac7d --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.xml @@ -0,0 +1,932 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--************************************************************************ +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +**************************************************************************--> +<widgetbox version="4.2"> + <category name="Layouts"> + + <categoryentry name="Vertical Layout" icon="win/editvlayout.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">verticalLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Layout" icon="win/edithlayout.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">horizontalLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Grid Layout" icon="win/editgrid.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">gridLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Form Layout" icon="win/editform.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">formLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Spacers"> + + <categoryentry name="Horizontal Spacer" icon="widgets/spacer.png"> + <ui> + <widget class="Spacer"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="objectName"> + <string notr="true">horizontalSpacer</string> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Spacer" icon="widgets/vspacer.png"> + <ui> + <widget class="Spacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="objectName"> + <string notr="true">verticalSpacer</string> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Buttons"> + + <categoryentry name="Push Button" icon="widgets/pushbutton.png"> + <ui> + <widget class="QPushButton"> + <property name="text" > + <string>PushButton</string> + </property> + <property name="objectName"> + <string notr="true">pushButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tool Button" icon="widgets/toolbutton.png"> + <ui> + <widget class="QToolButton"> + <property name="objectName"> + <string notr="true">toolButton</string> + </property> + <property name="text" > + <string>...</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Radio Button" icon="widgets/radiobutton.png"> + <ui> + <widget class="QRadioButton"> + <property name="text" > + <string>RadioButton</string> + </property> + <property name="objectName"> + <string notr="true">radioButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Check Box" icon="widgets/checkbox.png"> + <ui> + <widget class="QCheckBox"> + <property name="text" > + <string>CheckBox</string> + </property> + <property name="objectName"> + <string notr="true">checkBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Command Link Button" icon="widgets/commandlinkbutton.png"> + <ui> + <widget class="QCommandLinkButton"> + <property name="text" > + <string>CommandLinkButton</string> + </property> + <property name="objectName"> + <string notr="true">commandLinkButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Button Box" icon="widgets/dialogbuttonbox.png"> + <ui> + <widget class="QDialogButtonBox"> + <property name="standardButtons" > + <set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set> + </property> + <property name="objectName"> + <string notr="true">buttonBox</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Item Views (Model-Based)"> + + <categoryentry name="List View" icon="widgets/listbox.png"> + <ui> + <widget class="QListView"> + <property name="objectName"> + <string notr="true">listView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tree View" icon="widgets/listview.png"> + <ui> + <widget class="QTreeView"> + <property name="objectName"> + <string notr="true">treeView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Table View" icon="widgets/table.png"> + <ui> + <widget class="QTableView"> + <property name="objectName"> + <string notr="true">tableView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Column View" icon="widgets/columnview.png"> + <ui> + <widget class="QColumnView"> + <property name="objectName"> + <string notr="true">columnView</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Item Widgets (Item-Based)"> + <categoryentry name="List Widget" icon="widgets/listbox.png"> + <ui> + <widget class="QListWidget"> + <property name="objectName"> + <string notr="true">listWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tree Widget" icon="widgets/listview.png"> + <ui> + <widget class="QTreeWidget"> + <property name="objectName"> + <string notr="true">treeWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Table Widget" icon="widgets/table.png"> + <ui> + <widget class="QTableWidget"> + <property name="objectName"> + <string notr="true">tableWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Containers"> + + <categoryentry name="Group Box" icon="widgets/groupbox.png"> + <ui> + <widget class="QGroupBox"> + <property name="title" > + <string>GroupBox</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">groupBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry icon="widgets/scrollarea.png" type="default" name="Scroll Area"> + <ui> + <widget class="QScrollArea"> + <property name="objectName" > + <string notr="true" >scrollArea</string> + </property> + <property name="widgetResizable" > + <bool>true</bool> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tool Box" icon="widgets/toolbox.png"> + <ui> + <widget class="QToolBox"> + <property name="currentIndex" > + <number>0</number> + </property> + <property name="objectName"> + <string notr="true">toolBox</string> + </property> + <widget class="QWidget" name="page" > + <attribute name="label"> + <string>Page 1</string> + </attribute> + </widget> + <widget class="QWidget" name="page" > + <attribute name="label"> + <string>Page 2</string> + </attribute> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tab Widget" icon="widgets/tabwidget.png"> + <ui> + <widget class="QTabWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">tabWidget</string> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Tab 1</string> + </attribute> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Tab 2</string> + </attribute> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Stacked Widget" icon="widgets/widgetstack.png"> + <ui> + <widget class="QStackedWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">stackedWidget</string> + </property> + <widget class="QWidget" name="page" /> + <widget class="QWidget" name="page" /> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Frame" icon="widgets/frame.png"> + <ui> + <widget class="QFrame"> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="objectName"> + <string notr="true">frame</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Widget" icon="widgets/widget.png"> + <ui> + <widget class="QWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">widget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="MdiArea" icon="widgets/mdiarea.png"> + <ui> + <widget class="QMdiArea"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>200</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">mdiArea</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Dock Widget" icon="widgets/dockwidget.png"> + <ui> + <widget class="QDockWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dockWidget</string> + </property> + <widget class="QWidget" name="dockWidgetContents" /> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Input Widgets"> + + <categoryentry name="Combo Box" icon="widgets/combobox.png"> + <ui> + <widget class="QComboBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>28</y> + <width>41</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">comboBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Font Combo Box" icon="widgets/fontcombobox.png"> + <ui> + <widget class="QFontComboBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>28</y> + <width>41</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">fontComboBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Line Edit" icon="widgets/lineedit.png"> + <ui> + <widget class="QLineEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>1</y> + <width>113</width> + <height>20</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">lineEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Text Edit" icon="widgets/textedit.png"> + <ui> + <widget class="QTextEdit"> + <property name="objectName"> + <string notr="true">textEdit</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>104</width> + <height>64</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Plain Text Edit" icon="widgets/plaintextedit.png"> + <ui> + <widget class="QPlainTextEdit"> + <property name="objectName"> + <string notr="true">plainTextEdit</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>104</width> + <height>64</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Spin Box" icon="widgets/spinbox.png"> + <ui> + <widget class="QSpinBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>0</y> + <width>42</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">spinBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Double Spin Box" icon="widgets/doublespinbox.png"> + <ui> + <widget class="QDoubleSpinBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>0</y> + <width>62</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">doubleSpinBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Time Edit" icon="widgets/timeedit.png"> + <ui> + <widget class="QTimeEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>28</y> + <width>118</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">timeEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Date Edit" icon="widgets/dateedit.png"> + <ui> + <widget class="QDateEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>28</y> + <width>110</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dateEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Date/Time Edit" icon="widgets/datetimeedit.png"> + <ui> + <widget class="QDateTimeEdit"> + <property name="geometry"> + <rect> + <x>0</x> + <y>28</y> + <width>194</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dateTimeEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Dial" icon="widgets/dial.png"> + <ui> + <widget class="QDial"> + <property name="geometry" > + <rect> + <x>110</x> + <y>0</y> + <width>50</width> + <height>64</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dial</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Scroll Bar" icon="widgets/hscrollbar.png"> + <ui> + <widget class="QScrollBar"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>160</width> + <height>16</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">horizontalScrollBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Scroll Bar" icon="widgets/vscrollbar.png"> + <ui> + <widget class="QScrollBar"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>16</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">verticalScrollBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Slider" icon="widgets/hslider.png"> + <ui> + <widget class="QSlider"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>160</width> + <height>16</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">horizontalSlider</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Slider" icon="widgets/vslider.png"> + <ui> + <widget class="QSlider"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>16</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">verticalSlider</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + + <category name="Display Widgets"> + + <categoryentry name="Label" icon="widgets/label.png"> + <ui> + <widget class="QLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + <property name="objectName"> + <string notr="true">label</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Text Browser" icon="widgets/textedit.png"> + <ui> + <widget class="QTextBrowser"> + <property name="objectName"> + <string notr="true">textBrowser</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Graphics View" icon="widgets/graphicsview.png"> + <ui> + <widget class="QGraphicsView"> + <property name="objectName"> + <string notr="true">graphicsView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Calendar" icon="widgets/calendarwidget.png"> + <ui> + <widget class="QCalendarWidget"> + <property name="objectName"> + <string notr="true">calendarWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="LCD Number" icon="widgets/lcdnumber.png"> + <ui> + <widget class="QLCDNumber"> + <property name="objectName"> + <string notr="true">lcdNumber</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Progress Bar" icon="widgets/progress.png"> + <ui> + <widget class="QProgressBar"> + <property name="value" > + <number>24</number> + </property> + <property name="geometry" > + <rect> + <x>9</x> + <y>38</y> + <width>118</width> + <height>23</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">progressBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Line" icon="widgets/line.png"> + <ui> + <widget class="Line"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="objectName"> + <string notr="true">line</string> + </property> + <property name="geometry" > + <rect> + <x>9</x> + <y>67</y> + <width>118</width> + <height>3</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Line" icon="widgets/vline.png"> + <ui> + <widget class="Line"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="objectName"> + <string notr="true">line</string> + </property> + <property name="geometry" > + <rect> + <x>133</x> + <y>9</y> + <width>3</width> + <height>61</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + </category> +</widgetbox> diff --git a/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp new file mode 100644 index 0000000..1dc63a5 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox_dnditem.h" +#include "ui4_p.h" + +#include <widgetfactory_p.h> +#include <spacer_widget_p.h> +#include <qdesigner_formbuilder_p.h> +#include <qtresourcemodel_p.h> +#include <formscriptrunner_p.h> +#include <formwindowbase_p.h> +#include <qdesigner_utils_p.h> +#include <qdesigner_dockwidget_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtGui/QStyle> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +/******************************************************************************* +** WidgetBoxResource +*/ + +static inline DeviceProfile currentDeviceProfile(const QDesignerFormEditorInterface *core) +{ + if (QDesignerFormWindowInterface *cfw = core->formWindowManager()->activeFormWindow()) + if (const FormWindowBase *fwb = qobject_cast<const FormWindowBase *>(cfw)) + return fwb->deviceProfile(); + return DeviceProfile(); +} + +class WidgetBoxResource : public QDesignerFormBuilder +{ +public: + WidgetBoxResource(QDesignerFormEditorInterface *core); + + // protected->public + QWidget *createUI(DomUI *ui, QWidget *parents) { return QDesignerFormBuilder::create(ui, parents); } + +protected: + + virtual QWidget *create(DomWidget *ui_widget, QWidget *parents); + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); +}; + +WidgetBoxResource::WidgetBoxResource(QDesignerFormEditorInterface *core) : + QDesignerFormBuilder(core, DisableScripts, currentDeviceProfile(core)) +{ +} + + +QWidget *WidgetBoxResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) +{ + if (widgetName == QLatin1String("Spacer")) { + Spacer *spacer = new Spacer(parentWidget); + spacer->setObjectName(name); + return spacer; + } + + return QDesignerFormBuilder::createWidget(widgetName, parentWidget, name); +} + +QWidget *WidgetBoxResource::create(DomWidget *ui_widget, QWidget *parent) +{ + QWidget *result = QDesignerFormBuilder::create(ui_widget, parent); + // It is possible to have a syntax error or something in custom + // widget XML, so, try to recover here by creating an artificial + // top level + widget. + if (!result) { + const QString msg = QApplication::translate("qdesigner_internal::WidgetBox", "Warning: Widget creation failed in the widget box. This could be caused by invalid custom widget XML."); + qdesigner_internal::designerWarning(msg); + result = new QWidget(parent); + new QWidget(result); + } + result->setFocusPolicy(Qt::NoFocus); + result->setObjectName(ui_widget->attributeName()); + return result; +} + +/******************************************************************************* +** WidgetBoxResource +*/ + +static QSize geometryProp(const DomWidget *dw) +{ + const QList<DomProperty*> prop_list = dw->elementProperty(); + const QString geometry = QLatin1String("geometry"); + foreach (DomProperty *prop, prop_list) { + if (prop->attributeName() != geometry) + continue; + DomRect *dr = prop->elementRect(); + if (dr == 0) + continue; + return QSize(dr->elementWidth(), dr->elementHeight()); + } + return QSize(); +} + +static QSize domWidgetSize(const DomWidget *dw) +{ + QSize size = geometryProp(dw); + if (size.isValid()) + return size; + + foreach (const DomWidget *child, dw->elementWidget()) { + size = geometryProp(child); + if (size.isValid()) + return size; + } + + foreach (const DomLayout *dl, dw->elementLayout()) { + foreach (DomLayoutItem *item, dl->elementItem()) { + const DomWidget *child = item->elementWidget(); + if (child == 0) + continue; + size = geometryProp(child); + if (size.isValid()) + return size; + } + } + + return QSize(); +} + +static QWidget *decorationFromDomWidget(DomUI *dom_ui, QDesignerFormEditorInterface *core) +{ + WidgetBoxResource builder(core); + // We have the builder create the articial QWidget fake top level as a tooltip + // because the size algorithm works better at weird DPI settings + // if the actual widget is created as a child of a container + QWidget *fakeTopLevel = builder.createUI(dom_ui, static_cast<QWidget*>(0)); + fakeTopLevel->setParent(0, Qt::ToolTip); // Container + // Actual widget + const DomWidget *domW = dom_ui->elementWidget()->elementWidget().front(); + QWidget *w = qFindChildren<QWidget*>(fakeTopLevel).front(); + Q_ASSERT(w); + // hack begin; + // We set _q_dockDrag dynamic property which will be detected in drag enter event of form window. + // Dock drop is handled in special way (highlight goes to central widget of main window) + if (qobject_cast<QDesignerDockWidget *>(w)) + fakeTopLevel->setProperty("_q_dockDrag", QVariant(true)); + // hack end; + w->setAutoFillBackground(true); // Different style for embedded + QSize size = domWidgetSize(domW); + const QSize minimumSize = w->minimumSizeHint(); + if (!size.isValid()) + size = w->sizeHint(); + if (size.width() < minimumSize.width()) + size.setWidth(minimumSize.width()); + if (size.height() < minimumSize.height()) + size.setHeight(minimumSize.height()); + // A QWidget might have size -1,-1 if no geometry property is specified in the widget box. + if (size.isEmpty()) + size = size.expandedTo(QSize(16, 16)); + w->setGeometry(QRect(QPoint(0, 0), size)); + fakeTopLevel->resize(size); + return fakeTopLevel; +} + +WidgetBoxDnDItem::WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos) : + QDesignerDnDItem(CopyDrop) +{ + QWidget *decoration = decorationFromDomWidget(dom_ui, core); + decoration->move(global_mouse_pos - QPoint(5, 5)); + + init(dom_ui, 0, decoration, global_mouse_pos); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetbox_dnditem.h b/tools/designer/src/components/widgetbox/widgetbox_dnditem.h new file mode 100644 index 0000000..0641f69 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_dnditem.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_DNDITEM_H +#define WIDGETBOX_DNDITEM_H + +#include <qdesigner_dnditem_p.h> +#include "widgetbox_global.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class DomUI; + +namespace qdesigner_internal { + +class QT_WIDGETBOX_EXPORT WidgetBoxDnDItem : public QDesignerDnDItem +{ +public: + WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_DNDITEM_H diff --git a/tools/designer/src/components/widgetbox/widgetbox_global.h b/tools/designer/src/components/widgetbox/widgetbox_global.h new file mode 100644 index 0000000..3e95063 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_GLOBAL_H +#define WIDGETBOX_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_WIDGETBOX_LIBRARY +# define QT_WIDGETBOX_EXPORT +#else +# define QT_WIDGETBOX_EXPORT +#endif +#else +#define QT_WIDGETBOX_EXPORT +#endif + +#endif // WIDGETBOX_GLOBAL_H diff --git a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp new file mode 100644 index 0000000..fad13f2 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp @@ -0,0 +1,494 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxcategorylistview.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> + +#include <QtXml/QDomDocument> + +#include <QtGui/QIcon> +#include <QtGui/QListView> +#include <QtGui/QLineEdit> +#include <QtGui/QItemDelegate> +#include <QtGui/QSortFilterProxyModel> + +#include <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QTextStream> +#include <QtCore/QRegExp> + +static const char *widgetElementC = "widget"; +static const char *nameAttributeC = "name"; +static const char *uiOpeningTagC = "<ui>"; +static const char *uiClosingTagC = "</ui>"; + +QT_BEGIN_NAMESPACE + +enum { FilterRole = Qt::UserRole + 11 }; + +static QString domToString(const QDomElement &elt) +{ + QString result; + QTextStream stream(&result, QIODevice::WriteOnly); + elt.save(stream, 2); + stream.flush(); + return result; +} + +static QDomDocument stringToDom(const QString &xml) +{ + QDomDocument result; + result.setContent(xml); + return result; +} + +namespace qdesigner_internal { + +// Entry of the model list + +struct WidgetBoxCategoryEntry { + WidgetBoxCategoryEntry(); + explicit WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + + QDesignerWidgetBoxInterface::Widget widget; + QString toolTip; + QString whatsThis; + QIcon icon; + bool editable; +}; + + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry() : + editable(false) +{ +} + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &w, const QIcon &i, bool e) : + widget(w), + icon(i), + editable(e) +{ +} + +/* WidgetBoxCategoryModel, representing a list of category entries. Uses a + * QAbstractListModel since the behaviour depends on the view mode of the list + * view, it does not return text in the case of IconMode. */ + +class WidgetBoxCategoryModel : public QAbstractListModel { +public: + explicit WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent = 0); + + // QAbstractListModel + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); + virtual Qt::ItemFlags flags (const QModelIndex & index ) const; + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + + // The model returns no text in icon mode, so, it also needs to know it + QListView::ViewMode viewMode() const; + void setViewMode(QListView::ViewMode vm); + + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + + QDesignerWidgetBoxInterface::Widget widgetAt(const QModelIndex & index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(int row) const; + + int indexOfWidget(const QString &name); + + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + +private: + typedef QList<WidgetBoxCategoryEntry> WidgetBoxCategoryEntrys; + + QDesignerFormEditorInterface *m_core; + WidgetBoxCategoryEntrys m_items; + QListView::ViewMode m_viewMode; +}; + +WidgetBoxCategoryModel::WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent) : + QAbstractListModel(parent), + m_core(core), + m_viewMode(QListView::ListMode) +{ +} + +QListView::ViewMode WidgetBoxCategoryModel::viewMode() const +{ + return m_viewMode; +} + +void WidgetBoxCategoryModel::setViewMode(QListView::ViewMode vm) +{ + if (m_viewMode == vm) + return; + m_viewMode = vm; + if (!m_items.empty()) + reset(); +} + +int WidgetBoxCategoryModel::indexOfWidget(const QString &name) +{ + const int count = m_items.size(); + for (int i = 0; i < count; i++) + if (m_items.at(i).widget.name() == name) + return i; + return -1; +} + +QDesignerWidgetBoxInterface::Category WidgetBoxCategoryModel::category() const +{ + QDesignerWidgetBoxInterface::Category rc; + const WidgetBoxCategoryEntrys::const_iterator cend = m_items.constEnd(); + for (WidgetBoxCategoryEntrys::const_iterator it = m_items.constBegin(); it != cend; ++it) + rc.addWidget(it->widget); + return rc; +} + +bool WidgetBoxCategoryModel::removeCustomWidgets() +{ + // Typically, we are a whole category of custom widgets, so, remove all + // and do reset. + bool changed = false; + for (WidgetBoxCategoryEntrys::iterator it = m_items.begin(); it != m_items.end(); ) + if (it->widget.type() == QDesignerWidgetBoxInterface::Widget::Custom) { + it = m_items.erase(it); + changed = true; + } else { + ++it; + } + if (changed) + reset(); + return changed; +} + +void WidgetBoxCategoryModel::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon,bool editable) +{ + // build item + WidgetBoxCategoryEntry item(widget, icon, editable); + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const int dbIndex = db->indexOfClassName(widget.name()); + if (dbIndex != -1) { + const QDesignerWidgetDataBaseItemInterface *dbItem = db->item(dbIndex); + const QString toolTip = dbItem->toolTip(); + if (!toolTip.isEmpty()) + item.toolTip = toolTip; + const QString whatsThis = dbItem->whatsThis(); + if (!whatsThis.isEmpty()) + item.whatsThis = whatsThis; + } + // insert + const int row = m_items.size(); + beginInsertRows(QModelIndex(), row, row); + m_items.push_back(item); + endInsertRows(); +} + +QVariant WidgetBoxCategoryModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return QVariant(); + + const WidgetBoxCategoryEntry &item = m_items.at(row); + switch (role) { + case Qt::DisplayRole: + // No text in icon mode + return QVariant(m_viewMode == QListView::ListMode ? item.widget.name() : QString()); + case Qt::DecorationRole: + return QVariant(item.icon); + case Qt::EditRole: + return QVariant(item.widget.name()); + case Qt::ToolTipRole: { + if (m_viewMode == QListView::ListMode) + return QVariant(item.toolTip); + // Icon mode tooltip should contain the class name + QString tt = item.widget.name(); + if (!item.toolTip.isEmpty()) { + tt += QLatin1Char('\n'); + tt += item.toolTip; + } + return QVariant(tt); + + } + case Qt::WhatsThisRole: + return QVariant(item.whatsThis); + case FilterRole: + return item.widget.name(); + } + return QVariant(); +} + +bool WidgetBoxCategoryModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int row = index.row(); + if (role != Qt::EditRole || row < 0 || row >= m_items.size() || value.type() != QVariant::String) + return false; + // Set name and adapt Xml + WidgetBoxCategoryEntry &item = m_items[row]; + const QString newName = value.toString(); + item.widget.setName(newName); + + const QDomDocument doc = stringToDom(WidgetBoxCategoryListView::widgetDomXml(item.widget)); + QDomElement widget_elt = doc.firstChildElement(QLatin1String(widgetElementC)); + if (!widget_elt.isNull()) { + widget_elt.setAttribute(QLatin1String(nameAttributeC), newName); + item.widget.setDomXml(domToString(widget_elt)); + } + emit dataChanged(index, index); + return true; +} + +Qt::ItemFlags WidgetBoxCategoryModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags rc = Qt::ItemIsEnabled; + const int row = index.row(); + if (row >= 0 && row < m_items.size()) + if (m_items.at(row).editable) { + rc |= Qt::ItemIsSelectable; + // Can change name in list mode only + if (m_viewMode == QListView::ListMode) + rc |= Qt::ItemIsEditable; + } + return rc; +} + +int WidgetBoxCategoryModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_items.size(); +} + +bool WidgetBoxCategoryModel::removeRows(int row, int count, const QModelIndex & parent) +{ + if (row < 0 || count < 1) + return false; + const int size = m_items.size(); + const int last = row + count - 1; + if (row >= size || last >= size) + return false; + beginRemoveRows(parent, row, last); + for (int r = last; r >= row; r--) + m_items.removeAt(r); + endRemoveRows(); + return true; +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(const QModelIndex & index) const +{ + return widgetAt(index.row()); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(int row) const +{ + if (row < 0 || row >= m_items.size()) + return QDesignerWidgetBoxInterface::Widget(); + return m_items.at(row).widget; +} + +/* WidgetSubBoxItemDelegate, ensures a valid name using a regexp validator */ + +class WidgetBoxCategoryEntryDelegate : public QItemDelegate +{ +public: + explicit WidgetBoxCategoryEntryDelegate(QWidget *parent = 0) : QItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; +}; + +QWidget *WidgetBoxCategoryEntryDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QWidget *result = QItemDelegate::createEditor(parent, option, index); + if (QLineEdit *line_edit = qobject_cast<QLineEdit*>(result)) { + const QRegExp re = QRegExp(QLatin1String("[_a-zA-Z][_a-zA-Z0-9]*")); + Q_ASSERT(re.isValid()); + line_edit->setValidator(new QRegExpValidator(re, line_edit)); + } + return result; +} + +// ---------------------- WidgetBoxCategoryListView + +WidgetBoxCategoryListView::WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent) : + QListView(parent), + m_proxyModel(new QSortFilterProxyModel(this)), + m_model(new WidgetBoxCategoryModel(core, this)) +{ + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setIconSize(QSize(22, 22)); + setSpacing(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setResizeMode(QListView::Adjust); + setUniformItemSizes(true); + + setItemDelegate(new WidgetBoxCategoryEntryDelegate(this)); + + connect(this, SIGNAL(pressed(QModelIndex)), this, SLOT(slotPressed(QModelIndex))); + setEditTriggers(QAbstractItemView::AnyKeyPressed); + + m_proxyModel->setSourceModel(m_model); + m_proxyModel->setFilterRole(FilterRole); + setModel(m_proxyModel); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SIGNAL(scratchPadChanged())); +} + +void WidgetBoxCategoryListView::setViewMode(ViewMode vm) +{ + QListView::setViewMode(vm); + m_model->setViewMode(vm); +} + +void WidgetBoxCategoryListView::setCurrentItem(AccessMode am, int row) +{ + const QModelIndex index = am == FilteredAccess ? + m_proxyModel->index(row, 0) : + m_proxyModel->mapFromSource(m_model->index(row, 0)); + + if (index.isValid()) + setCurrentIndex(index); +} + +void WidgetBoxCategoryListView::slotPressed(const QModelIndex &index) +{ + const QDesignerWidgetBoxInterface::Widget wgt = m_model->widgetAt(m_proxyModel->mapToSource(index)); + if (wgt.isNull()) + return; + emit pressed(wgt.name(), widgetDomXml(wgt), QCursor::pos()); +} + +void WidgetBoxCategoryListView::removeCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (!index.isValid() || !m_proxyModel->removeRow(index.row())) + return; + + // We check the unfiltered item count here, we don't want to get removed if the + // filtered view is empty + if (m_model->rowCount()) { + emit itemRemoved(); + } else { + emit lastItemRemoved(); + } +} + +void WidgetBoxCategoryListView::editCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (index.isValid()) + edit(index); +} + +int WidgetBoxCategoryListView::count(AccessMode am) const +{ + return am == FilteredAccess ? m_proxyModel->rowCount() : m_model->rowCount(); +} + +int WidgetBoxCategoryListView::mapRowToSource(int filterRow) const +{ + const QModelIndex filterIndex = m_proxyModel->index(filterRow, 0); + return m_proxyModel->mapToSource(filterIndex).row(); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, const QModelIndex & index) const +{ + const QModelIndex unfilteredIndex = am == FilteredAccess ? m_proxyModel->mapToSource(index) : index; + return m_model->widgetAt(unfilteredIndex); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, int row) const +{ + return m_model->widgetAt(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +void WidgetBoxCategoryListView::removeRow(AccessMode am, int row) +{ + m_model->removeRow(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +bool WidgetBoxCategoryListView::containsWidget(const QString &name) +{ + return m_model->indexOfWidget(name) != -1; +} + +void WidgetBoxCategoryListView::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable) +{ + m_model->addWidget(widget, icon, editable); +} + +QString WidgetBoxCategoryListView::widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget) +{ + QString domXml = widget.domXml(); + + if (domXml.isEmpty()) { + domXml = QLatin1String(uiOpeningTagC); + domXml += QLatin1String("<widget class=\""); + domXml += widget.name(); + domXml += QLatin1String("\"/>"); + domXml += QLatin1String(uiClosingTagC); + } + return domXml; +} + +void WidgetBoxCategoryListView::filter(const QRegExp &re) +{ + m_proxyModel->setFilterRegExp(re); +} + +QDesignerWidgetBoxInterface::Category WidgetBoxCategoryListView::category() const +{ + return m_model->category(); +} + +bool WidgetBoxCategoryListView::removeCustomWidgets() +{ + return m_model->removeCustomWidgets(); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h new file mode 100644 index 0000000..c8c5d3a --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXCATEGORYLISTVIEW_H +#define WIDGETBOXCATEGORYLISTVIEW_H + +#include <QtDesigner/QDesignerWidgetBoxInterface> + +#include <QtGui/QListView> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QSortFilterProxyModel; +class QRegExp; + +namespace qdesigner_internal { + +class WidgetBoxCategoryModel; + +// List view of a category, switchable between icon and list mode. +// Provides a filtered view. +class WidgetBoxCategoryListView : public QListView +{ + Q_OBJECT +public: + // Whether to access the filtered or unfiltered view + enum AccessMode { FilteredAccess, UnfilteredAccess }; + + explicit WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent = 0); + void setViewMode(ViewMode vm); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list); + + using QListView::contentsSize; + + // These methods operate on the filtered/unfiltered model according to accessmode + int count(AccessMode am) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, const QModelIndex &index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, int row) const; + void removeRow(AccessMode am, int row); + void setCurrentItem(AccessMode am, int row); + + // These methods operate on the unfiltered model and are used for serialization + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + bool containsWidget(const QString &name); + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + + // Helper: Ensure a <ui> tag in the case of empty XML + static QString widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget); + +signals: + void scratchPadChanged(); + void pressed(const QString &name, const QString &xml, const QPoint &globalPos); + void itemRemoved(); + void lastItemRemoved(); + +public slots: + void filter(const QRegExp &re); + +private slots: + void slotPressed(const QModelIndex &index); + void removeCurrentItem(); + void editCurrentItem(); + +private: + int mapRowToSource(int filterRow) const; + QSortFilterProxyModel *m_proxyModel; + WidgetBoxCategoryModel *m_model; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXCATEGORYLISTVIEW_H diff --git a/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp b/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp new file mode 100644 index 0000000..799f96f --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp @@ -0,0 +1,998 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxtreewidget.h" +#include "widgetboxcategorylistview.h" + +// shared +#include <iconloader_p.h> +#include <sheet_delegate_p.h> +#include <QtDesigner/private/abstractsettings_p.h> +#include <ui4_p.h> +#include <qdesigner_utils_p.h> +#include <pluginmanager_p.h> + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerDnDItemInterface> +#include <QtDesigner/QDesignerCustomWidgetInterface> +#include <QtDesigner/private/abstractsettings_p.h> + +#include <QtGui/QHeaderView> +#include <QtGui/QApplication> +#include <QtGui/QTreeWidgetItem> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QMenu> + +#include <QtCore/QFile> +#include <QtCore/QTimer> +#include <QtCore/QDebug> + +static const char *widgetBoxRootElementC = "widgetbox"; +static const char *widgetElementC = "widget"; +static const char *uiElementC = "ui"; +static const char *categoryElementC = "category"; +static const char *categoryEntryElementC = "categoryentry"; +static const char *nameAttributeC = "name"; +static const char *typeAttributeC = "type"; +static const char *iconAttributeC = "icon"; +static const char *defaultTypeValueC = "default"; +static const char *customValueC = "custom"; +static const char *iconPrefixC = "__qt_icon__"; +static const char *scratchPadValueC = "scratchpad"; +static const char *qtLogoC = "qtlogo.png"; +static const char *invisibleNameC = "[invisible]"; + +enum TopLevelRole { NORMAL_ITEM, SCRATCHPAD_ITEM, CUSTOM_ITEM }; + +QT_BEGIN_NAMESPACE + +static void setTopLevelRole(TopLevelRole tlr, QTreeWidgetItem *item) +{ + item->setData(0, Qt::UserRole, QVariant(tlr)); +} + +static TopLevelRole topLevelRole(const QTreeWidgetItem *item) +{ + return static_cast<TopLevelRole>(item->data(0, Qt::UserRole).toInt()); +} + +namespace qdesigner_internal { + +WidgetBoxTreeWidget::WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent) : + QTreeWidget(parent), + m_core(core), + m_iconMode(false), + m_scratchPadDeleteTimer(0) +{ + setFocusPolicy(Qt::NoFocus); + setIndentation(0); + setRootIsDecorated(false); + setColumnCount(1); + header()->hide(); + header()->setResizeMode(QHeaderView::Stretch); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollMode(ScrollPerPixel); + + setItemDelegate(new SheetDelegate(this, this)); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), + this, SLOT(handleMousePress(QTreeWidgetItem*))); +} + +QIcon WidgetBoxTreeWidget::iconForWidget(QString iconName) const +{ + if (iconName.isEmpty()) + iconName = QLatin1String(qtLogoC); + + if (iconName.startsWith(QLatin1String(iconPrefixC))) { + const IconCache::const_iterator it = m_pluginIcons.constFind(iconName); + if (it != m_pluginIcons.constEnd()) + return it.value(); + } + return createIconSet(iconName); +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::categoryViewAt(int idx) const +{ + WidgetBoxCategoryListView *rc = 0; + if (QTreeWidgetItem *cat_item = topLevelItem(idx)) + if (QTreeWidgetItem *embedItem = cat_item->child(0)) + rc = qobject_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + Q_ASSERT(rc); + return rc; +} + +void WidgetBoxTreeWidget::saveExpandedState() const +{ + QStringList closedCategories; + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + const QTreeWidgetItem *cat_item = topLevelItem(i); + if (!isItemExpanded(cat_item)) + closedCategories.append(cat_item->text(0)); + } + } + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(widgetBoxRootElementC)); + settings->setValue(QLatin1String("Closed categories"), closedCategories); + settings->setValue(QLatin1String("View mode"), m_iconMode); + settings->endGroup(); +} + +void WidgetBoxTreeWidget::restoreExpandedState() +{ + typedef QSet<QString> StringSet; + QDesignerSettingsInterface *settings = m_core->settingsManager(); + m_iconMode = settings->value(QLatin1String("WidgetBox/View mode")).toBool(); + updateViewMode(); + const StringSet closedCategories = settings->value(QLatin1String("WidgetBox/Closed categories"), QStringList()).toStringList().toSet(); + expandAll(); + if (closedCategories.empty()) + return; + + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + QTreeWidgetItem *item = topLevelItem(i); + if (closedCategories.contains(item->text(0))) + item->setExpanded(false); + } + } +} + +WidgetBoxTreeWidget::~WidgetBoxTreeWidget() +{ + saveExpandedState(); +} + +void WidgetBoxTreeWidget::setFileName(const QString &file_name) +{ + m_file_name = file_name; +} + +QString WidgetBoxTreeWidget::fileName() const +{ + return m_file_name; +} + +bool WidgetBoxTreeWidget::save() +{ + if (fileName().isEmpty()) + return false; + + QFile file(fileName()); + if (!file.open(QIODevice::WriteOnly)) + return false; + + CategoryList cat_list; + const int count = categoryCount(); + for (int i = 0; i < count; ++i) + cat_list.append(category(i)); + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + writeCategories(writer, cat_list); + writer.writeEndDocument(); + + return true; +} + +void WidgetBoxTreeWidget::slotSave() +{ + save(); +} + +void WidgetBoxTreeWidget::handleMousePress(QTreeWidgetItem *item) +{ + if (item == 0) + return; + + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + if (item->parent() == 0) { + setItemExpanded(item, !isItemExpanded(item)); + return; + } +} + +int WidgetBoxTreeWidget::ensureScratchpad() +{ + const int existingIndex = indexOfScratchpad(); + if (existingIndex != -1) + return existingIndex; + + QTreeWidgetItem *scratch_item = new QTreeWidgetItem(this); + scratch_item->setText(0, tr("Scratchpad")); + setTopLevelRole(SCRATCHPAD_ITEM, scratch_item); + addCategoryView(scratch_item, false); // Scratchpad in list mode. + return categoryCount() - 1; +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::addCategoryView(QTreeWidgetItem *parent, bool iconMode) +{ + QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent); + embed_item->setFlags(Qt::ItemIsEnabled); + WidgetBoxCategoryListView *categoryView = new WidgetBoxCategoryListView(m_core, this); + categoryView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode); + connect(categoryView, SIGNAL(scratchPadChanged()), this, SLOT(slotSave())); + connect(categoryView, SIGNAL(pressed(QString,QString,QPoint)), this, SIGNAL(pressed(QString,QString,QPoint))); + connect(categoryView, SIGNAL(itemRemoved()), this, SLOT(slotScratchPadItemDeleted())); + connect(categoryView, SIGNAL(lastItemRemoved()), this, SLOT(slotLastScratchPadItemDeleted())); + setItemWidget(embed_item, 0, categoryView); + return categoryView; +} + +int WidgetBoxTreeWidget::indexOfScratchpad() const +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + if (topLevelRole(topLevelItem(i)) == SCRATCHPAD_ITEM) + return i; + } + } + return -1; +} + +int WidgetBoxTreeWidget::indexOfCategory(const QString &name) const +{ + const int topLevelCount = topLevelItemCount(); + for (int i = 0; i < topLevelCount; ++i) { + if (topLevelItem(i)->text(0) == name) + return i; + } + return -1; +} + +bool WidgetBoxTreeWidget::load(QDesignerWidgetBox::LoadMode loadMode) +{ + switch (loadMode) { + case QDesignerWidgetBox::LoadReplace: + clear(); + break; + case QDesignerWidgetBox::LoadCustomWidgetsOnly: + addCustomCategories(true); + updateGeometries(); + return true; + default: + break; + } + + const QString name = fileName(); + + QFile f(name); + if (!f.open(QIODevice::ReadOnly)) // Might not exist at first startup + return false; + + const QString contents = QString::fromUtf8(f.readAll()); + return loadContents(contents); +} + +bool WidgetBoxTreeWidget::loadContents(const QString &contents) +{ + QString errorMessage; + CategoryList cat_list; + if (!readCategories(m_file_name, contents, &cat_list, &errorMessage)) { + qdesigner_internal::designerWarning(errorMessage); + return false; + } + + foreach(const Category &cat, cat_list) + addCategory(cat); + + addCustomCategories(false); + // Restore which items are expanded + restoreExpandedState(); + return true; +} + +void WidgetBoxTreeWidget::addCustomCategories(bool replace) +{ + if (replace) { + // clear out all existing custom widgets + if (const int numTopLevels = topLevelItemCount()) { + for (int t = 0; t < numTopLevels ; ++t) + categoryViewAt(t)->removeCustomWidgets(); + } + } + // re-add + const CategoryList customList = loadCustomCategoryList(); + const CategoryList::const_iterator cend = customList.constEnd(); + for (CategoryList::const_iterator it = customList.constBegin(); it != cend; ++it) + addCategory(*it); +} + +static inline QString msgXmlError(const QString &fileName, const QXmlStreamReader &r) +{ + return QDesignerWidgetBox::tr("An error has been encountered at line %1 of %2: %3") + .arg(r.lineNumber()).arg(fileName, r.errorString()); +} + +bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString &contents, + CategoryList *cats, QString *errorMessage) +{ + // Read widget box XML: + // + //<widgetbox version="4.5"> + // <category name="Layouts"> + // <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default"> + // <widget class="QListWidget" ...> + // ... + + QXmlStreamReader reader(contents); + + + // Entries of category with name="invisible" should be ignored + bool ignoreEntries = false; + + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + //<widgetbox version="4.5"> + continue; + } + if (tag == QLatin1String(categoryElementC)) { + // <category name="Layouts"> + const QXmlStreamAttributes attributes = reader.attributes(); + const QString categoryName = attributes.value(QLatin1String(nameAttributeC)).toString(); + if (categoryName == QLatin1String(invisibleNameC)) { + ignoreEntries = true; + } else { + Category category(categoryName); + if (attributes.value(QLatin1String(typeAttributeC)) == QLatin1String(scratchPadValueC)) + category.setType(Category::Scratchpad); + cats->push_back(category); + } + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + // <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default"> + if (!ignoreEntries) { + QXmlStreamAttributes attr = reader.attributes(); + const QString widgetName = attr.value(QLatin1String(nameAttributeC)).toString(); + const QString widgetIcon = attr.value(QLatin1String(iconAttributeC)).toString(); + const WidgetBoxTreeWidget::Widget::Type widgetType = + attr.value(QLatin1String(typeAttributeC)).toString() + == QLatin1String(customValueC) ? + WidgetBoxTreeWidget::Widget::Custom : + WidgetBoxTreeWidget::Widget::Default; + + Widget w; + w.setName(widgetName); + w.setIconName(widgetIcon); + w.setType(widgetType); + if (!readWidget(&w, contents, reader)) + continue; + + cats->back().addWidget(w); + } // ignoreEntries + continue; + } + break; + } + case QXmlStreamReader::EndElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + continue; + } + if (tag == QLatin1String(categoryElementC)) { + ignoreEntries = false; + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + continue; + } + break; + } + default: break; + } + } + + if (reader.hasError()) { + *errorMessage = msgXmlError(fileName, reader); + return false; + } + + return true; +} + +/*! + * Read out a widget within a category. This can either be + * enclosed in a <ui> element or a (legacy) <widget> element which may + * contain nested <widget> elements. + * + * Examples: + * + * <ui language="c++"> + * <widget class="MultiPageWidget" name="multipagewidget"> ... </widget> + * <customwidgets>...</customwidgets> + * <ui> + * + * or + * + * <widget> + * <widget> ... </widget> + * ... + * <widget> + * + * Returns true on success, false if end was reached or an error has been encountered + * in which case the reader has its error flag set. If successful, the current item + * of the reader will be the closing element (</ui> or </widget>) + */ +bool WidgetBoxTreeWidget::readWidget(Widget *w, const QString &xml, QXmlStreamReader &r) +{ + qint64 startTagPosition =0, endTagPosition = 0; + + int nesting = 0; + bool endEncountered = false; + bool parsedWidgetTag = false; + QString outmostElement; + while (!endEncountered) { + const qint64 currentPosition = r.characterOffset(); + switch(r.readNext()) { + case QXmlStreamReader::StartElement: + if (nesting++ == 0) { + // First element must be <ui> or (legacy) <widget> + const QStringRef name = r.name(); + if (name == QLatin1String(uiElementC)) { + startTagPosition = currentPosition; + } else { + if (name == QLatin1String(widgetElementC)) { + startTagPosition = currentPosition; + parsedWidgetTag = true; + } else { + r.raiseError(QDesignerWidgetBox::tr("Unexpected element <%1> encountered when parsing for <widget> or <ui>").arg(name.toString())); + return false; + } + } + } else { + // We are within <ui> looking for the first <widget> tag + if (!parsedWidgetTag && r.name() == QLatin1String(widgetElementC)) { + parsedWidgetTag = true; + } + } + break; + case QXmlStreamReader::EndElement: + // Reached end of widget? + if (--nesting == 0) { + endTagPosition = r.characterOffset(); + endEncountered = true; + } + break; + case QXmlStreamReader::EndDocument: + r.raiseError(QDesignerWidgetBox::tr("Unexpected end of file encountered when parsing widgets.")); + return false; + case QXmlStreamReader::Invalid: + return false; + default: + break; + } + } + if (!parsedWidgetTag) { + r.raiseError(QDesignerWidgetBox::tr("A widget element could not be found.")); + return false; + } + // Oddity: Startposition is 1 off + QString widgetXml = xml.mid(startTagPosition, endTagPosition - startTagPosition); + const QChar lessThan = QLatin1Char('<'); + if (!widgetXml.startsWith(lessThan)) + widgetXml.prepend(lessThan); + w->setDomXml(widgetXml); + return true; +} + +void WidgetBoxTreeWidget::writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const +{ + const QString widgetbox = QLatin1String(widgetBoxRootElementC); + const QString name = QLatin1String(nameAttributeC); + const QString type = QLatin1String(typeAttributeC); + const QString icon = QLatin1String(iconAttributeC); + const QString defaultType = QLatin1String(defaultTypeValueC); + const QString category = QLatin1String(categoryElementC); + const QString categoryEntry = QLatin1String(categoryEntryElementC); + const QString iconPrefix = QLatin1String(iconPrefixC); + const QString widgetTag = QLatin1String(widgetElementC); + + // + // <widgetbox> + // <category name="Layouts"> + // <categoryEntry name="Vertical Layout" type="default" icon="win/editvlayout.png"> + // <ui> + // ... + // </ui> + // </categoryEntry> + // ... + // </category> + // ... + // </widgetbox> + // + + writer.writeStartElement(widgetbox); + + foreach (const Category &cat, cat_list) { + writer.writeStartElement(category); + writer.writeAttribute(name, cat.name()); + if (cat.type() == Category::Scratchpad) + writer.writeAttribute(type, QLatin1String(scratchPadValueC)); + + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget wgt = cat.widget(i); + if (wgt.type() == Widget::Custom) + continue; + + writer.writeStartElement(categoryEntry); + writer.writeAttribute(name, wgt.name()); + if (!wgt.iconName().startsWith(iconPrefix)) + writer.writeAttribute(icon, wgt.iconName()); + writer.writeAttribute(type, defaultType); + + const DomUI *domUI = QDesignerWidgetBox::xmlToUi(wgt.name(), WidgetBoxCategoryListView::widgetDomXml(wgt), false); + if (domUI) { + domUI->write(writer); + delete domUI; + } + + writer.writeEndElement(); // categoryEntry + } + writer.writeEndElement(); // categoryEntry + } + + writer.writeEndElement(); // widgetBox +} + +static int findCategory(const QString &name, const WidgetBoxTreeWidget::CategoryList &list) +{ + int idx = 0; + foreach (const WidgetBoxTreeWidget::Category &cat, list) { + if (cat.name() == name) + return idx; + ++idx; + } + return -1; +} + +static inline bool isValidIcon(const QIcon &icon) +{ + if (!icon.isNull()) { + const QList<QSize> availableSizes = icon.availableSizes(); + if (!availableSizes.empty()) + return !availableSizes.front().isEmpty(); + } + return false; +} + +WidgetBoxTreeWidget::CategoryList WidgetBoxTreeWidget::loadCustomCategoryList() const +{ + CategoryList result; + + const QDesignerPluginManager *pm = m_core->pluginManager(); + const QDesignerPluginManager::CustomWidgetList customWidgets = pm->registeredCustomWidgets(); + if (customWidgets.empty()) + return result; + + static const QString customCatName = tr("Custom Widgets"); + + const QString invisible = QLatin1String(invisibleNameC); + const QString iconPrefix = QLatin1String(iconPrefixC); + + foreach(QDesignerCustomWidgetInterface *c, customWidgets) { + const QString dom_xml = c->domXml(); + if (dom_xml.isEmpty()) + continue; + + const QString pluginName = c->name(); + const QDesignerCustomWidgetData data = pm->customWidgetData(c); + QString displayName = data.xmlDisplayName(); + if (displayName.isEmpty()) + displayName = pluginName; + + QString cat_name = c->group(); + if (cat_name.isEmpty()) + cat_name = customCatName; + else if (cat_name == invisible) + continue; + + int idx = findCategory(cat_name, result); + if (idx == -1) { + result.append(Category(cat_name)); + idx = result.size() - 1; + } + Category &cat = result[idx]; + + const QIcon icon = c->icon(); + + QString icon_name; + if (isValidIcon(icon)) { + icon_name = iconPrefix; + icon_name += pluginName; + m_pluginIcons.insert(icon_name, icon); + } else { + icon_name = QLatin1String(qtLogoC); + } + + cat.addWidget(Widget(displayName, dom_xml, icon_name, Widget::Custom)); + } + + return result; +} + +void WidgetBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item) +{ + QTreeWidgetItem *embedItem = cat_item->child(0); + WidgetBoxCategoryListView *list_widget = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + list_widget->setFixedWidth(header()->width()); + list_widget->doItemsLayout(); + const int height = qMax(list_widget->contentsSize().height() ,1); + list_widget->setFixedHeight(height); + embedItem->setSizeHint(0, QSize(-1, height - 1)); +} + +int WidgetBoxTreeWidget::categoryCount() const +{ + return topLevelItemCount(); +} + +WidgetBoxTreeWidget::Category WidgetBoxTreeWidget::category(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Category(); + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + + QTreeWidgetItem *embedItem = cat_item->child(0); + WidgetBoxCategoryListView *categoryView = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + + Category result = categoryView->category(); + result.setName(cat_item->text(0)); + + switch (topLevelRole(cat_item)) { + case SCRATCHPAD_ITEM: + result.setType(Category::Scratchpad); + break; + default: + result.setType(Category::Default); + break; + } + return result; +} + +void WidgetBoxTreeWidget::addCategory(const Category &cat) +{ + if (cat.widgetCount() == 0) + return; + + const bool isScratchPad = cat.type() == Category::Scratchpad; + WidgetBoxCategoryListView *categoryView; + QTreeWidgetItem *cat_item; + + if (isScratchPad) { + const int idx = ensureScratchpad(); + categoryView = categoryViewAt(idx); + cat_item = topLevelItem(idx); + } else { + const int existingIndex = indexOfCategory(cat.name()); + if (existingIndex == -1) { + cat_item = new QTreeWidgetItem(); + cat_item->setText(0, cat.name()); + setTopLevelRole(NORMAL_ITEM, cat_item); + // insert before scratchpad + const int scratchPadIndex = indexOfScratchpad(); + if (scratchPadIndex == -1) { + addTopLevelItem(cat_item); + } else { + insertTopLevelItem(scratchPadIndex, cat_item); + } + setItemExpanded(cat_item, true); + categoryView = addCategoryView(cat_item, m_iconMode); + } else { + categoryView = categoryViewAt(existingIndex); + cat_item = topLevelItem(existingIndex); + } + } + // The same categories are read from the file $HOME, avoid duplicates + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget w = cat.widget(i); + if (!categoryView->containsWidget(w.name())) + categoryView->addWidget(w, iconForWidget(w.iconName()), isScratchPad); + } + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeCategory(int cat_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + delete takeTopLevelItem(cat_idx); +} + +int WidgetBoxTreeWidget::widgetCount(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return 0; + // SDK functions want unfiltered access + return categoryViewAt(cat_idx)->count(WidgetBoxCategoryListView::UnfilteredAccess); +} + +WidgetBoxTreeWidget::Widget WidgetBoxTreeWidget::widget(int cat_idx, int wgt_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Widget(); + // SDK functions want unfiltered access + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + return categoryView->widgetAt(WidgetBoxCategoryListView::UnfilteredAccess, wgt_idx); +} + +void WidgetBoxTreeWidget::addWidget(int cat_idx, const Widget &wgt) +{ + if (cat_idx >= topLevelItemCount()) + return; + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + const bool scratch = topLevelRole(cat_item) == SCRATCHPAD_ITEM; + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), scratch); + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeWidget(int cat_idx, int wgt_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + // SDK functions want unfiltered access + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::UnfilteredAccess; + if (wgt_idx >= categoryView->count(am)) + return; + + categoryView->removeRow(am, wgt_idx); +} + +void WidgetBoxTreeWidget::slotScratchPadItemDeleted() +{ + const int scratch_idx = indexOfScratchpad(); + QTreeWidgetItem *scratch_item = topLevelItem(scratch_idx); + adjustSubListSize(scratch_item); + save(); +} + +void WidgetBoxTreeWidget::slotLastScratchPadItemDeleted() +{ + // Remove the scratchpad in the next idle loop + if (!m_scratchPadDeleteTimer) { + m_scratchPadDeleteTimer = new QTimer(this); + m_scratchPadDeleteTimer->setSingleShot(true); + m_scratchPadDeleteTimer->setInterval(0); + connect(m_scratchPadDeleteTimer, SIGNAL(timeout()), this, SLOT(deleteScratchpad())); + } + if (!m_scratchPadDeleteTimer->isActive()) + m_scratchPadDeleteTimer->start(); +} + +void WidgetBoxTreeWidget::deleteScratchpad() +{ + const int idx = indexOfScratchpad(); + if (idx == -1) + return; + delete takeTopLevelItem(idx); + save(); +} + + +void WidgetBoxTreeWidget::slotListMode() +{ + m_iconMode = false; + updateViewMode(); +} + +void WidgetBoxTreeWidget::slotIconMode() +{ + m_iconMode = true; + updateViewMode(); +} + +void WidgetBoxTreeWidget::updateViewMode() +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + QTreeWidgetItem *topLevel = topLevelItem(i); + // Scratch pad stays in list mode. + const QListView::ViewMode viewMode = m_iconMode && (topLevelRole(topLevel) != SCRATCHPAD_ITEM) ? QListView::IconMode : QListView::ListMode; + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + if (viewMode != categoryView->viewMode()) { + categoryView->setViewMode(viewMode); + adjustSubListSize(topLevelItem(i)); + } + } + } + + updateGeometries(); +} + +void WidgetBoxTreeWidget::resizeEvent(QResizeEvent *e) +{ + QTreeWidget::resizeEvent(e); + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) + adjustSubListSize(topLevelItem(i)); + } +} + +void WidgetBoxTreeWidget::contextMenuEvent(QContextMenuEvent *e) +{ + QTreeWidgetItem *item = itemAt(e->pos()); + + const bool scratchpad_menu = item != 0 + && item->parent() != 0 + && topLevelRole(item->parent()) == SCRATCHPAD_ITEM; + + QMenu menu; + menu.addAction(tr("Expand all"), this, SLOT(expandAll())); + menu.addAction(tr("Collapse all"), this, SLOT(collapseAll())); + menu.addSeparator(); + + QAction *listModeAction = menu.addAction(tr("List View")); + QAction *iconModeAction = menu.addAction(tr("Icon View")); + listModeAction->setCheckable(true); + iconModeAction->setCheckable(true); + QActionGroup *viewModeGroup = new QActionGroup(&menu); + viewModeGroup->addAction(listModeAction); + viewModeGroup->addAction(iconModeAction); + if (m_iconMode) + iconModeAction->setChecked(true); + else + listModeAction->setChecked(true); + connect(listModeAction, SIGNAL(triggered()), SLOT(slotListMode())); + connect(iconModeAction, SIGNAL(triggered()), SLOT(slotIconMode())); + + if (scratchpad_menu) { + menu.addSeparator(); + menu.addAction(tr("Remove"), itemWidget(item, 0), SLOT(removeCurrentItem())); + if (!m_iconMode) + menu.addAction(tr("Edit name"), itemWidget(item, 0), SLOT(editCurrentItem())); + } + e->accept(); + menu.exec(mapToGlobal(e->pos())); +} + +void WidgetBoxTreeWidget::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list) +{ + QTreeWidgetItem *scratch_item = 0; + WidgetBoxCategoryListView *categoryView = 0; + bool added = false; + + foreach (QDesignerDnDItemInterface *item, item_list) { + QWidget *w = item->widget(); + if (w == 0) + continue; + + DomUI *dom_ui = item->domUi(); + if (dom_ui == 0) + continue; + + const int scratch_idx = ensureScratchpad(); + scratch_item = topLevelItem(scratch_idx); + categoryView = categoryViewAt(scratch_idx); + + // Temporarily remove the fake toplevel in-between + DomWidget *fakeTopLevel = dom_ui->takeElementWidget(); + DomWidget *firstWidget = 0; + if (fakeTopLevel && !fakeTopLevel->elementWidget().isEmpty()) { + firstWidget = fakeTopLevel->elementWidget().first(); + dom_ui->setElementWidget(firstWidget); + } else { + dom_ui->setElementWidget(fakeTopLevel); + continue; + } + + // Serialize to XML + QString xml; + { + QXmlStreamWriter writer(&xml); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + dom_ui->write(writer); + writer.writeEndDocument(); + } + + // Insert fake toplevel again + dom_ui->takeElementWidget(); + dom_ui->setElementWidget(fakeTopLevel); + + const Widget wgt = Widget(w->objectName(), xml); + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), true); + setItemExpanded(scratch_item, true); + added = true; + } + + if (added) { + save(); + QApplication::setActiveWindow(this); + // Is the new item visible in filtered mode? + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::FilteredAccess; + if (const int count = categoryView->count(am)) + categoryView->setCurrentItem(am, count - 1); + categoryView->adjustSize(); // XXX + adjustSubListSize(scratch_item); + } +} + +void WidgetBoxTreeWidget::filter(const QString &f) +{ + const bool empty = f.isEmpty(); + const QRegExp re = empty ? QRegExp() : QRegExp(f, Qt::CaseInsensitive, QRegExp::FixedString); + const int numTopLevels = topLevelItemCount(); + bool changed = false; + for (int i = 0; i < numTopLevels; i++) { + QTreeWidgetItem *tl = topLevelItem(i); + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + // Anything changed? -> Enable the category + const int oldCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + categoryView->filter(re); + const int newCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + if (oldCount != newCount) { + changed = true; + const bool categoryEnabled = newCount > 0 || empty; + if (categoryEnabled) { + categoryView->adjustSize(); + adjustSubListSize(tl); + } + setRowHidden (i, QModelIndex(), !categoryEnabled); + } + } + if (changed) + updateGeometries(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetboxtreewidget.h b/tools/designer/src/components/widgetbox/widgetboxtreewidget.h new file mode 100644 index 0000000..9282a0f --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxtreewidget.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXTREEWIDGET_H +#define WIDGETBOXTREEWIDGET_H + +#include <qdesigner_widgetbox_p.h> + +#include <QtGui/QTreeWidget> +#include <QtGui/QIcon> +#include <QtCore/QList> +#include <QtCore/QHash> +#include <QtCore/QXmlStreamReader> // Cannot forward declare them on Mac +#include <QtCore/QXmlStreamWriter> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QTimer; + +namespace qdesigner_internal { + +class WidgetBoxCategoryListView; + +// WidgetBoxTreeWidget: A tree of categories + +class WidgetBoxTreeWidget : public QTreeWidget +{ + Q_OBJECT + +public: + typedef QDesignerWidgetBoxInterface::Widget Widget; + typedef QDesignerWidgetBoxInterface::Category Category; + typedef QDesignerWidgetBoxInterface::CategoryList CategoryList; + + explicit WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~WidgetBoxTreeWidget(); + + int categoryCount() const; + Category category(int cat_idx) const; + void addCategory(const Category &cat); + void removeCategory(int cat_idx); + + int widgetCount(int cat_idx) const; + Widget widget(int cat_idx, int wgt_idx) const; + void addWidget(int cat_idx, const Widget &wgt); + void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list); + + void setFileName(const QString &file_name); + QString fileName() const; + bool load(QDesignerWidgetBox::LoadMode loadMode); + bool loadContents(const QString &contents); + bool save(); + QIcon iconForWidget(QString iconName) const; + +signals: + void pressed(const QString name, const QString dom_xml, const QPoint &global_mouse_pos); + +public slots: + void filter(const QString &); + +protected: + void contextMenuEvent(QContextMenuEvent *e); + void resizeEvent(QResizeEvent *e); + +private slots: + void slotSave(); + void slotScratchPadItemDeleted(); + void slotLastScratchPadItemDeleted(); + + void handleMousePress(QTreeWidgetItem *item); + void deleteScratchpad(); + void slotListMode(); + void slotIconMode(); + +private: + WidgetBoxCategoryListView *addCategoryView(QTreeWidgetItem *parent, bool iconMode); + WidgetBoxCategoryListView *categoryViewAt(int idx) const; + void adjustSubListSize(QTreeWidgetItem *cat_item); + + static bool readCategories(const QString &fileName, const QString &xml, CategoryList *cats, QString *errorMessage); + static bool readWidget(Widget *w, const QString &xml, QXmlStreamReader &r); + + CategoryList loadCustomCategoryList() const; + void writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const; + + int indexOfCategory(const QString &name) const; + int indexOfScratchpad() const; + int ensureScratchpad(); + void addCustomCategories(bool replace); + + void saveExpandedState() const; + void restoreExpandedState(); + void updateViewMode(); + + QDesignerFormEditorInterface *m_core; + QString m_file_name; + typedef QHash<QString, QIcon> IconCache; + mutable IconCache m_pluginIcons; + bool m_iconMode; + QTimer *m_scratchPadDeleteTimer; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXTREEWIDGET_H |