summaryrefslogtreecommitdiffstats
path: root/tools/designer/src/lib/shared
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:18:55 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:18:55 (GMT)
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /tools/designer/src/lib/shared
downloadQt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2
Long live Qt 4.5!
Diffstat (limited to 'tools/designer/src/lib/shared')
-rw-r--r--tools/designer/src/lib/shared/actioneditor.cpp822
-rw-r--r--tools/designer/src/lib/shared/actioneditor_p.h168
-rw-r--r--tools/designer/src/lib/shared/actionprovider_p.h108
-rw-r--r--tools/designer/src/lib/shared/actionrepository.cpp659
-rw-r--r--tools/designer/src/lib/shared/actionrepository_p.h257
-rw-r--r--tools/designer/src/lib/shared/addlinkdialog.ui112
-rw-r--r--tools/designer/src/lib/shared/codedialog.cpp266
-rw-r--r--tools/designer/src/lib/shared/codedialog_p.h100
-rw-r--r--tools/designer/src/lib/shared/connectionedit.cpp1612
-rw-r--r--tools/designer/src/lib/shared/connectionedit_p.h324
-rw-r--r--tools/designer/src/lib/shared/csshighlighter.cpp192
-rw-r--r--tools/designer/src/lib/shared/csshighlighter_p.h82
-rw-r--r--tools/designer/src/lib/shared/defaultgradients.xml498
-rw-r--r--tools/designer/src/lib/shared/deviceprofile.cpp467
-rw-r--r--tools/designer/src/lib/shared/deviceprofile_p.h152
-rw-r--r--tools/designer/src/lib/shared/dialoggui.cpp265
-rw-r--r--tools/designer/src/lib/shared/dialoggui_p.h107
-rw-r--r--tools/designer/src/lib/shared/extensionfactory_p.h120
-rw-r--r--tools/designer/src/lib/shared/filterwidget.cpp237
-rw-r--r--tools/designer/src/lib/shared/filterwidget_p.h152
-rw-r--r--tools/designer/src/lib/shared/formlayoutmenu.cpp534
-rw-r--r--tools/designer/src/lib/shared/formlayoutmenu_p.h100
-rw-r--r--tools/designer/src/lib/shared/formlayoutrowdialog.ui166
-rw-r--r--tools/designer/src/lib/shared/formwindowbase.cpp487
-rw-r--r--tools/designer/src/lib/shared/formwindowbase_p.h202
-rw-r--r--tools/designer/src/lib/shared/grid.cpp186
-rw-r--r--tools/designer/src/lib/shared/grid_p.h118
-rw-r--r--tools/designer/src/lib/shared/gridpanel.cpp121
-rw-r--r--tools/designer/src/lib/shared/gridpanel.ui144
-rw-r--r--tools/designer/src/lib/shared/gridpanel_p.h101
-rw-r--r--tools/designer/src/lib/shared/htmlhighlighter.cpp198
-rw-r--r--tools/designer/src/lib/shared/htmlhighlighter_p.h101
-rw-r--r--tools/designer/src/lib/shared/iconloader.cpp80
-rw-r--r--tools/designer/src/lib/shared/iconloader_p.h72
-rw-r--r--tools/designer/src/lib/shared/iconselector.cpp546
-rw-r--r--tools/designer/src/lib/shared/iconselector_p.h142
-rw-r--r--tools/designer/src/lib/shared/invisible_widget.cpp57
-rw-r--r--tools/designer/src/lib/shared/invisible_widget_p.h75
-rw-r--r--tools/designer/src/lib/shared/layout.cpp1326
-rw-r--r--tools/designer/src/lib/shared/layout_p.h152
-rw-r--r--tools/designer/src/lib/shared/layoutinfo.cpp312
-rw-r--r--tools/designer/src/lib/shared/layoutinfo_p.h114
-rw-r--r--tools/designer/src/lib/shared/metadatabase.cpp295
-rw-r--r--tools/designer/src/lib/shared/metadatabase_p.h142
-rw-r--r--tools/designer/src/lib/shared/morphmenu.cpp635
-rw-r--r--tools/designer/src/lib/shared/morphmenu_p.h97
-rw-r--r--tools/designer/src/lib/shared/newactiondialog.cpp197
-rw-r--r--tools/designer/src/lib/shared/newactiondialog.ui277
-rw-r--r--tools/designer/src/lib/shared/newactiondialog_p.h124
-rw-r--r--tools/designer/src/lib/shared/newformwidget.cpp587
-rw-r--r--tools/designer/src/lib/shared/newformwidget.ui192
-rw-r--r--tools/designer/src/lib/shared/newformwidget_p.h143
-rw-r--r--tools/designer/src/lib/shared/orderdialog.cpp192
-rw-r--r--tools/designer/src/lib/shared/orderdialog.ui198
-rw-r--r--tools/designer/src/lib/shared/orderdialog_p.h114
-rw-r--r--tools/designer/src/lib/shared/plaintexteditor.cpp123
-rw-r--r--tools/designer/src/lib/shared/plaintexteditor_p.h89
-rw-r--r--tools/designer/src/lib/shared/plugindialog.cpp207
-rw-r--r--tools/designer/src/lib/shared/plugindialog.ui136
-rw-r--r--tools/designer/src/lib/shared/plugindialog_p.h81
-rw-r--r--tools/designer/src/lib/shared/pluginmanager.cpp670
-rw-r--r--tools/designer/src/lib/shared/pluginmanager_p.h151
-rw-r--r--tools/designer/src/lib/shared/previewconfigurationwidget.cpp382
-rw-r--r--tools/designer/src/lib/shared/previewconfigurationwidget.ui91
-rw-r--r--tools/designer/src/lib/shared/previewconfigurationwidget_p.h96
-rw-r--r--tools/designer/src/lib/shared/previewmanager.cpp815
-rw-r--r--tools/designer/src/lib/shared/previewmanager_p.h184
-rw-r--r--tools/designer/src/lib/shared/promotionmodel.cpp224
-rw-r--r--tools/designer/src/lib/shared/promotionmodel_p.h98
-rw-r--r--tools/designer/src/lib/shared/promotiontaskmenu.cpp361
-rw-r--r--tools/designer/src/lib/shared/promotiontaskmenu_p.h151
-rw-r--r--tools/designer/src/lib/shared/propertylineedit.cpp96
-rw-r--r--tools/designer/src/lib/shared/propertylineedit_p.h85
-rw-r--r--tools/designer/src/lib/shared/qdesigner_command.cpp2968
-rw-r--r--tools/designer/src/lib/shared/qdesigner_command2.cpp159
-rw-r--r--tools/designer/src/lib/shared/qdesigner_command2_p.h101
-rw-r--r--tools/designer/src/lib/shared/qdesigner_command_p.h1136
-rw-r--r--tools/designer/src/lib/shared/qdesigner_dnditem.cpp300
-rw-r--r--tools/designer/src/lib/shared/qdesigner_dnditem_p.h147
-rw-r--r--tools/designer/src/lib/shared/qdesigner_dockwidget.cpp140
-rw-r--r--tools/designer/src/lib/shared/qdesigner_dockwidget_p.h87
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formbuilder.cpp478
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formbuilder_p.h166
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formeditorcommand.cpp64
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formeditorcommand_p.h83
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp149
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h96
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formwindowmanager.cpp167
-rw-r--r--tools/designer/src/lib/shared/qdesigner_formwindowmanager_p.h99
-rw-r--r--tools/designer/src/lib/shared/qdesigner_integration.cpp496
-rw-r--r--tools/designer/src/lib/shared/qdesigner_integration_p.h152
-rw-r--r--tools/designer/src/lib/shared/qdesigner_introspection.cpp372
-rw-r--r--tools/designer/src/lib/shared/qdesigner_introspection_p.h84
-rw-r--r--tools/designer/src/lib/shared/qdesigner_membersheet.cpp371
-rw-r--r--tools/designer/src/lib/shared/qdesigner_membersheet_p.h120
-rw-r--r--tools/designer/src/lib/shared/qdesigner_menu.cpp1355
-rw-r--r--tools/designer/src/lib/shared/qdesigner_menu_p.h203
-rw-r--r--tools/designer/src/lib/shared/qdesigner_menubar.cpp955
-rw-r--r--tools/designer/src/lib/shared/qdesigner_menubar_p.h177
-rw-r--r--tools/designer/src/lib/shared/qdesigner_objectinspector.cpp80
-rw-r--r--tools/designer/src/lib/shared/qdesigner_objectinspector_p.h103
-rw-r--r--tools/designer/src/lib/shared/qdesigner_promotion.cpp373
-rw-r--r--tools/designer/src/lib/shared/qdesigner_promotion_p.h98
-rw-r--r--tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp452
-rw-r--r--tools/designer/src/lib/shared/qdesigner_promotiondialog_p.h161
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertycommand.cpp1479
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertycommand_p.h301
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp131
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h106
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertysheet.cpp1601
-rw-r--r--tools/designer/src/lib/shared/qdesigner_propertysheet_p.h265
-rw-r--r--tools/designer/src/lib/shared/qdesigner_qsettings.cpp94
-rw-r--r--tools/designer/src/lib/shared/qdesigner_qsettings_p.h88
-rw-r--r--tools/designer/src/lib/shared/qdesigner_stackedbox.cpp396
-rw-r--r--tools/designer/src/lib/shared/qdesigner_stackedbox_p.h164
-rw-r--r--tools/designer/src/lib/shared/qdesigner_tabwidget.cpp567
-rw-r--r--tools/designer/src/lib/shared/qdesigner_tabwidget_p.h153
-rw-r--r--tools/designer/src/lib/shared/qdesigner_taskmenu.cpp781
-rw-r--r--tools/designer/src/lib/shared/qdesigner_taskmenu_p.h132
-rw-r--r--tools/designer/src/lib/shared/qdesigner_toolbar.cpp486
-rw-r--r--tools/designer/src/lib/shared/qdesigner_toolbar_p.h135
-rw-r--r--tools/designer/src/lib/shared/qdesigner_toolbox.cpp437
-rw-r--r--tools/designer/src/lib/shared/qdesigner_toolbox_p.h140
-rw-r--r--tools/designer/src/lib/shared/qdesigner_utils.cpp734
-rw-r--r--tools/designer/src/lib/shared/qdesigner_utils_p.h482
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widget.cpp108
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widget_p.h122
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widgetbox.cpp185
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widgetbox_p.h101
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widgetitem.cpp345
-rw-r--r--tools/designer/src/lib/shared/qdesigner_widgetitem_p.h147
-rw-r--r--tools/designer/src/lib/shared/qlayout_widget.cpp2103
-rw-r--r--tools/designer/src/lib/shared/qlayout_widget_p.h292
-rw-r--r--tools/designer/src/lib/shared/qscripthighlighter.cpp468
-rw-r--r--tools/designer/src/lib/shared/qscripthighlighter_p.h84
-rw-r--r--tools/designer/src/lib/shared/qsimpleresource.cpp283
-rw-r--r--tools/designer/src/lib/shared/qsimpleresource_p.h147
-rw-r--r--tools/designer/src/lib/shared/qtresourceeditordialog.cpp2226
-rw-r--r--tools/designer/src/lib/shared/qtresourceeditordialog.ui177
-rw-r--r--tools/designer/src/lib/shared/qtresourceeditordialog_p.h129
-rw-r--r--tools/designer/src/lib/shared/qtresourcemodel.cpp648
-rw-r--r--tools/designer/src/lib/shared/qtresourcemodel_p.h144
-rw-r--r--tools/designer/src/lib/shared/qtresourceview.cpp766
-rw-r--r--tools/designer/src/lib/shared/qtresourceview_p.h140
-rw-r--r--tools/designer/src/lib/shared/richtexteditor.cpp762
-rw-r--r--tools/designer/src/lib/shared/richtexteditor_p.h102
-rw-r--r--tools/designer/src/lib/shared/scriptcommand.cpp103
-rw-r--r--tools/designer/src/lib/shared/scriptcommand_p.h93
-rw-r--r--tools/designer/src/lib/shared/scriptdialog.cpp128
-rw-r--r--tools/designer/src/lib/shared/scriptdialog_p.h90
-rw-r--r--tools/designer/src/lib/shared/scripterrordialog.cpp112
-rw-r--r--tools/designer/src/lib/shared/scripterrordialog_p.h83
-rw-r--r--tools/designer/src/lib/shared/selectsignaldialog.ui93
-rw-r--r--tools/designer/src/lib/shared/shared.pri189
-rw-r--r--tools/designer/src/lib/shared/shared.qrc20
-rw-r--r--tools/designer/src/lib/shared/shared_enums_p.h99
-rw-r--r--tools/designer/src/lib/shared/shared_global_p.h76
-rw-r--r--tools/designer/src/lib/shared/shared_settings.cpp321
-rw-r--r--tools/designer/src/lib/shared/shared_settings_p.h142
-rw-r--r--tools/designer/src/lib/shared/sheet_delegate.cpp112
-rw-r--r--tools/designer/src/lib/shared/sheet_delegate_p.h85
-rw-r--r--tools/designer/src/lib/shared/signalslotdialog.cpp526
-rw-r--r--tools/designer/src/lib/shared/signalslotdialog.ui129
-rw-r--r--tools/designer/src/lib/shared/signalslotdialog_p.h173
-rw-r--r--tools/designer/src/lib/shared/spacer_widget.cpp280
-rw-r--r--tools/designer/src/lib/shared/spacer_widget_p.h117
-rw-r--r--tools/designer/src/lib/shared/stylesheeteditor.cpp415
-rw-r--r--tools/designer/src/lib/shared/stylesheeteditor_p.h144
-rw-r--r--tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui67
-rw-r--r--tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Bottom.ui71
-rw-r--r--tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Right.ui71
-rw-r--r--tools/designer/src/lib/shared/templates/forms/Dialog_without_Buttons.ui18
-rw-r--r--tools/designer/src/lib/shared/templates/forms/Main_Window.ui24
-rw-r--r--tools/designer/src/lib/shared/templates/forms/Widget.ui21
-rw-r--r--tools/designer/src/lib/shared/textpropertyeditor.cpp429
-rw-r--r--tools/designer/src/lib/shared/textpropertyeditor_p.h156
-rw-r--r--tools/designer/src/lib/shared/widgetdatabase.cpp865
-rw-r--r--tools/designer/src/lib/shared/widgetdatabase_p.h210
-rw-r--r--tools/designer/src/lib/shared/widgetfactory.cpp897
-rw-r--r--tools/designer/src/lib/shared/widgetfactory_p.h191
-rw-r--r--tools/designer/src/lib/shared/zoomwidget.cpp578
-rw-r--r--tools/designer/src/lib/shared/zoomwidget_p.h238
189 files changed, 57145 insertions, 0 deletions
diff --git a/tools/designer/src/lib/shared/actioneditor.cpp b/tools/designer/src/lib/shared/actioneditor.cpp
new file mode 100644
index 0000000..6a66442
--- /dev/null
+++ b/tools/designer/src/lib/shared/actioneditor.cpp
@@ -0,0 +1,822 @@
+/****************************************************************************
+**
+** 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::ActionEditor
+*/
+
+#include "actioneditor_p.h"
+#include "filterwidget_p.h"
+#include "actionrepository_p.h"
+#include "iconloader_p.h"
+#include "newactiondialog_p.h"
+#include "qdesigner_menu_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "qdesigner_utils_p.h"
+#include "qsimpleresource_p.h"
+#include "formwindowbase_p.h"
+#include "qdesigner_taskmenu_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+#include <QtDesigner/QDesignerIconCacheInterface>
+#include <QtDesigner/private/abstractsettings_p.h>
+
+#include <QtGui/QMenu>
+#include <QtGui/QToolBar>
+#include <QtGui/QSplitter>
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QItemDelegate>
+#include <QtGui/QPainter>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QLineEdit>
+#include <QtGui/QLabel>
+#include <QtGui/QPushButton>
+#include <QtGui/QToolButton>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QItemSelection>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtCore/QSignalMapper>
+#include <QtCore/QBuffer>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+static const char *actionEditorViewModeKey = "ActionEditorViewMode";
+
+static const char *iconPropertyC = "icon";
+static const char *shortcutPropertyC = "shortcut";
+static const char *toolTipPropertyC = "toolTip";
+static const char *checkablePropertyC = "checkable";
+static const char *objectNamePropertyC = "objectName";
+static const char *textPropertyC = "text";
+
+namespace qdesigner_internal {
+//-------- ActionGroupDelegate
+class ActionGroupDelegate: public QItemDelegate
+{
+public:
+ ActionGroupDelegate(QObject *parent)
+ : QItemDelegate(parent) {}
+
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option.rect, option.palette.highlight());
+
+ QItemDelegate::paint(painter, option, index);
+ }
+
+ virtual void drawFocus(QPainter * /*painter*/, const QStyleOptionViewItem &/*option*/, const QRect &/*rect*/) const {}
+};
+
+//-------- ActionEditor
+ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) :
+ QDesignerActionEditorInterface(parent, flags),
+ m_core(core),
+ m_actionGroups(0),
+ m_actionView(new ActionView),
+ m_actionNew(new QAction(tr("New..."), this)),
+ m_actionEdit(new QAction(tr("Edit..."), this)),
+ m_actionNavigateToSlot(new QAction(tr("Go to slot..."), this)),
+ m_actionCopy(new QAction(tr("Copy"), this)),
+ m_actionCut(new QAction(tr("Cut"), this)),
+ m_actionPaste(new QAction(tr("Paste"), this)),
+ m_actionSelectAll(new QAction(tr("Select all"), this)),
+ m_actionDelete(new QAction(tr("Delete"), this)),
+ m_viewModeGroup(new QActionGroup(this)),
+ m_iconViewAction(0),
+ m_listViewAction(0),
+ m_filterWidget(0),
+ m_selectAssociatedWidgetsMapper(0)
+{
+ m_actionView->initialize(m_core);
+ m_actionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ setWindowTitle(tr("Actions"));
+
+ QVBoxLayout *l = new QVBoxLayout(this);
+ l->setMargin(0);
+ l->setSpacing(0);
+
+ QToolBar *toolbar = new QToolBar;
+ toolbar->setIconSize(QSize(22, 22));
+ toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ l->addWidget(toolbar);
+ // edit actions
+ m_actionNew->setIcon(createIconSet(QLatin1String("filenew.png")));
+ m_actionNew->setEnabled(false);
+ connect(m_actionNew, SIGNAL(triggered()), this, SLOT(slotNewAction()));
+ toolbar->addAction(m_actionNew);
+
+ connect(m_actionSelectAll, SIGNAL(triggered()), m_actionView, SLOT(selectAll()));
+
+ m_actionCut->setEnabled(false);
+ connect(m_actionCut, SIGNAL(triggered()), this, SLOT(slotCut()));
+ m_actionCut->setIcon(createIconSet(QLatin1String("editcut.png")));
+
+ m_actionCopy->setEnabled(false);
+ connect(m_actionCopy, SIGNAL(triggered()), this, SLOT(slotCopy()));
+ m_actionCopy->setIcon(createIconSet(QLatin1String("editcopy.png")));
+ toolbar->addAction(m_actionCopy);
+
+ connect(m_actionPaste, SIGNAL(triggered()), this, SLOT(slotPaste()));
+ m_actionPaste->setIcon(createIconSet(QLatin1String("editpaste.png")));
+ toolbar->addAction(m_actionPaste);
+
+ m_actionEdit->setEnabled(false);
+ connect(m_actionEdit, SIGNAL(triggered()), this, SLOT(editCurrentAction()));
+
+ connect(m_actionNavigateToSlot, SIGNAL(triggered()), this, SLOT(navigateToSlotCurrentAction()));
+
+ m_actionDelete->setIcon(createIconSet(QLatin1String("editdelete.png")));
+ m_actionDelete->setEnabled(false);
+ connect(m_actionDelete, SIGNAL(triggered()), this, SLOT(slotDelete()));
+ toolbar->addAction(m_actionDelete);
+
+ // Toolbutton with menu containing action group for detailed/icon view. Steal the icons from the file dialog.
+ //
+ QMenu *configureMenu;
+ toolbar->addWidget(createConfigureMenuButton(tr("Configure Action Editor"), &configureMenu));
+
+ connect(m_viewModeGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewMode(QAction*)));
+ m_iconViewAction = m_viewModeGroup->addAction(tr("Icon View"));
+ m_iconViewAction->setData(QVariant(ActionView::IconView));
+ m_iconViewAction->setCheckable(true);
+ m_iconViewAction->setIcon(style()->standardIcon (QStyle::SP_FileDialogListView));
+ configureMenu->addAction(m_iconViewAction);
+
+ m_listViewAction = m_viewModeGroup->addAction(tr("Detailed View"));
+ m_listViewAction->setData(QVariant(ActionView::DetailedView));
+ m_listViewAction->setCheckable(true);
+ m_listViewAction->setIcon(style()->standardIcon (QStyle::SP_FileDialogDetailedView));
+ configureMenu->addAction(m_listViewAction);
+ // filter
+ m_filterWidget = new FilterWidget(toolbar);
+ connect(m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(setFilter(QString)));
+ m_filterWidget->setEnabled(false);
+ toolbar->addWidget(m_filterWidget);
+
+ // main layout
+ QSplitter *splitter = new QSplitter(Qt::Horizontal);
+ splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ splitter->addWidget(m_actionView);
+ l->addWidget(splitter);
+
+#if 0 // ### implement me
+ m_actionGroups = new QListWidget(splitter);
+ splitter->addWidget(m_actionGroups);
+ m_actionGroups->setItemDelegate(new ActionGroupDelegate(m_actionGroups));
+ m_actionGroups->setMovement(QListWidget::Static);
+ m_actionGroups->setResizeMode(QListWidget::Fixed);
+ m_actionGroups->setIconSize(QSize(48, 48));
+ m_actionGroups->setFlow(QListWidget::TopToBottom);
+ m_actionGroups->setViewMode(QListWidget::IconMode);
+ m_actionGroups->setWrapping(false);
+#endif
+
+ connect(m_actionView, SIGNAL(resourceImageDropped(QString,QAction*)),
+ this, SLOT(resourceImageDropped(QString,QAction*)));
+
+ connect(m_actionView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentItemChanged(QAction*)));
+ // make it possible for vs integration to reimplement edit action dialog
+ connect(m_actionView, SIGNAL(activated(QAction*)), this, SIGNAL(itemActivated(QAction*)));
+
+ connect(m_actionView,SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)));
+
+ connect(m_actionView, SIGNAL(contextMenuRequested(QContextMenuEvent*, QAction*)),
+ this, SLOT(slotContextMenuRequested(QContextMenuEvent*, QAction*)));
+
+ connect(this, SIGNAL(itemActivated(QAction*)), this, SLOT(editAction(QAction*)));
+
+ restoreSettings();
+ updateViewModeActions();
+}
+
+// Utility to create a configure button with menu for usage on toolbars
+QToolButton *ActionEditor::createConfigureMenuButton(const QString &t, QMenu **ptrToMenu)
+{
+ QToolButton *configureButton = new QToolButton;
+ QAction *configureAction = new QAction(t, configureButton);
+ configureAction->setIcon(createIconSet(QLatin1String("configure.png")));
+ QMenu *configureMenu = new QMenu;
+ configureAction->setMenu(configureMenu);
+ configureButton->setDefaultAction(configureAction);
+ configureButton->setPopupMode(QToolButton::InstantPopup);
+ *ptrToMenu = configureMenu;
+ return configureButton;
+}
+
+ActionEditor::~ActionEditor()
+{
+ saveSettings();
+}
+
+QAction *ActionEditor::actionNew() const
+{
+ return m_actionNew;
+}
+
+QAction *ActionEditor::actionDelete() const
+{
+ return m_actionDelete;
+}
+
+QDesignerFormWindowInterface *ActionEditor::formWindow() const
+{
+ return m_formWindow;
+}
+
+void ActionEditor::setFormWindow(QDesignerFormWindowInterface *formWindow)
+{
+ if (formWindow != 0 && formWindow->mainContainer() == 0)
+ formWindow = 0;
+
+ // we do NOT rely on this function to update the action editor
+ if (m_formWindow == formWindow)
+ return;
+
+ if (m_formWindow != 0) {
+ const ActionList actionList = qFindChildren<QAction*>(m_formWindow->mainContainer());
+ foreach (QAction *action, actionList)
+ disconnect(action, SIGNAL(changed()), this, SLOT(slotActionChanged()));
+ }
+
+ m_formWindow = formWindow;
+
+ m_actionView->model()->clearActions();
+
+ m_actionEdit->setEnabled(false);
+ m_actionCopy->setEnabled(false);
+ m_actionCut->setEnabled(false);
+ m_actionDelete->setEnabled(false);
+
+ if (!formWindow || !formWindow->mainContainer()) {
+ m_actionNew->setEnabled(false);
+ m_filterWidget->setEnabled(false);
+ return;
+ }
+
+ m_actionNew->setEnabled(true);
+ m_filterWidget->setEnabled(true);
+
+ const ActionList actionList = qFindChildren<QAction*>(formWindow->mainContainer());
+ foreach (QAction *action, actionList)
+ if (!action->isSeparator() && core()->metaDataBase()->item(action) != 0) {
+ // Show unless it has a menu. However, listen for change on menu actions also as it might be removed
+ if (!action->menu())
+ m_actionView->model()->addAction(action);
+ connect(action, SIGNAL(changed()), this, SLOT(slotActionChanged()));
+ }
+
+ setFilter(m_filter);
+}
+
+void ActionEditor::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/)
+{
+ const bool hasSelection = !selected.indexes().empty();
+ m_actionCopy->setEnabled(hasSelection);
+ m_actionCut->setEnabled(hasSelection);
+ m_actionDelete->setEnabled(hasSelection);
+}
+
+void ActionEditor::slotCurrentItemChanged(QAction *action)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+
+ const bool hasCurrentAction = action != 0;
+ m_actionEdit->setEnabled(hasCurrentAction);
+
+ if (!action) {
+ fw->clearSelection();
+ return;
+ }
+
+ QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(core()->objectInspector());
+
+ if (action->associatedWidgets().empty()) {
+ // Special case: action not in object tree. Deselect all and set in property editor
+ fw->clearSelection(false);
+ if (oi)
+ oi->clearSelection();
+ core()->propertyEditor()->setObject(action);
+ } else {
+ if (oi)
+ oi->selectObject(action);
+ }
+}
+
+void ActionEditor::slotActionChanged()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ Q_ASSERT(action != 0);
+
+ ActionModel *model = m_actionView->model();
+ const int row = model->findAction(action);
+ if (row == -1) {
+ if (action->menu() == 0) // action got its menu deleted, create item
+ model->addAction(action);
+ } else if (action->menu() != 0) { // action got its menu created, remove item
+ model->removeRow(row);
+ } else {
+ // action text or icon changed, update item
+ model->update(row);
+ }
+}
+
+QDesignerFormEditorInterface *ActionEditor::core() const
+{
+ return m_core;
+}
+
+QString ActionEditor::filter() const
+{
+ return m_filter;
+}
+
+void ActionEditor::setFilter(const QString &f)
+{
+ m_filter = f;
+ m_actionView->filter(m_filter);
+}
+
+// Set changed state of icon property, reset when icon is cleared
+static void refreshIconPropertyChanged(const QAction *action, QDesignerPropertySheetExtension *sheet)
+{
+ sheet->setChanged(sheet->indexOf(QLatin1String(iconPropertyC)), !action->icon().isNull());
+}
+
+void ActionEditor::manageAction(QAction *action)
+{
+ action->setParent(formWindow()->mainContainer());
+ core()->metaDataBase()->add(action);
+
+ if (action->isSeparator() || action->menu() != 0)
+ return;
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), action);
+ sheet->setChanged(sheet->indexOf(QLatin1String(objectNamePropertyC)), true);
+ sheet->setChanged(sheet->indexOf(QLatin1String(textPropertyC)), true);
+ refreshIconPropertyChanged(action, sheet);
+
+ m_actionView->setCurrentIndex(m_actionView->model()->addAction(action));
+ connect(action, SIGNAL(changed()), this, SLOT(slotActionChanged()));
+}
+
+void ActionEditor::unmanageAction(QAction *action)
+{
+ core()->metaDataBase()->remove(action);
+ action->setParent(0);
+
+ disconnect(action, SIGNAL(changed()), this, SLOT(slotActionChanged()));
+
+ const int row = m_actionView->model()->findAction(action);
+ if (row != -1)
+ m_actionView->model()->remove(row);
+}
+
+// Set an intial property and mark it as changed in the sheet
+static void setInitialProperty(QDesignerPropertySheetExtension *sheet, const QString &name, const QVariant &value)
+{
+ const int index = sheet->indexOf(name);
+ Q_ASSERT(index != -1);
+ sheet->setProperty(index, value);
+ sheet->setChanged(index, true);
+}
+
+void ActionEditor::slotNewAction()
+{
+ NewActionDialog dlg(this);
+ dlg.setWindowTitle(tr("New action"));
+
+ if (dlg.exec() == QDialog::Accepted) {
+ const ActionData actionData = dlg.actionData();
+ m_actionView->clearSelection();
+
+ QAction *action = new QAction(formWindow());
+ action->setObjectName(actionData.name);
+ formWindow()->ensureUniqueObjectName(action);
+ action->setText(actionData.text);
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), action);
+ if (!actionData.toolTip.isEmpty())
+ setInitialProperty(sheet, QLatin1String(toolTipPropertyC), actionData.toolTip);
+
+ if (actionData.checkable)
+ setInitialProperty(sheet, QLatin1String(checkablePropertyC), QVariant(true));
+
+ if (!actionData.keysequence.isEmpty())
+ setInitialProperty(sheet, QLatin1String(shortcutPropertyC), qVariantFromValue(actionData.keysequence));
+
+ sheet->setProperty(sheet->indexOf(QLatin1String(iconPropertyC)), qVariantFromValue(actionData.icon));
+
+ AddActionCommand *cmd = new AddActionCommand(formWindow());
+ cmd->init(action);
+ formWindow()->commandHistory()->push(cmd);
+ }
+}
+
+static inline bool isSameIcon(const QIcon &i1, const QIcon &i2)
+{
+ return i1.serialNumber() == i2.serialNumber();
+}
+
+// return a FormWindow command to apply an icon or a reset command in case it
+// is empty.
+
+static QDesignerFormWindowCommand *setIconPropertyCommand(const PropertySheetIconValue &newIcon, QAction *action, QDesignerFormWindowInterface *fw)
+{
+ const QString iconProperty = QLatin1String(iconPropertyC);
+ if (newIcon.paths().isEmpty()) {
+ ResetPropertyCommand *cmd = new ResetPropertyCommand(fw);
+ cmd->init(action, iconProperty);
+ return cmd;
+ }
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(action, iconProperty, qVariantFromValue(newIcon));
+ return cmd;
+}
+
+// return a FormWindow command to apply a QKeySequence or a reset command
+// in case it is empty.
+
+static QDesignerFormWindowCommand *setKeySequencePropertyCommand(const QKeySequence &ks, QAction *action, QDesignerFormWindowInterface *fw)
+{
+ const QString shortcutProperty = QLatin1String(shortcutPropertyC);
+ if (ks.isEmpty()) {
+ ResetPropertyCommand *cmd = new ResetPropertyCommand(fw);
+ cmd->init(action, shortcutProperty);
+ return cmd;
+ }
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(action, shortcutProperty, qVariantFromValue(ks));
+ return cmd;
+}
+
+// return a FormWindow command to apply a POD value or reset command in case
+// it is equal to the default value.
+
+template <class T>
+QDesignerFormWindowCommand *setPropertyCommand(const QString &name, T value, T defaultValue,
+ QObject *o, QDesignerFormWindowInterface *fw)
+{
+ if (value == defaultValue) {
+ ResetPropertyCommand *cmd = new ResetPropertyCommand(fw);
+ cmd->init(o, name);
+ return cmd;
+ }
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(o, name, QVariant(value));
+ return cmd;
+}
+
+// Return the text value of a string property via PropertySheetStringValue
+static inline QString textPropertyValue(const QDesignerPropertySheetExtension *sheet, const QString &name)
+{
+ const int index = sheet->indexOf(name);
+ Q_ASSERT(index != -1);
+ const PropertySheetStringValue ps = qVariantValue<PropertySheetStringValue>(sheet->property(index));
+ return ps.value();
+}
+
+void ActionEditor::editAction(QAction *action)
+{
+ if (!action)
+ return;
+
+ NewActionDialog dlg(this);
+ dlg.setWindowTitle(tr("Edit action"));
+
+ ActionData oldActionData;
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), action);
+ oldActionData.name = action->objectName();
+ oldActionData.text = action->text();
+ oldActionData.toolTip = textPropertyValue(sheet, QLatin1String(toolTipPropertyC));
+ oldActionData.icon = qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String(iconPropertyC))));
+ oldActionData.keysequence = qVariantValue<QKeySequence>(sheet->property(sheet->indexOf(QLatin1String(shortcutPropertyC))));
+ oldActionData.checkable = action->isCheckable();
+ dlg.setActionData(oldActionData);
+
+ if (!dlg.exec())
+ return;
+
+ // figure out changes and whether to start a macro
+ const ActionData newActionData = dlg.actionData();
+ const unsigned changeMask = newActionData.compare(oldActionData);
+ if (changeMask == 0u)
+ return;
+
+ const bool severalChanges = (changeMask != ActionData::TextChanged) && (changeMask != ActionData::NameChanged)
+ && (changeMask != ActionData::ToolTipChanged) && (changeMask != ActionData::IconChanged)
+ && (changeMask != ActionData::CheckableChanged) && (changeMask != ActionData::KeysequenceChanged);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ QUndoStack *undoStack = fw->commandHistory();
+ if (severalChanges)
+ fw->beginCommand(QLatin1String("Edit action"));
+
+ if (changeMask & ActionData::NameChanged)
+ undoStack->push(createTextPropertyCommand(QLatin1String(objectNamePropertyC), newActionData.name, action, fw));
+
+ if (changeMask & ActionData::TextChanged)
+ undoStack->push(createTextPropertyCommand(QLatin1String(textPropertyC), newActionData.text, action, fw));
+
+ if (changeMask & ActionData::ToolTipChanged)
+ undoStack->push(createTextPropertyCommand(QLatin1String(toolTipPropertyC), newActionData.toolTip, action, fw));
+
+ if (changeMask & ActionData::IconChanged)
+ undoStack->push(setIconPropertyCommand(newActionData.icon, action, fw));
+
+ if (changeMask & ActionData::CheckableChanged)
+ undoStack->push(setPropertyCommand(QLatin1String(checkablePropertyC), newActionData.checkable, false, action, fw));
+
+ if (changeMask & ActionData::KeysequenceChanged)
+ undoStack->push(setKeySequencePropertyCommand(newActionData.keysequence, action, fw));
+
+ if (severalChanges)
+ fw->endCommand();
+}
+
+void ActionEditor::editCurrentAction()
+{
+ if (QAction *a = m_actionView->currentAction())
+ editAction(a);
+}
+
+void ActionEditor::navigateToSlotCurrentAction()
+{
+ if (QAction *a = m_actionView->currentAction())
+ QDesignerTaskMenu::navigateToSlot(m_core, a, QLatin1String("triggered()"));
+}
+
+void ActionEditor::deleteActions(QDesignerFormWindowInterface *fw, const ActionList &actions)
+{
+ // We need a macro even in the case of single action because the commands might cause the
+ // scheduling of other commands (signal slots connections)
+ const QString description = actions.size() == 1 ?
+ tr("Remove action '%1'").arg(actions.front()->objectName()) : tr("Remove actions");
+ fw->beginCommand(description);
+ foreach(QAction *action, actions) {
+ RemoveActionCommand *cmd = new RemoveActionCommand(fw);
+ cmd->init(action);
+ fw->commandHistory()->push(cmd);
+ }
+ fw->endCommand();
+}
+
+void ActionEditor::copyActions(QDesignerFormWindowInterface *fwi, const ActionList &actions)
+{
+ FormWindowBase *fw = qobject_cast<FormWindowBase *>(fwi);
+ if (!fw )
+ return;
+
+ FormBuilderClipboard clipboard;
+ clipboard.m_actions = actions;
+
+ if (clipboard.empty())
+ return;
+
+ QEditorFormBuilder *formBuilder = fw->createFormBuilder();
+ Q_ASSERT(formBuilder);
+
+ QBuffer buffer;
+ if (buffer.open(QIODevice::WriteOnly))
+ if (formBuilder->copy(&buffer, clipboard))
+ qApp->clipboard()->setText(QString::fromUtf8(buffer.buffer()), QClipboard::Clipboard);
+ delete formBuilder;
+}
+
+void ActionEditor::slotDelete()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+
+ const ActionView::ActionList selection = m_actionView->selectedActions();
+ if (selection.empty())
+ return;
+
+ deleteActions(fw, selection);
+}
+
+QString ActionEditor::actionTextToName(const QString &text, const QString &prefix)
+{
+ QString name = text;
+ if (name.isEmpty())
+ return QString();
+
+ name[0] = name.at(0).toUpper();
+ name.prepend(prefix);
+ const QString underscore = QString(QLatin1Char('_'));
+ name.replace(QRegExp(QString(QLatin1String("[^a-zA-Z_0-9]"))), underscore);
+ name.replace(QRegExp(QLatin1String("__*")), underscore);
+ if (name.endsWith(underscore.at(0)))
+ name.truncate(name.size() - 1);
+
+ return name;
+}
+
+void ActionEditor::resourceImageDropped(const QString &path, QAction *action)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), action);
+ const PropertySheetIconValue oldIcon =
+ qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String(iconPropertyC))));
+ PropertySheetIconValue newIcon;
+ newIcon.setPixmap(QIcon::Normal, QIcon::Off, PropertySheetPixmapValue(path));
+ if (newIcon.paths().isEmpty() || newIcon.paths() == oldIcon.paths())
+ return;
+
+ fw->commandHistory()->push(setIconPropertyCommand(newIcon , action, fw));
+}
+
+void ActionEditor::mainContainerChanged()
+{
+ // Invalidate references to objects kept in model
+ if (sender() == formWindow())
+ setFormWindow(0);
+}
+
+void ActionEditor::slotViewMode(QAction *a)
+{
+ m_actionView->setViewMode(a->data().toInt());
+ updateViewModeActions();
+}
+
+void ActionEditor::slotSelectAssociatedWidget(QWidget *w)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw )
+ return;
+
+ QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(core()->objectInspector());
+ if (!oi)
+ return;
+
+ fw->clearSelection(); // Actually, there are no widgets selected due to focus in event handling. Just to be sure.
+ oi->selectObject(w);
+}
+
+void ActionEditor::restoreSettings()
+{
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ m_actionView->setViewMode(settings->value(QLatin1String(actionEditorViewModeKey), 0).toInt());
+ updateViewModeActions();
+}
+
+void ActionEditor::saveSettings()
+{
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->setValue(QLatin1String(actionEditorViewModeKey), m_actionView->viewMode());
+}
+
+void ActionEditor::updateViewModeActions()
+{
+ switch (m_actionView->viewMode()) {
+ case ActionView::IconView:
+ m_iconViewAction->setChecked(true);
+ break;
+ case ActionView::DetailedView:
+ m_listViewAction->setChecked(true);
+ break;
+ }
+}
+
+void ActionEditor::slotCopy()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw )
+ return;
+
+ const ActionView::ActionList selection = m_actionView->selectedActions();
+ if (selection.empty())
+ return;
+
+ copyActions(fw, selection);
+}
+
+void ActionEditor::slotCut()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw )
+ return;
+
+ const ActionView::ActionList selection = m_actionView->selectedActions();
+ if (selection.empty())
+ return;
+
+ copyActions(fw, selection);
+ deleteActions(fw, selection);
+}
+
+void ActionEditor::slotPaste()
+{
+ FormWindowBase *fw = qobject_cast<FormWindowBase *>(formWindow());
+ if (!fw)
+ return;
+ m_actionView->clearSelection();
+ fw->paste(FormWindowBase::PasteActionsOnly);
+}
+
+void ActionEditor::slotContextMenuRequested(QContextMenuEvent *e, QAction *item)
+{
+ // set up signal mapper
+ if (!m_selectAssociatedWidgetsMapper) {
+ m_selectAssociatedWidgetsMapper = new QSignalMapper(this);
+ connect(m_selectAssociatedWidgetsMapper, SIGNAL(mapped(QWidget*)), this, SLOT(slotSelectAssociatedWidget(QWidget*)));
+ }
+
+ QMenu menu(this);
+ menu.addAction(m_actionNew);
+ menu.addSeparator();
+ menu.addAction(m_actionEdit);
+ if (QDesignerTaskMenu::isSlotNavigationEnabled(m_core))
+ menu.addAction(m_actionNavigateToSlot);
+
+ // Associated Widgets
+ if (QAction *action = m_actionView->currentAction()) {
+ const QWidgetList associatedWidgets = ActionModel::associatedWidgets(action);
+ if (!associatedWidgets.empty()) {
+ QMenu *associatedWidgetsSubMenu = menu.addMenu(tr("Used In"));
+ foreach (QWidget *w, associatedWidgets) {
+ QAction *action = associatedWidgetsSubMenu->addAction(w->objectName());
+ m_selectAssociatedWidgetsMapper->setMapping(action, w);
+ connect(action, SIGNAL(triggered()), m_selectAssociatedWidgetsMapper, SLOT(map()));
+ }
+ }
+ }
+
+ menu.addSeparator();
+ menu.addAction(m_actionCut);
+ menu.addAction(m_actionCopy);
+ menu.addAction(m_actionPaste);
+ menu.addAction(m_actionSelectAll);
+ menu.addAction(m_actionDelete);
+ menu.addSeparator();
+ menu.addAction(m_iconViewAction);
+ menu.addAction(m_listViewAction);
+
+ emit contextMenuRequested(&menu, item);
+
+ menu.exec(e->globalPos());
+ e->accept();
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
diff --git a/tools/designer/src/lib/shared/actioneditor_p.h b/tools/designer/src/lib/shared/actioneditor_p.h
new file mode 100644
index 0000000..36baf50
--- /dev/null
+++ b/tools/designer/src/lib/shared/actioneditor_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 ACTIONEDITOR_H
+#define ACTIONEDITOR_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/QDesignerActionEditorInterface>
+
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerPropertyEditorInterface;
+class QDesignerSettingsInterface;
+class QMenu;
+class QActionGroup;
+class QSignalMapper;
+class QItemSelection;
+class QListWidget;
+class QPushButton;
+class QLineEdit;
+class QToolButton;
+
+namespace qdesigner_internal {
+
+class ActionView;
+class ResourceMimeData;
+
+class QDESIGNER_SHARED_EXPORT ActionEditor: public QDesignerActionEditorInterface
+{
+ Q_OBJECT
+public:
+ explicit ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~ActionEditor();
+
+ QDesignerFormWindowInterface *formWindow() const;
+ virtual void setFormWindow(QDesignerFormWindowInterface *formWindow);
+
+ virtual QDesignerFormEditorInterface *core() const;
+
+ QAction *actionNew() const;
+ QAction *actionDelete() const;
+
+ QString filter() const;
+
+ virtual void manageAction(QAction *action);
+ virtual void unmanageAction(QAction *action);
+
+ static QString actionTextToName(const QString &text, const QString &prefix = QLatin1String("action"));
+
+ // Utility to create a configure button with menu for usage on toolbars
+ static QToolButton *createConfigureMenuButton(const QString &t, QMenu **ptrToMenu);
+
+public slots:
+ void setFilter(const QString &filter);
+ void mainContainerChanged();
+
+private slots:
+ void slotCurrentItemChanged(QAction *item);
+ void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
+ void editAction(QAction *item);
+ void editCurrentAction();
+ void navigateToSlotCurrentAction();
+ void slotActionChanged();
+ void slotNewAction();
+ void slotDelete();
+ void resourceImageDropped(const QString &path, QAction *action);
+ void slotContextMenuRequested(QContextMenuEvent *, QAction *);
+ void slotViewMode(QAction *a);
+ void slotSelectAssociatedWidget(QWidget *w);
+ void slotCopy();
+ void slotCut();
+ void slotPaste();
+
+signals:
+ void itemActivated(QAction *item);
+ // Context menu for item or global menu if item == 0.
+ void contextMenuRequested(QMenu *menu, QAction *item);
+
+private:
+ typedef QList<QAction *> ActionList;
+ void deleteActions(QDesignerFormWindowInterface *formWindow, const ActionList &);
+ void copyActions(QDesignerFormWindowInterface *formWindow, const ActionList &);
+
+ void restoreSettings();
+ void saveSettings();
+
+ void updateViewModeActions();
+
+ QDesignerFormEditorInterface *m_core;
+ QPointer<QDesignerFormWindowInterface> m_formWindow;
+ QListWidget *m_actionGroups;
+
+ ActionView *m_actionView;
+
+ QAction *m_actionNew;
+ QAction *m_actionEdit;
+ QAction *m_actionNavigateToSlot;
+ QAction *m_actionCopy;
+ QAction *m_actionCut;
+ QAction *m_actionPaste;
+ QAction *m_actionSelectAll;
+ QAction *m_actionDelete;
+
+ QActionGroup *m_viewModeGroup;
+ QAction *m_iconViewAction;
+ QAction *m_listViewAction;
+
+ QString m_filter;
+ QWidget *m_filterWidget;
+ QSignalMapper *m_selectAssociatedWidgetsMapper;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // ACTIONEDITOR_H
diff --git a/tools/designer/src/lib/shared/actionprovider_p.h b/tools/designer/src/lib/shared/actionprovider_p.h
new file mode 100644
index 0000000..e358f61
--- /dev/null
+++ b/tools/designer/src/lib/shared/actionprovider_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 ACTIONPROVIDER_H
+#define ACTIONPROVIDER_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 <QtDesigner/extension.h>
+#include <QtCore/QPoint>
+#include <QtCore/QRect>
+#include <QtGui/QApplication>
+
+QT_BEGIN_NAMESPACE
+
+class QAction;
+
+class QDesignerActionProviderExtension
+{
+public:
+ virtual ~QDesignerActionProviderExtension() {}
+
+ virtual QRect actionGeometry(QAction *action) const = 0;
+ virtual QAction *actionAt(const QPoint &pos) const = 0;
+
+ virtual void adjustIndicator(const QPoint &pos) = 0;
+};
+
+// Find action at the given position for a widget that has actionGeometry() (QToolBar,
+// QMenuBar, QMenu). They usually have actionAt(), but that fails since Designer usually sets
+// WA_TransparentForMouseEvents on the widgets.
+template <class Widget>
+ int actionIndexAt(const Widget *w, const QPoint &pos, Qt::Orientation orientation)
+{
+ const QList<QAction*> actions = w->actions();
+ const int actionCount = actions.count();
+ if (actionCount == 0)
+ return -1;
+ // actionGeometry() can be wrong sometimes; it returns a geometry that
+ // stretches to the end of the toolbar/menu bar. So, check from the beginning
+ // in the case of a horizontal right-to-left orientation.
+ const bool checkTopRight = orientation == Qt::Horizontal && QApplication::layoutDirection() == Qt::RightToLeft;
+ const QPoint topRight = QPoint(w->rect().width(), 0);
+ for (int index = 0; index < actionCount; ++index) {
+ QRect g = w->actionGeometry(actions.at(index));
+ if (checkTopRight)
+ g.setTopRight(topRight);
+ else
+ g.setTopLeft(QPoint(0, 0));
+
+ if (g.contains(pos))
+ return index;
+ }
+ return -1;
+}
+
+Q_DECLARE_EXTENSION_INTERFACE(QDesignerActionProviderExtension, "com.trolltech.Qt.Designer.ActionProvider")
+
+QT_END_NAMESPACE
+
+#endif // ACTIONPROVIDER_H
diff --git a/tools/designer/src/lib/shared/actionrepository.cpp b/tools/designer/src/lib/shared/actionrepository.cpp
new file mode 100644
index 0000000..941a9ba
--- /dev/null
+++ b/tools/designer/src/lib/shared/actionrepository.cpp
@@ -0,0 +1,659 @@
+/****************************************************************************
+**
+** 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 "actionrepository_p.h"
+#include "qtresourceview_p.h"
+#include "iconloader_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QDrag>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QToolButton>
+#include <QtGui/QPixmap>
+#include <QtGui/QAction>
+#include <QtGui/QHeaderView>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenu>
+#include <QtGui/qevent.h>
+#include <QtCore/QSet>
+#include <QtCore/QDebug>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ enum { listModeIconSize = 16, iconModeIconSize = 24 };
+}
+
+static const char *actionMimeType = "action-repository/actions";
+static const char *plainTextMimeType = "text/plain";
+
+static inline QAction *actionOfItem(const QStandardItem* item)
+{
+ return qvariant_cast<QAction*>(item->data(qdesigner_internal::ActionModel::ActionRole));
+}
+
+static QIcon fixActionIcon(const QIcon &icon)
+{
+ if (icon.isNull())
+ return qdesigner_internal::emptyIcon();
+ return icon;
+}
+
+namespace qdesigner_internal {
+
+// ----------- ActionModel
+ActionModel::ActionModel(QWidget *parent ) :
+ QStandardItemModel(parent),
+ m_core(0)
+{
+ QStringList headers;
+ headers += tr("Name");
+ headers += tr("Used");
+ headers += tr("Text");
+ headers += tr("Shortcut");
+ headers += tr("Checkable");
+ headers += tr("ToolTip");
+ Q_ASSERT(NumColumns == headers.size());
+ setHorizontalHeaderLabels(headers);
+}
+
+void ActionModel::clearActions()
+{
+ removeRows(0, rowCount());
+}
+
+int ActionModel::findAction(QAction *action) const
+{
+ const int rows = rowCount();
+ for (int i = 0; i < rows; i++)
+ if (action == actionOfItem(item(i)))
+ return i;
+ return -1;
+}
+
+void ActionModel::update(int row)
+{
+ Q_ASSERT(m_core);
+ // need to create the row list ... grrr..
+ if (row >= rowCount())
+ return;
+
+ QStandardItemList list;
+ for (int i = 0; i < NumColumns; i++)
+ list += item(row, i);
+
+ setItems(m_core, actionOfItem(list.front()), list);
+}
+
+void ActionModel::remove(int row)
+{
+ qDeleteAll(takeRow(row));
+}
+
+QModelIndex ActionModel::addAction(QAction *action)
+{
+ Q_ASSERT(m_core);
+ QStandardItemList items;
+ const Qt::ItemFlags flags = Qt::ItemIsSelectable|Qt::ItemIsDropEnabled|Qt::ItemIsDragEnabled|Qt::ItemIsEnabled;
+
+ QVariant itemData;
+ qVariantSetValue(itemData, action);
+
+ for (int i = 0; i < NumColumns; i++) {
+ QStandardItem *item = new QStandardItem;
+ item->setData(itemData, ActionRole);
+ item->setFlags(flags);
+ items.push_back(item);
+ }
+ setItems(m_core, action, items);
+ appendRow(items);
+ return indexFromItem(items.front());
+}
+
+// Find the associated menus and toolbars, ignore toolbuttons
+QWidgetList ActionModel::associatedWidgets(const QAction *action)
+{
+ QWidgetList rc = action->associatedWidgets();
+ for (QWidgetList::iterator it = rc.begin(); it != rc.end(); )
+ if (qobject_cast<const QMenu *>(*it) || qobject_cast<const QToolBar *>(*it)) {
+ ++it;
+ } else {
+ it = rc.erase(it);
+ }
+ return rc;
+}
+
+// shortcut is a fake property, need to retrieve it via property sheet.
+static QString actionShortCut(QDesignerFormEditorInterface *core, QAction *action)
+{
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), action);
+ if (!sheet)
+ return QString();
+ const int index = sheet->indexOf(QLatin1String("shortcut"));
+ if (index == -1)
+ return QString();
+ const QKeySequence keysequence = qvariant_cast<QKeySequence>(sheet->property(index));
+ return keysequence.toString();
+}
+
+void ActionModel::setItems(QDesignerFormEditorInterface *core, QAction *action, QStandardItemList &sl)
+{
+
+ // Tooltip, mostly for icon view mode
+ QString firstTooltip = action->objectName();
+ const QString text = action->text();
+ if (!text.isEmpty()) {
+ firstTooltip += QLatin1Char('\n');
+ firstTooltip += text;
+ }
+
+ Q_ASSERT(sl.size() == NumColumns);
+
+ QStandardItem *item = sl[NameColumn];
+ item->setText(action->objectName());
+ item->setIcon(fixActionIcon(action->icon()));
+ item->setToolTip(firstTooltip);
+ item->setWhatsThis(firstTooltip);
+ // Used
+ const QWidgetList associatedDesignerWidgets = associatedWidgets(action);
+ const bool used = !associatedDesignerWidgets.empty();
+ item = sl[UsedColumn];
+ item->setCheckState(used ? Qt::Checked : Qt::Unchecked);
+ if (used) {
+ QString usedToolTip;
+ const QString separator = QLatin1String(", ");
+ const int count = associatedDesignerWidgets.size();
+ for (int i = 0; i < count; i++) {
+ if (i)
+ usedToolTip += separator;
+ usedToolTip += associatedDesignerWidgets.at(i)->objectName();
+ }
+ item->setToolTip(usedToolTip);
+ } else {
+ item->setToolTip(QString());
+ }
+ // text
+ item = sl[TextColumn];
+ item->setText(action->text());
+ item->setToolTip(action->text());
+ // shortcut
+ const QString shortcut = actionShortCut(core, action);
+ item = sl[ShortCutColumn];
+ item->setText(shortcut);
+ item->setToolTip(shortcut);
+ // checkable
+ sl[CheckedColumn]->setCheckState(action->isCheckable() ? Qt::Checked : Qt::Unchecked);
+ // ToolTip. This might be multi-line, rich text
+ QString toolTip = action->toolTip();
+ item = sl[ToolTipColumn];
+ item->setToolTip(toolTip);
+ item->setText(toolTip.replace(QLatin1Char('\n'), QLatin1Char(' ')));
+}
+
+QMimeData *ActionModel::mimeData(const QModelIndexList &indexes ) const
+{
+ ActionRepositoryMimeData::ActionList actionList;
+
+ QSet<QAction*> actions;
+ foreach (const QModelIndex &index, indexes)
+ if (QStandardItem *item = itemFromIndex(index))
+ if (QAction *action = actionOfItem(item))
+ actions.insert(action);
+ return new ActionRepositoryMimeData(actions.toList(), Qt::CopyAction);
+}
+
+// Resource images are plain text. The drag needs to be restricted, however.
+QStringList ActionModel::mimeTypes() const
+{
+ return QStringList(QLatin1String(plainTextMimeType));
+}
+
+QString ActionModel::actionName(int row) const
+{
+ return item(row, NameColumn)->text();
+}
+
+bool ActionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &)
+{
+ if (action != Qt::CopyAction)
+ return false;
+
+ QStandardItem *droppedItem = item(row, column);
+ if (!droppedItem)
+ return false;
+
+
+ QtResourceView::ResourceType type;
+ QString path;
+ if (!QtResourceView::decodeMimeData(data, &type, &path) || type != QtResourceView::ResourceImage)
+ return false;
+
+ emit resourceImageDropped(path, actionOfItem(droppedItem));
+ return true;
+}
+
+QAction *ActionModel::actionAt(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ QStandardItem *i = itemFromIndex(index);
+ if (!i)
+ return 0;
+ return actionOfItem(i);
+}
+
+// helpers
+
+static bool handleImageDragEnterMoveEvent(QDropEvent *event)
+{
+ QtResourceView::ResourceType type;
+ const bool rc = QtResourceView::decodeMimeData(event->mimeData(), &type) && type == QtResourceView::ResourceImage;
+ if (rc)
+ event->acceptProposedAction();
+ else
+ event->ignore();
+ return rc;
+}
+
+static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, ActionModel *am)
+{
+ const QModelIndex index = iv->indexAt(event->pos());
+ if (!index.isValid()) {
+ event->ignore();
+ return;
+ }
+
+ if (!handleImageDragEnterMoveEvent(event))
+ return;
+
+ am->dropMimeData(event->mimeData(), event->proposedAction(), index.row(), 0, iv->rootIndex());
+}
+
+// Basically mimic QAbstractItemView's startDrag routine, except that
+// another pixmap is used, we don't want the whole row.
+
+void startActionDrag(QWidget *dragParent, ActionModel *model, const QModelIndexList &indexes, Qt::DropActions supportedActions)
+{
+ if (indexes.empty())
+ return;
+
+ QDrag *drag = new QDrag(dragParent);
+ QMimeData *data = model->mimeData(indexes);
+ drag->setMimeData(data);
+ if (ActionRepositoryMimeData *actionMimeData = qobject_cast<ActionRepositoryMimeData *>(data))
+ drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(actionMimeData->actionList().front()));
+
+ drag->start(supportedActions);
+}
+
+// ---------------- ActionTreeView:
+ActionTreeView::ActionTreeView(ActionModel *model, QWidget *parent) :
+ QTreeView(parent),
+ m_model(model)
+{
+ setDragEnabled(true);
+ setAcceptDrops(true);
+ setDropIndicatorShown(true);
+ setDragDropMode(DragDrop);
+ setModel(model);
+ setRootIsDecorated(false);
+ setTextElideMode(Qt::ElideMiddle);
+
+ setModel(model);
+ connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(slotActivated(QModelIndex)));
+ connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int)));
+
+ setIconSize(QSize(listModeIconSize, listModeIconSize));
+
+}
+
+QAction *ActionTreeView::currentAction() const
+{
+ return m_model->actionAt(currentIndex());
+}
+
+void ActionTreeView::filter(const QString &text)
+{
+ const int rowCount = m_model->rowCount();
+ const bool empty = text.isEmpty();
+ const QModelIndex parent = rootIndex();
+ for (int i = 0; i < rowCount; i++)
+ setRowHidden(i, parent, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive));
+}
+
+void ActionTreeView::dragEnterEvent(QDragEnterEvent *event)
+{
+ handleImageDragEnterMoveEvent(event);
+}
+
+void ActionTreeView::dragMoveEvent(QDragMoveEvent *event)
+{
+ handleImageDragEnterMoveEvent(event);
+}
+
+void ActionTreeView::dropEvent(QDropEvent *event)
+{
+ handleImageDropEvent(this, event, m_model);
+}
+
+void ActionTreeView::focusInEvent(QFocusEvent *event)
+{
+ QTreeView::focusInEvent(event);
+ // Make property editor display current action
+ if (QAction *a = currentAction())
+ emit currentChanged(a);
+}
+
+void ActionTreeView::contextMenuEvent(QContextMenuEvent *event)
+{
+ emit contextMenuRequested(event, m_model->actionAt(indexAt(event->pos())));
+}
+
+void ActionTreeView::currentChanged(const QModelIndex &current, const QModelIndex &/*previous*/)
+{
+ emit currentChanged(m_model->actionAt(current));
+}
+
+void ActionTreeView::slotActivated(const QModelIndex &index)
+{
+ emit activated(m_model->actionAt(index));
+}
+
+void ActionTreeView::startDrag(Qt::DropActions supportedActions)
+{
+ startActionDrag(this, m_model, selectedIndexes(), supportedActions);
+}
+
+// ---------------- ActionListView:
+ActionListView::ActionListView(ActionModel *model, QWidget *parent) :
+ QListView(parent),
+ m_model(model)
+{
+ setDragEnabled(true);
+ setAcceptDrops(true);
+ setDropIndicatorShown(true);
+ setDragDropMode(DragDrop);
+ setModel(model);
+ setTextElideMode(Qt::ElideMiddle);
+ connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(slotActivated(QModelIndex)));
+
+ // We actually want 'Static' as the user should be able to
+ // drag away actions only (not to rearrange icons).
+ // We emulate that by not accepting our own
+ // drag data. 'Static' causes the list view to disable drag and drop
+ // on the viewport.
+ setMovement(Snap);
+ setViewMode(IconMode);
+ setIconSize(QSize(iconModeIconSize, iconModeIconSize));
+ setGridSize(QSize(4 * iconModeIconSize, 2 * iconModeIconSize));
+ setSpacing(iconModeIconSize / 3);
+}
+
+QAction *ActionListView::currentAction() const
+{
+ return m_model->actionAt(currentIndex());
+}
+
+void ActionListView::filter(const QString &text)
+{
+ const int rowCount = m_model->rowCount();
+ const bool empty = text.isEmpty();
+ for (int i = 0; i < rowCount; i++)
+ setRowHidden(i, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive));
+}
+
+void ActionListView::dragEnterEvent(QDragEnterEvent *event)
+{
+ handleImageDragEnterMoveEvent(event);
+}
+
+void ActionListView::dragMoveEvent(QDragMoveEvent *event)
+{
+ handleImageDragEnterMoveEvent(event);
+}
+
+void ActionListView::dropEvent(QDropEvent *event)
+{
+ handleImageDropEvent(this, event, m_model);
+}
+
+void ActionListView::focusInEvent(QFocusEvent *event)
+{
+ QListView::focusInEvent(event);
+ // Make property editor display current action
+ if (QAction *a = currentAction())
+ emit currentChanged(a);
+}
+
+void ActionListView::contextMenuEvent(QContextMenuEvent *event)
+{
+ emit contextMenuRequested(event, m_model->actionAt(indexAt(event->pos())));
+}
+
+void ActionListView::currentChanged(const QModelIndex &current, const QModelIndex & /*previous*/)
+{
+ emit currentChanged(m_model->actionAt(current));
+}
+
+void ActionListView::slotActivated(const QModelIndex &index)
+{
+ emit activated(m_model->actionAt(index));
+}
+
+void ActionListView::startDrag(Qt::DropActions supportedActions)
+{
+ startActionDrag(this, m_model, selectedIndexes(), supportedActions);
+}
+
+// ActionView
+ActionView::ActionView(QWidget *parent) :
+ QStackedWidget(parent),
+ m_model(new ActionModel(this)),
+ m_actionTreeView(new ActionTreeView(m_model)),
+ m_actionListView(new ActionListView(m_model))
+{
+ addWidget(m_actionListView);
+ addWidget(m_actionTreeView);
+ // Wire signals
+ connect(m_actionTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*, QAction*)),
+ this, SIGNAL(contextMenuRequested(QContextMenuEvent*, QAction*)));
+ connect(m_actionListView, SIGNAL(contextMenuRequested(QContextMenuEvent*, QAction*)),
+ this, SIGNAL(contextMenuRequested(QContextMenuEvent*, QAction*)));
+
+ // make it possible for vs integration to reimplement edit action dialog
+ // [which it shouldn't do actually]
+ connect(m_actionListView, SIGNAL(activated(QAction*)), this, SIGNAL(activated(QAction*)));
+ connect(m_actionTreeView, SIGNAL(activated(QAction*)), this, SIGNAL(activated(QAction*)));
+
+ connect(m_actionListView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentChanged(QAction*)));
+ connect(m_actionTreeView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentChanged(QAction*)));
+
+ connect(m_model, SIGNAL(resourceImageDropped(QString,QAction*)),
+ this, SIGNAL(resourceImageDropped(QString,QAction*)));
+
+ // sync selection models
+ QItemSelectionModel *selectionModel = m_actionTreeView->selectionModel();
+ m_actionListView->setSelectionModel(selectionModel);
+ connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SIGNAL(selectionChanged(QItemSelection,QItemSelection)));
+}
+
+int ActionView::viewMode() const
+{
+ return currentWidget() == m_actionListView ? IconView : DetailedView;
+}
+
+void ActionView::setViewMode(int lm)
+{
+ if (viewMode() == lm)
+ return;
+
+ switch (lm) {
+ case IconView:
+ setCurrentWidget(m_actionListView);
+ break;
+ case DetailedView:
+ setCurrentWidget(m_actionTreeView);
+ break;
+ default:
+ break;
+ }
+}
+
+void ActionView::slotCurrentChanged(QAction *action)
+{
+ // emit only for currently visible
+ if (sender() == currentWidget())
+ emit currentChanged(action);
+}
+
+void ActionView::filter(const QString &text)
+{
+ m_actionTreeView->filter(text);
+ m_actionListView->filter(text);
+}
+
+void ActionView::selectAll()
+{
+ m_actionTreeView->selectAll();
+}
+
+void ActionView::clearSelection()
+{
+ m_actionTreeView->selectionModel()->clearSelection();
+}
+
+void ActionView::setCurrentIndex(const QModelIndex &index)
+{
+ m_actionTreeView->setCurrentIndex(index);
+}
+
+QAction *ActionView::currentAction() const
+{
+ return m_actionListView->currentAction();
+}
+
+void ActionView::setSelectionMode(QAbstractItemView::SelectionMode sm)
+{
+ m_actionTreeView->setSelectionMode(sm);
+ m_actionListView->setSelectionMode(sm);
+}
+
+QAbstractItemView::SelectionMode ActionView::selectionMode() const
+{
+ return m_actionListView->selectionMode();
+}
+
+QItemSelection ActionView::selection() const
+{
+ return m_actionListView->selectionModel()->selection();
+}
+
+ActionView::ActionList ActionView::selectedActions() const
+{
+ ActionList rc;
+ foreach (const QModelIndex &index, selection().indexes())
+ if (index.column() == 0)
+ rc += actionOfItem(m_model->itemFromIndex(index));
+ return rc;
+}
+// ---------- ActionRepositoryMimeData
+ActionRepositoryMimeData::ActionRepositoryMimeData(QAction *a, Qt::DropAction dropAction) :
+ m_dropAction(dropAction)
+{
+ m_actionList += a;
+}
+
+ActionRepositoryMimeData::ActionRepositoryMimeData(const ActionList &al, Qt::DropAction dropAction) :
+ m_dropAction(dropAction),
+ m_actionList(al)
+{
+}
+
+QStringList ActionRepositoryMimeData::formats() const
+{
+ return QStringList(QLatin1String(actionMimeType));
+}
+
+QPixmap ActionRepositoryMimeData::actionDragPixmap(const QAction *action)
+{
+
+ // Try to find a suitable pixmap. Grab either widget or icon.
+ const QIcon icon = action->icon();
+ if (!icon.isNull())
+ return icon.pixmap(QSize(22, 22));
+
+ foreach (QWidget *w, action->associatedWidgets())
+ if (QToolButton *tb = qobject_cast<QToolButton *>(w))
+ return QPixmap::grabWidget(tb);
+
+ // Create a QToolButton
+ QToolButton *tb = new QToolButton;
+ tb->setText(action->text());
+ tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
+#ifdef Q_WS_WIN // Force alien off to make adjustSize() take the system minimumsize into account.
+ tb->createWinId();
+#endif
+ tb->adjustSize();
+ const QPixmap rc = QPixmap::grabWidget(tb);
+ tb->deleteLater();
+ return rc;
+}
+
+void ActionRepositoryMimeData::accept(QDragMoveEvent *event) const
+{
+ if (event->proposedAction() == m_dropAction) {
+ event->acceptProposedAction();
+ } else {
+ event->setDropAction(m_dropAction);
+ event->accept();
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/actionrepository_p.h b/tools/designer/src/lib/shared/actionrepository_p.h
new file mode 100644
index 0000000..9d1af5a
--- /dev/null
+++ b/tools/designer/src/lib/shared/actionrepository_p.h
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** 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 ACTIONREPOSITORY_H
+#define ACTIONREPOSITORY_H
+
+#include "shared_global_p.h"
+#include <QtCore/QMimeData>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QTreeView>
+#include <QtGui/QListView>
+#include <QtGui/QStackedWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QPixmap;
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+// Shared model of actions, to be used for several views (detailed/icon view).
+class QDESIGNER_SHARED_EXPORT ActionModel: public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ enum Columns { NameColumn, UsedColumn, TextColumn, ShortCutColumn, CheckedColumn, ToolTipColumn, NumColumns };
+ enum { ActionRole = Qt::UserRole + 1000 };
+
+ explicit ActionModel(QWidget *parent = 0);
+ void initialize(QDesignerFormEditorInterface *core) { m_core = core; }
+
+ void clearActions();
+ QModelIndex addAction(QAction *a);
+ // remove row
+ void remove(int row);
+ // update the row from the underlying action
+ void update(int row);
+
+ // return row of action or -1.
+ int findAction(QAction *) const;
+
+ QString actionName(int row) const;
+ QAction *actionAt(const QModelIndex &index) const;
+
+ virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
+ virtual QStringList mimeTypes() const;
+ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+
+ // Find the associated menus and toolbars, ignore toolbuttons
+ static QWidgetList associatedWidgets(const QAction *action);
+
+signals:
+ void resourceImageDropped(const QString &path, QAction *action);
+
+private:
+ void initializeHeaders();
+
+ typedef QList<QStandardItem *> QStandardItemList;
+ static void setItems(QDesignerFormEditorInterface *core, QAction *a, QStandardItemList &sl);
+
+ QDesignerFormEditorInterface *m_core;
+};
+
+// Internal class that provides the detailed view of actions.
+class ActionTreeView: public QTreeView
+{
+ Q_OBJECT
+public:
+ explicit ActionTreeView(ActionModel *model, QWidget *parent = 0);
+ QAction *currentAction() const;
+
+public slots:
+ void filter(const QString &text);
+
+signals:
+ void contextMenuRequested(QContextMenuEvent *event, QAction *);
+ void currentChanged(QAction *action);
+ void activated(QAction *action);
+
+protected slots:
+ virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+
+protected:
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void contextMenuEvent(QContextMenuEvent *event);
+ virtual void startDrag(Qt::DropActions supportedActions);
+
+private slots:
+ void slotActivated(const QModelIndex &);
+
+private:
+ ActionModel *m_model;
+};
+
+// Internal class that provides the icon view of actions.
+class ActionListView: public QListView
+{
+ Q_OBJECT
+public:
+ explicit ActionListView(ActionModel *model, QWidget *parent = 0);
+ QAction *currentAction() const;
+
+public slots:
+ void filter(const QString &text);
+
+signals:
+ void contextMenuRequested(QContextMenuEvent *event, QAction *);
+ void currentChanged(QAction *action);
+ void activated(QAction *action);
+
+protected slots:
+ virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+
+protected:
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void contextMenuEvent(QContextMenuEvent *event);
+ virtual void startDrag(Qt::DropActions supportedActions);
+
+private slots:
+ void slotActivated(const QModelIndex &);
+
+private:
+ ActionModel *m_model;
+};
+
+// Action View that can be switched between detailed and icon view
+// using a QStackedWidget of ActionListView / ActionTreeView
+// that share the item model and the selection model.
+
+class ActionView : public QStackedWidget {
+ Q_OBJECT
+public:
+ // Separate initialize() function takes core argument to make this
+ // thing usable as promoted widget.
+ explicit ActionView(QWidget *parent = 0);
+ void initialize(QDesignerFormEditorInterface *core) { m_model->initialize(core); }
+
+ // View mode
+ enum { DetailedView, IconView };
+ int viewMode() const;
+ void setViewMode(int lm);
+
+ void setSelectionMode(QAbstractItemView::SelectionMode sm);
+ QAbstractItemView::SelectionMode selectionMode() const;
+
+ ActionModel *model() const { return m_model; }
+
+ QAction *currentAction() const;
+ void setCurrentIndex(const QModelIndex &index);
+
+ typedef QList<QAction*> ActionList;
+ ActionList selectedActions() const;
+ QItemSelection selection() const;
+
+public slots:
+ void filter(const QString &text);
+ void selectAll();
+ void clearSelection();
+
+signals:
+ void contextMenuRequested(QContextMenuEvent *event, QAction *);
+ void currentChanged(QAction *action);
+ void activated(QAction *action);
+ void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
+ void resourceImageDropped(const QString &data, QAction *action);
+
+private slots:
+ void slotCurrentChanged(QAction *action);
+
+private:
+ ActionModel *m_model;
+ ActionTreeView *m_actionTreeView;
+ ActionListView *m_actionListView;
+};
+
+class QDESIGNER_SHARED_EXPORT ActionRepositoryMimeData: public QMimeData
+{
+ Q_OBJECT
+public:
+ typedef QList<QAction*> ActionList;
+
+ ActionRepositoryMimeData(const ActionList &, Qt::DropAction dropAction);
+ ActionRepositoryMimeData(QAction *, Qt::DropAction dropAction);
+
+ const ActionList &actionList() const { return m_actionList; }
+ virtual QStringList formats() const;
+
+ static QPixmap actionDragPixmap(const QAction *action);
+
+ // Utility to accept with right action
+ void accept(QDragMoveEvent *event) const;
+private:
+ const Qt::DropAction m_dropAction;
+ ActionList m_actionList;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // ACTIONREPOSITORY_H
diff --git a/tools/designer/src/lib/shared/addlinkdialog.ui b/tools/designer/src/lib/shared/addlinkdialog.ui
new file mode 100644
index 0000000..3171159
--- /dev/null
+++ b/tools/designer/src/lib/shared/addlinkdialog.ui
@@ -0,0 +1,112 @@
+<ui version="4.0" >
+ <class>AddLinkDialog</class>
+ <widget class="QDialog" name="AddLinkDialog" >
+ <property name="windowTitle" >
+ <string>Insert Link</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>false</bool>
+ </property>
+ <property name="modal" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <layout class="QFormLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Title:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="titleInput" >
+ <property name="minimumSize" >
+ <size>
+ <width>337</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>URL:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="urlInput" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AddLinkDialog</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>AddLinkDialog</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/lib/shared/codedialog.cpp b/tools/designer/src/lib/shared/codedialog.cpp
new file mode 100644
index 0000000..5a2db33
--- /dev/null
+++ b/tools/designer/src/lib/shared/codedialog.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** 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::CodeDialog
+*/
+
+#include "codedialog_p.h"
+#include "qdesigner_utils_p.h"
+#include "iconloader_p.h"
+
+#include <texteditfindwidget.h>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QFileDialog>
+#include <QtGui/QIcon>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+#include <QtGui/QTextEdit>
+#include <QtGui/QToolBar>
+#include <QtGui/QVBoxLayout>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTemporaryFile>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+// ----------------- CodeDialogPrivate
+struct CodeDialog::CodeDialogPrivate {
+ CodeDialogPrivate();
+
+ QTextEdit *m_textEdit;
+ TextEditFindWidget *m_findWidget;
+ QString m_formFileName;
+};
+
+CodeDialog::CodeDialogPrivate::CodeDialogPrivate()
+ : m_textEdit(new QTextEdit)
+ , m_findWidget(new TextEditFindWidget)
+{
+}
+
+// ----------------- CodeDialog
+CodeDialog::CodeDialog(QWidget *parent) :
+ QDialog(parent),
+ m_impl(new CodeDialogPrivate)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ QVBoxLayout *vBoxLayout = new QVBoxLayout;
+
+ // Edit tool bar
+ QToolBar *toolBar = new QToolBar;
+
+ const QIcon saveIcon = createIconSet(QLatin1String("filesave.png"));
+ QAction *saveAction = toolBar->addAction(saveIcon, tr("Save..."));
+ connect(saveAction, SIGNAL(triggered()), this, SLOT(slotSaveAs()));
+
+ const QIcon copyIcon = createIconSet(QLatin1String("editcopy.png"));
+ QAction *copyAction = toolBar->addAction(copyIcon, tr("Copy All"));
+ connect(copyAction, SIGNAL(triggered()), this, SLOT(copyAll()));
+
+ QAction *findAction = toolBar->addAction(
+ TextEditFindWidget::findIconSet(),
+ tr("&Find in Text..."),
+ m_impl->m_findWidget, SLOT(activate()));
+ findAction->setShortcut(QKeySequence::Find);
+
+ vBoxLayout->addWidget(toolBar);
+
+ // Edit
+ m_impl->m_textEdit->setReadOnly(true);
+ m_impl->m_textEdit->setMinimumSize(QSize(
+ m_impl->m_findWidget->minimumSize().width(),
+ 500));
+ vBoxLayout->addWidget(m_impl->m_textEdit);
+
+ // Find
+ m_impl->m_findWidget->setTextEdit(m_impl->m_textEdit);
+ vBoxLayout->addWidget(m_impl->m_findWidget);
+
+ // Button box
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ // Disable auto default
+ QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
+ closeButton->setAutoDefault(false);
+ vBoxLayout->addWidget(buttonBox);
+
+ setLayout(vBoxLayout);
+}
+
+CodeDialog::~CodeDialog()
+{
+ delete m_impl;
+}
+
+void CodeDialog::setCode(const QString &code)
+{
+ m_impl->m_textEdit->setPlainText(code);
+}
+
+QString CodeDialog::code() const
+{
+ return m_impl->m_textEdit->toPlainText();
+}
+
+void CodeDialog::setFormFileName(const QString &f)
+{
+ m_impl->m_formFileName = f;
+}
+
+QString CodeDialog::formFileName() const
+{
+ return m_impl->m_formFileName;
+}
+
+bool CodeDialog::generateCode(const QDesignerFormWindowInterface *fw,
+ QString *code,
+ QString *errorMessage)
+{
+ // Generate temporary file name similar to form file name
+ // (for header guards)
+ QString tempPattern = QDir::tempPath();
+ if (!tempPattern.endsWith(QDir::separator())) // platform-dependant
+ tempPattern += QDir::separator();
+ const QString fileName = fw->fileName();
+ if (fileName.isEmpty()) {
+ tempPattern += QLatin1String("designer");
+ } else {
+ tempPattern += QFileInfo(fileName).baseName();
+ }
+ tempPattern += QLatin1String("XXXXXX.ui");
+ // Write to temp file
+ QTemporaryFile tempFormFile(tempPattern);
+
+ tempFormFile.setAutoRemove(true);
+ if (!tempFormFile.open()) {
+ *errorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath());
+ return false;
+ }
+ const QString tempFormFileName = tempFormFile.fileName();
+ tempFormFile.write(fw->contents().toUtf8());
+ if (!tempFormFile.flush()) {
+ *errorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName);
+ return false;
+ }
+ tempFormFile.close();
+ // Run uic
+ QByteArray rc;
+ if (!runUIC(tempFormFileName, UIC_GenerateCode, rc, *errorMessage))
+ return false;
+ *code = QString::fromUtf8(rc);
+ return true;
+}
+
+bool CodeDialog::showCodeDialog(const QDesignerFormWindowInterface *fw,
+ QWidget *parent,
+ QString *errorMessage)
+{
+ QString code;
+ if (!generateCode(fw, &code, errorMessage))
+ return false;
+
+ CodeDialog dialog(parent);
+ dialog.setWindowTitle(tr("%1 - [Code]").arg(fw->mainContainer()->windowTitle()));
+ dialog.setCode(code);
+ dialog.setFormFileName(fw->fileName());
+ dialog.exec();
+ return true;
+}
+
+void CodeDialog::slotSaveAs()
+{
+ // build the default relative name 'ui_sth.h'
+ const QString headerSuffix = QString(QLatin1Char('h'));
+ QString filter;
+ const QString uiFile = formFileName();
+
+ if (!uiFile.isEmpty()) {
+ filter = QLatin1String("ui_");
+ filter += QFileInfo(uiFile).baseName();
+ filter += QLatin1Char('.');
+ filter += headerSuffix;
+ }
+ // file dialog
+ while (true) {
+ const QString fileName =
+ QFileDialog::getSaveFileName (this, tr("Save Code"), filter, tr("Header Files (*.%1)").arg(headerSuffix));
+ if (fileName.isEmpty())
+ break;
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) {
+ warning(tr("The file %1 could not be opened: %2").arg(fileName).arg(file.errorString()));
+ continue;
+ }
+ file.write(code().toUtf8());
+ if (!file.flush()) {
+ warning(tr("The file %1 could not be written: %2").arg(fileName).arg(file.errorString()));
+ continue;
+ }
+ file.close();
+ break;
+ }
+}
+
+void CodeDialog::warning(const QString &msg)
+{
+ QMessageBox::warning(
+ this, tr("%1 - Error").arg(windowTitle()),
+ msg, QMessageBox::Close);
+}
+
+void CodeDialog::copyAll()
+{
+ QApplication::clipboard()->setText(code());
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/codedialog_p.h b/tools/designer/src/lib/shared/codedialog_p.h
new file mode 100644
index 0000000..89f5fa9
--- /dev/null
+++ b/tools/designer/src/lib/shared/codedialog_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 CODEPREVIEWDIALOG_H
+#define CODEPREVIEWDIALOG_H
+
+#include "shared_global_p.h"
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+namespace qdesigner_internal {
+// Dialog for viewing code.
+class QDESIGNER_SHARED_EXPORT CodeDialog : public QDialog
+{
+ Q_OBJECT
+ explicit CodeDialog(QWidget *parent = 0);
+public:
+ virtual ~CodeDialog();
+
+ static bool generateCode(const QDesignerFormWindowInterface *fw,
+ QString *code,
+ QString *errorMessage);
+
+ static bool showCodeDialog(const QDesignerFormWindowInterface *fw,
+ QWidget *parent,
+ QString *errorMessage);
+
+private slots:
+ void slotSaveAs();
+ void copyAll();
+
+private:
+ void setCode(const QString &code);
+ QString code() const;
+ void setFormFileName(const QString &f);
+ QString formFileName() const;
+
+ void warning(const QString &msg);
+
+ struct CodeDialogPrivate;
+ CodeDialogPrivate *m_impl;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // CODEPREVIEWDIALOG_H
diff --git a/tools/designer/src/lib/shared/connectionedit.cpp b/tools/designer/src/lib/shared/connectionedit.cpp
new file mode 100644
index 0000000..579a59e
--- /dev/null
+++ b/tools/designer/src/lib/shared/connectionedit.cpp
@@ -0,0 +1,1612 @@
+/****************************************************************************
+**
+** 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 "connectionedit_p.h"
+
+#include <QtDesigner/abstractformwindow.h>
+
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QFontMetrics>
+#include <QtGui/QPixmap>
+#include <QtGui/QMatrix>
+#include <QtGui/QApplication>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+#include <QtCore/QMultiMap>
+
+QT_BEGIN_NAMESPACE
+
+static const int BG_ALPHA = 32;
+static const int LINE_PROXIMITY_RADIUS = 3;
+static const int LOOP_MARGIN = 20;
+static const int VLABEL_MARGIN = 1;
+static const int HLABEL_MARGIN = 3;
+static const int GROUND_W = 20;
+static const int GROUND_H = 25;
+
+/*******************************************************************************
+** Tools
+*/
+
+static QRect fixRect(const QRect &r)
+{
+ return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1);
+}
+
+static QRect expand(const QRect &r, int i)
+{
+ return QRect(r.x() - i, r.y() - i, r.width() + 2*i, r.height() + 2*i);
+}
+
+static QRect endPointRectHelper(const QPoint &pos)
+{
+ const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),
+ QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));
+ return r;
+}
+
+static void paintGround(QPainter *p, QRect r)
+{
+ const QPoint mid = r.center();
+ p->drawLine(mid.x(), r.top(), mid.x(), mid.y());
+ p->drawLine(r.left(), mid.y(), r.right(), mid.y());
+ int y = r.top() + 4*r.height()/6;
+ int x = GROUND_W/6;
+ p->drawLine(r.left() + x, y, r.right() - x, y);
+ y = r.top() + 5*r.height()/6;
+ x = 2*GROUND_W/6;
+ p->drawLine(r.left() + x, y, r.right() - x, y);
+ p->drawLine(mid.x(), r.bottom(), mid.x() + 1, r.bottom());
+}
+
+static void paintEndPoint(QPainter *p, const QPoint &pos)
+{
+ const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),
+ QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));
+ p->fillRect(fixRect(r), p->pen().color());
+}
+
+static qdesigner_internal::CETypes::LineDir classifyLine(const QPoint &p1, const QPoint &p2)
+{
+ if (p1.x() == p2.x())
+ return p1.y() < p2.y() ? qdesigner_internal::CETypes::DownDir : qdesigner_internal::CETypes::UpDir;
+ Q_ASSERT(p1.y() == p2.y());
+ return p1.x() < p2.x() ? qdesigner_internal::CETypes::RightDir : qdesigner_internal::CETypes::LeftDir;
+}
+
+static QPoint pointInsideRect(const QRect &r, QPoint p)
+{
+ if (p.x() < r.left())
+ p.setX(r.left());
+ else if (p.x() > r.right())
+ p.setX(r.right());
+
+ if (p.y() < r.top())
+ p.setY(r.top());
+ else if (p.y() > r.bottom())
+ p.setY(r.bottom());
+
+ return p;
+}
+
+namespace qdesigner_internal {
+
+/*******************************************************************************
+** Commands
+*/
+
+AddConnectionCommand::AddConnectionCommand(ConnectionEdit *edit, Connection *con)
+ : CECommand(edit), m_con(con)
+{
+ setText(QApplication::translate("Command", "Add connection"));
+}
+
+void AddConnectionCommand::redo()
+{
+ edit()->selectNone();
+ emit edit()->aboutToAddConnection(edit()->m_con_list.size());
+ edit()->m_con_list.append(m_con);
+ m_con->inserted();
+ edit()->setSelected(m_con, true);
+ emit edit()->connectionAdded(m_con);
+}
+
+void AddConnectionCommand::undo()
+{
+ const int idx = edit()->indexOfConnection(m_con);
+ emit edit()->aboutToRemoveConnection(m_con);
+ edit()->setSelected(m_con, false);
+ m_con->update();
+ m_con->removed();
+ edit()->m_con_list.removeAll(m_con);
+ emit edit()->connectionRemoved(idx);
+}
+
+class AdjustConnectionCommand : public CECommand
+{
+public:
+ AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,
+ const QPoint &old_source_pos,
+ const QPoint &old_target_pos,
+ const QPoint &new_source_pos,
+ const QPoint &new_target_pos);
+ virtual void redo();
+ virtual void undo();
+private:
+ Connection *m_con;
+ const QPoint m_old_source_pos;
+ const QPoint m_old_target_pos;
+ const QPoint m_new_source_pos;
+ const QPoint m_new_target_pos;
+};
+
+AdjustConnectionCommand::AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,
+ const QPoint &old_source_pos,
+ const QPoint &old_target_pos,
+ const QPoint &new_source_pos,
+ const QPoint &new_target_pos) :
+ CECommand(edit),
+ m_con(con),
+ m_old_source_pos(old_source_pos),
+ m_old_target_pos(old_target_pos),
+ m_new_source_pos(new_source_pos),
+ m_new_target_pos(new_target_pos)
+{
+ setText(QApplication::translate("Command", "Adjust connection"));
+}
+
+void AdjustConnectionCommand::undo()
+{
+ m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_old_source_pos);
+ m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_old_target_pos);
+}
+
+void AdjustConnectionCommand::redo()
+{
+ m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_new_source_pos);
+ m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_new_target_pos);
+}
+
+DeleteConnectionsCommand::DeleteConnectionsCommand(ConnectionEdit *edit,
+ const ConnectionList &con_list)
+ : CECommand(edit), m_con_list(con_list)
+{
+ setText(QApplication::translate("Command", "Delete connections"));
+}
+
+void DeleteConnectionsCommand::redo()
+{
+ foreach (Connection *con, m_con_list) {
+ const int idx = edit()->indexOfConnection(con);
+ emit edit()->aboutToRemoveConnection(con);
+ Q_ASSERT(edit()->m_con_list.contains(con));
+ edit()->setSelected(con, false);
+ con->update();
+ con->removed();
+ edit()->m_con_list.removeAll(con);
+ emit edit()->connectionRemoved(idx);
+ }
+}
+
+void DeleteConnectionsCommand::undo()
+{
+ foreach (Connection *con, m_con_list) {
+ Q_ASSERT(!edit()->m_con_list.contains(con));
+ emit edit()->aboutToAddConnection(edit()->m_con_list.size());
+ edit()->m_con_list.append(con);
+ edit()->setSelected(con, true);
+ con->update();
+ con->inserted();
+ emit edit()->connectionAdded(con);
+ }
+}
+
+class SetEndPointCommand : public CECommand
+{
+public:
+ SetEndPointCommand(ConnectionEdit *edit, Connection *con, EndPoint::Type type, QObject *object);
+ virtual void redo();
+ virtual void undo();
+private:
+ Connection *m_con;
+ const EndPoint::Type m_type;
+ QObject *m_old_widget, *m_new_widget;
+ const QPoint m_old_pos;
+ QPoint m_new_pos;
+};
+
+SetEndPointCommand::SetEndPointCommand(ConnectionEdit *edit, Connection *con,
+ EndPoint::Type type, QObject *object) :
+ CECommand(edit),
+ m_con(con),
+ m_type(type),
+ m_old_widget(con->object(type)),
+ m_new_widget(object),
+ m_old_pos(con->endPointPos(type))
+{
+ if (QWidget *widget = qobject_cast<QWidget*>(object)) {
+ m_new_pos = edit->widgetRect(widget).center();
+ }
+
+ if (m_type == EndPoint::Source)
+ setText(QApplication::translate("Command", "Change source"));
+ else
+ setText(QApplication::translate("Command", "Change target"));
+}
+
+void SetEndPointCommand::redo()
+{
+ m_con->setEndPoint(m_type, m_new_widget, m_new_pos);
+ emit edit()->connectionChanged(m_con);
+}
+
+void SetEndPointCommand::undo()
+{
+ m_con->setEndPoint(m_type, m_old_widget, m_old_pos);
+ emit edit()->connectionChanged(m_con);
+}
+
+/*******************************************************************************
+** Connection
+*/
+
+Connection::Connection(ConnectionEdit *edit) :
+ m_source_pos(QPoint(-1, -1)),
+ m_target_pos(QPoint(-1, -1)),
+ m_source(0),
+ m_target(0),
+ m_edit(edit),
+ m_visible(true)
+{
+
+}
+
+Connection::Connection(ConnectionEdit *edit, QObject *source, QObject *target) :
+ m_source_pos(QPoint(-1, -1)),
+ m_target_pos(QPoint(-1, -1)),
+ m_source(source),
+ m_target(target),
+ m_edit(edit),
+ m_visible(true)
+{
+}
+
+void Connection::setVisible(bool b)
+{
+ m_visible = b;
+}
+
+void Connection::updateVisibility()
+{
+ QWidget *source = widget(EndPoint::Source);
+ QWidget *target = widget(EndPoint::Target);
+
+ if (source == 0 || target == 0) {
+ setVisible(false);
+ return;
+ }
+
+ QWidget *w = source;
+ while (w && w->parentWidget()) {
+ if (!w->isVisibleTo(w->parentWidget())) {
+ setVisible(false);
+ return;
+ }
+ w = w->parentWidget();
+ }
+
+ w = target;
+ while (w && w->parentWidget()) {
+ if (!w->isVisibleTo(w->parentWidget())) {
+ setVisible(false);
+ return;
+ }
+ w = w->parentWidget();
+ }
+
+ setVisible(true);
+}
+
+bool Connection::isVisible() const
+{
+ return m_visible;
+}
+
+bool Connection::ground() const
+{
+ return m_target != 0 && m_target == m_edit->m_bg_widget;
+}
+
+QPoint Connection::endPointPos(EndPoint::Type type) const
+{
+ if (type == EndPoint::Source)
+ return m_source_pos;
+ else
+ return m_target_pos;
+}
+
+static QPoint lineEntryPos(const QPoint &p1, const QPoint &p2, const QRect &rect)
+{
+ QPoint result;
+
+ switch (classifyLine(p1, p2)) {
+ case CETypes::UpDir:
+ result = QPoint(p1.x(), rect.bottom());
+ break;
+ case CETypes::DownDir:
+ result = QPoint(p1.x(), rect.top());
+ break;
+ case CETypes::LeftDir:
+ result = QPoint(rect.right(), p1.y());
+ break;
+ case CETypes::RightDir:
+ result = QPoint(rect.left(), p1.y());
+ break;
+ }
+
+ return result;
+}
+
+static QPolygonF arrowHead(const QPoint &p1, const QPoint &p2)
+{
+ QPolygonF result;
+
+ switch (classifyLine(p1, p2)) {
+ case CETypes::UpDir:
+ result.append(p2 + QPoint(0, 1));
+ result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));
+ result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));
+ break;
+ case CETypes::DownDir:
+ result.append(p2);
+ result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));
+ result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));
+ break;
+ case CETypes::LeftDir:
+ result.append(p2 + QPoint(1, 0));
+ result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, -LINE_PROXIMITY_RADIUS));
+ result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, LINE_PROXIMITY_RADIUS));
+ break;
+ case CETypes::RightDir:
+ result.append(p2);
+ result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS));
+ result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS));
+ break;
+ }
+
+ return result;
+}
+
+static CETypes::LineDir closestEdge(const QPoint &p, const QRect &r)
+{
+ CETypes::LineDir result = CETypes::UpDir;
+ int min = p.y() - r.top();
+
+ int d = p.x() - r.left();
+ if (d < min) {
+ min = d;
+ result = CETypes::LeftDir;
+ }
+
+ d = r.bottom() - p.y();
+ if (d < min) {
+ min = d;
+ result = CETypes::DownDir;
+ }
+
+ d = r.right() - p.x();
+ if (d < min) {
+ min = d;
+ result = CETypes::RightDir;
+ }
+
+ return result;
+}
+
+static bool pointAboveLine(const QPoint &l1, const QPoint &l2, const QPoint &p)
+{
+ if (l1.x() == l2.x())
+ return p.x() >= l1.x();
+ return p.y() <= l1.y() + (p.x() - l1.x())*(l2.y() - l1.y())/(l2.x() - l1.x());
+}
+
+void Connection::updateKneeList()
+{
+ const LineDir old_source_label_dir = labelDir(EndPoint::Source);
+ const LineDir old_target_label_dir = labelDir(EndPoint::Target);
+
+ QPoint s = endPointPos(EndPoint::Source);
+ QPoint t = endPointPos(EndPoint::Target);
+ const QRect sr = m_source_rect;
+ const QRect tr = m_target_rect;
+
+ m_knee_list.clear();
+ m_arrow_head.clear();
+
+ if (m_source == 0 || s == QPoint(-1, -1) || t == QPoint(-1, -1))
+ return;
+
+ const QRect r = sr | tr;
+
+ m_knee_list.append(s);
+ if (m_target == 0) {
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ } else if (m_target == m_edit->m_bg_widget) {
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ } else if (tr.contains(sr) || sr.contains(tr)) {
+/*
+ +------------------+
+ | +----------+ |
+ | | | |
+ | | o | |
+ | +---|------+ |
+ | | x |
+ +-----|-----|------+
+ +-----+
+
+ We find out which edge of the outer rectangle is closest to the target
+ point, and make a loop which exits and re-enters through that edge.
+*/
+ const LineDir dir = closestEdge(t, tr);
+ switch (dir) {
+ case UpDir:
+ m_knee_list.append(QPoint(s.x(), r.top() - LOOP_MARGIN));
+ m_knee_list.append(QPoint(t.x(), r.top() - LOOP_MARGIN));
+ break;
+ case DownDir:
+ m_knee_list.append(QPoint(s.x(), r.bottom() + LOOP_MARGIN));
+ m_knee_list.append(QPoint(t.x(), r.bottom() + LOOP_MARGIN));
+ break;
+ case LeftDir:
+ m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, s.y()));
+ m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, t.y()));
+ break;
+ case RightDir:
+ m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, s.y()));
+ m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, t.y()));
+ break;
+ }
+ } else {
+ if (r.height() < sr.height() + tr.height()) {
+ if ((s.y() >= tr.top() && s.y() <= tr.bottom()) || (t.y() >= sr.bottom() || t.y() <= sr.top())) {
+/*
+ +--------+
+ | | +--------+
+ | o--+---+--x |
+ | o | | |
+ +-----|--+ | |
+ +------+--x |
+ +--------+
+
+ When dragging one end point, move the other end point to the same y position,
+ if that does not cause it to exit it's rectangle.
+*/
+ if (m_edit->state() == ConnectionEdit::Dragging) {
+ if (m_edit->m_drag_end_point.type == EndPoint::Source) {
+ const QPoint p(t.x(), s.y());
+ m_knee_list.append(p);
+ if (tr.contains(p))
+ t = m_target_pos = p;
+ } else {
+ const QPoint p(s.x(), t.y());
+ m_knee_list.append(p);
+ if (sr.contains(p))
+ s = m_source_pos = p;
+ }
+ } else {
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ }
+ } else {
+/*
+ +--------+
+ | o----+-------+
+ | | +---|----+
+ +--------+ | | |
+ | x |
+ +--------+
+*/
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ }
+ } else if (r.width() < sr.width() + tr.width()) {
+ if ((s.x() >= tr.left() && s.x() <= tr.right()) || t.x() >= sr.right() || t.x() <= sr.left()) {
+/*
+ +--------+
+ | |
+ | o o+--+
+ +----|---+ |
+ +-|------|-+
+ | x x |
+ | |
+ +----------+
+
+ When dragging one end point, move the other end point to the same x position,
+ if that does not cause it to exit it's rectangle.
+*/
+ if (m_edit->state() == ConnectionEdit::Dragging) {
+ if (m_edit->m_drag_end_point.type == EndPoint::Source) {
+ const QPoint p(s.x(), t.y());
+ m_knee_list.append(p);
+ if (tr.contains(p))
+ t = m_target_pos = p;
+ } else {
+ const QPoint p(t.x(), s.y());
+ m_knee_list.append(p);
+ if (sr.contains(p))
+ s = m_source_pos = p;
+ }
+ } else {
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ }
+ } else {
+/*
+ +--------+
+ | |
+ | o |
+ +--|-----+
+ | +--------+
+ +---+-x |
+ | |
+ +--------+
+
+*/
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ }
+ } else {
+/*
+ +--------+
+ | |
+ | o o-+--------+
+ +--|-----+ |
+ | +-----|--+
+ | | x |
+ +--------+-x |
+ +--------+
+
+ The line enters the target rectangle through the closest edge.
+*/
+ if (sr.topLeft() == r.topLeft()) {
+ if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t))
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ else
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ } else if (sr.topRight() == r.topRight()) {
+ if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t))
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ else
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ } else if (sr.bottomRight() == r.bottomRight()) {
+ if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t))
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ else
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ } else {
+ if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t))
+ m_knee_list.append(QPoint(s.x(), t.y()));
+ else
+ m_knee_list.append(QPoint(t.x(), s.y()));
+ }
+ }
+ }
+ m_knee_list.append(t);
+
+ if (m_knee_list.size() == 2)
+ m_knee_list.clear();
+
+ trimLine();
+
+ const LineDir new_source_label_dir = labelDir(EndPoint::Source);
+ const LineDir new_target_label_dir = labelDir(EndPoint::Target);
+ if (new_source_label_dir != old_source_label_dir)
+ updatePixmap(EndPoint::Source);
+ if (new_target_label_dir != old_target_label_dir)
+ updatePixmap(EndPoint::Target);
+}
+
+void Connection::trimLine()
+{
+ if (m_source == 0 || m_source_pos == QPoint(-1, -1) || m_target_pos == QPoint(-1, -1))
+ return;
+ int cnt = m_knee_list.size();
+ if (cnt < 2)
+ return;
+
+ const QRect sr = m_source_rect;
+ const QRect tr = m_target_rect;
+
+ if (sr.contains(m_knee_list.at(1)))
+ m_knee_list.removeFirst();
+
+ cnt = m_knee_list.size();
+ if (cnt < 2)
+ return;
+
+ if (!tr.contains(sr) && tr.contains(m_knee_list.at(cnt - 2)))
+ m_knee_list.removeLast();
+
+ cnt = m_knee_list.size();
+ if (cnt < 2)
+ return;
+
+ if (sr.contains(m_knee_list.at(0)) && !sr.contains(m_knee_list.at(1)))
+ m_knee_list[0] = lineEntryPos(m_knee_list.at(1), m_knee_list.at(0), sr);
+
+ if (tr.contains(m_knee_list.at(cnt - 1)) && !tr.contains(m_knee_list.at(cnt - 2))) {
+ m_knee_list[cnt - 1]
+ = lineEntryPos(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1), tr);
+ m_arrow_head = arrowHead(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1));
+ }
+}
+
+void Connection::setSource(QObject *source, const QPoint &pos)
+{
+ if (source == m_source && m_source_pos == pos)
+ return;
+
+ update(false);
+
+ m_source = source;
+ if (QWidget *widget = qobject_cast<QWidget*>(source)) {
+ m_source_pos = pos;
+ m_source_rect = m_edit->widgetRect(widget);
+ updateKneeList();
+ }
+
+ update(false);
+}
+
+void Connection::setTarget(QObject *target, const QPoint &pos)
+{
+ if (target == m_target && m_target_pos == pos)
+ return;
+
+ update(false);
+
+ m_target = target;
+ if (QWidget *widget = qobject_cast<QWidget*>(target)) {
+ m_target_pos = pos;
+ m_target_rect = m_edit->widgetRect(widget);
+ updateKneeList();
+ }
+
+ update(false);
+}
+
+static QRect lineRect(const QPoint &a, const QPoint &b)
+{
+ const QPoint c(qMin(a.x(), b.x()), qMin(a.y(), b.y()));
+ const QPoint d(qMax(a.x(), b.x()), qMax(a.y(), b.y()));
+
+ QRect result(c, d);
+ return expand(result, LINE_PROXIMITY_RADIUS);
+}
+
+QRect Connection::groundRect() const
+{
+ if (!ground())
+ return QRect();
+ if (m_knee_list.isEmpty())
+ return QRect();
+
+ const QPoint p = m_knee_list.last();
+ return QRect(p.x() - GROUND_W/2, p.y(), GROUND_W, GROUND_H);
+}
+
+QRegion Connection::region() const
+{
+ QRegion result;
+
+ for (int i = 0; i < m_knee_list.size() - 1; ++i)
+ result = result.unite(lineRect(m_knee_list.at(i), m_knee_list.at(i + 1)));
+
+ if (!m_arrow_head.isEmpty()) {
+ QRect r = m_arrow_head.boundingRect().toRect();
+ r = expand(r, 1);
+ result = result.unite(r);
+ } else if (ground()) {
+ result = result.unite(groundRect());
+ }
+
+ result = result.unite(labelRect(EndPoint::Source));
+ result = result.unite(labelRect(EndPoint::Target));
+
+ return result;
+}
+
+void Connection::update(bool update_widgets) const
+{
+ m_edit->update(region());
+ if (update_widgets) {
+ if (m_source != 0)
+ m_edit->update(m_source_rect);
+ if (m_target != 0)
+ m_edit->update(m_target_rect);
+ }
+
+ m_edit->update(endPointRect(EndPoint::Source));
+ m_edit->update(endPointRect(EndPoint::Target));
+}
+
+void Connection::paint(QPainter *p) const
+{
+ for (int i = 0; i < m_knee_list.size() - 1; ++i)
+ p->drawLine(m_knee_list.at(i), m_knee_list.at(i + 1));
+
+ if (!m_arrow_head.isEmpty()) {
+ p->save();
+ p->setBrush(p->pen().color());
+ p->drawPolygon(m_arrow_head);
+ p->restore();
+ } else if (ground()) {
+ paintGround(p, groundRect());
+ }
+}
+
+bool Connection::contains(const QPoint &pos) const
+{
+ return region().contains(pos);
+}
+
+QRect Connection::endPointRect(EndPoint::Type type) const
+{
+ if (type == EndPoint::Source) {
+ if (m_source_pos != QPoint(-1, -1))
+ return endPointRectHelper(m_source_pos);
+ } else {
+ if (m_target_pos != QPoint(-1, -1))
+ return endPointRectHelper(m_target_pos);
+ }
+ return QRect();
+}
+
+CETypes::LineDir Connection::labelDir(EndPoint::Type type) const
+{
+ const int cnt = m_knee_list.size();
+ if (cnt < 2)
+ return RightDir;
+
+ LineDir dir;
+ if (type == EndPoint::Source)
+ dir = classifyLine(m_knee_list.at(0), m_knee_list.at(1));
+ else
+ dir = classifyLine(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1));
+
+ if (dir == LeftDir)
+ dir = RightDir;
+ if (dir == UpDir)
+ dir = DownDir;
+
+ return dir;
+}
+
+QRect Connection::labelRect(EndPoint::Type type) const
+{
+ const int cnt = m_knee_list.size();
+ if (cnt < 2)
+ return QRect();
+ const QString text = label(type);
+ if (text.isEmpty())
+ return QRect();
+
+ const QSize size = labelPixmap(type).size();
+ QPoint p1, p2;
+ if (type == EndPoint::Source) {
+ p1 = m_knee_list.at(0);
+ p2 = m_knee_list.at(1);
+ } else {
+ p1 = m_knee_list.at(cnt - 1);
+ p2 = m_knee_list.at(cnt - 2);
+ }
+ const LineDir dir = classifyLine(p1, p2);
+
+ QRect result;
+ switch (dir) {
+ case UpDir:
+ result = QRect(p1 + QPoint(-size.width()/2, 0), size);
+ break;
+ case DownDir:
+ result = QRect(p1 + QPoint(-size.width()/2, -size.height()), size);
+ break;
+ case LeftDir:
+ result = QRect(p1 + QPoint(0, -size.height()/2), size);
+ break;
+ case RightDir:
+ result = QRect(p1 + QPoint(-size.width(), -size.height()/2), size);
+ break;
+ }
+
+ return result;
+}
+
+void Connection::setLabel(EndPoint::Type type, const QString &text)
+{
+ if (text == label(type))
+ return;
+
+ if (type == EndPoint::Source)
+ m_source_label = text;
+ else
+ m_target_label = text;
+
+ updatePixmap(type);
+}
+
+void Connection::updatePixmap(EndPoint::Type type)
+{
+ QPixmap *pm = type == EndPoint::Source ? &m_source_label_pm : &m_target_label_pm;
+
+ const QString text = label(type);
+ if (text.isEmpty()) {
+ *pm = QPixmap();
+ return;
+ }
+
+ const QFontMetrics fm = m_edit->fontMetrics();
+ const QSize size = fm.size(Qt::TextSingleLine, text) + QSize(HLABEL_MARGIN*2, VLABEL_MARGIN*2);
+ *pm = QPixmap(size);
+ QColor color = m_edit->palette().color(QPalette::Normal, QPalette::Base);
+ color.setAlpha(190);
+ pm->fill(color);
+
+ QPainter p(pm);
+ p.setPen(m_edit->palette().color(QPalette::Normal, QPalette::Text));
+ p.drawText(-fm.leftBearing(text.at(0)) + HLABEL_MARGIN, fm.ascent() + VLABEL_MARGIN, text);
+ p.end();
+
+ const LineDir dir = labelDir(type);
+
+ if (dir == DownDir)
+ *pm = pm->transformed(QMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0));
+}
+
+void Connection::checkWidgets()
+{
+ bool changed = false;
+
+ if (QWidget *sourceWidget = qobject_cast<QWidget*>(m_source)) {
+ const QRect r = m_edit->widgetRect(sourceWidget);
+ if (r != m_source_rect) {
+ if (m_source_pos != QPoint(-1, -1) && !r.contains(m_source_pos)) {
+ QPoint offset = m_source_pos - m_source_rect.topLeft();
+ QPoint old_pos = m_source_pos;
+ m_source_pos = pointInsideRect(r, r.topLeft() + offset);
+ }
+ m_edit->update(m_source_rect);
+ m_source_rect = r;
+ changed = true;
+ }
+ }
+
+ if (QWidget *targetWidget = qobject_cast<QWidget*>(m_target)) {
+ const QRect r = m_edit->widgetRect(targetWidget);
+ if (r != m_target_rect) {
+ if (m_target_pos != QPoint(-1, -1) && !r.contains(m_target_pos)) {
+ const QPoint offset = m_target_pos - m_target_rect.topLeft();
+ const QPoint old_pos = m_target_pos;
+ m_target_pos = pointInsideRect(r, r.topLeft() + offset);
+ }
+ m_edit->update(m_target_rect);
+ m_target_rect = r;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ update();
+ updateKneeList();
+ update();
+ }
+}
+
+/*******************************************************************************
+** ConnectionEdit
+*/
+
+ConnectionEdit::ConnectionEdit(QWidget *parent, QDesignerFormWindowInterface *form) :
+ QWidget(parent),
+ m_bg_widget(0),
+ m_undo_stack(form->commandHistory()),
+ m_enable_update_background(false),
+ m_tmp_con(0),
+ m_start_connection_on_drag(true),
+ m_widget_under_mouse(0),
+ m_inactive_color(Qt::blue),
+ m_active_color(Qt::red)
+{
+ setAttribute(Qt::WA_MouseTracking, true);
+ setFocusPolicy(Qt::ClickFocus);
+
+ connect(form, SIGNAL(widgetRemoved(QWidget*)), this, SLOT(widgetRemoved(QWidget*)));
+ connect(form, SIGNAL(objectRemoved(QObject*)), this, SLOT(objectRemoved(QObject*)));
+}
+
+ConnectionEdit::~ConnectionEdit()
+{
+ qDeleteAll(m_con_list);
+}
+
+void ConnectionEdit::clear()
+{
+ m_con_list.clear();
+ m_sel_con_set.clear();
+ m_bg_widget = 0;
+ m_widget_under_mouse = 0;
+ m_tmp_con = 0;
+}
+
+void ConnectionEdit::setBackground(QWidget *background)
+{
+ if (background == m_bg_widget) {
+ // nothing to do
+ return;
+ }
+
+ m_bg_widget = background;
+ updateBackground();
+}
+
+void ConnectionEdit::enableUpdateBackground(bool enable)
+{
+ m_enable_update_background = enable;
+ if (enable)
+ updateBackground();
+}
+
+void ConnectionEdit::updateBackground()
+{
+ // Might happen while reloading a form.
+ if (m_bg_widget == 0)
+ return;
+
+ if (!m_enable_update_background)
+ return;
+
+ foreach(Connection *c, m_con_list)
+ c->updateVisibility();
+
+ updateLines();
+ update();
+}
+
+QWidget *ConnectionEdit::widgetAt(const QPoint &pos) const
+{
+ if (m_bg_widget == 0)
+ return 0;
+ QWidget *widget = m_bg_widget->childAt(pos);
+ if (widget == 0)
+ widget = m_bg_widget;
+
+ return widget;
+}
+
+
+QRect ConnectionEdit::widgetRect(QWidget *w) const
+{
+ if (w == 0)
+ return QRect();
+ QRect r = w->geometry();
+ QPoint pos = w->mapToGlobal(QPoint(0, 0));
+ pos = mapFromGlobal(pos);
+ r.moveTopLeft(pos);
+ return r;
+}
+
+ConnectionEdit::State ConnectionEdit::state() const
+{
+ if (m_tmp_con != 0)
+ return Connecting;
+ if (!m_drag_end_point.isNull())
+ return Dragging;
+ return Editing;
+}
+
+void ConnectionEdit::paintLabel(QPainter *p, EndPoint::Type type, Connection *con)
+{
+ if (con->label(type).isEmpty())
+ return;
+
+ const bool heavy = selected(con) || con == m_tmp_con;
+ p->setPen(heavy ? m_active_color : m_inactive_color);
+ p->setBrush(Qt::NoBrush);
+ const QRect r = con->labelRect(type);
+ p->drawPixmap(r.topLeft(), con->labelPixmap(type));
+ p->drawRect(fixRect(r));
+}
+
+void ConnectionEdit::paintConnection(QPainter *p, Connection *con,
+ WidgetSet *heavy_highlight_set,
+ WidgetSet *light_highlight_set) const
+{
+ QWidget *source = con->widget(EndPoint::Source);
+ QWidget *target = con->widget(EndPoint::Target);
+
+ const bool heavy = selected(con) || con == m_tmp_con;
+ WidgetSet *set = heavy ? heavy_highlight_set : light_highlight_set;
+ p->setPen(heavy ? m_active_color : m_inactive_color);
+ con->paint(p);
+
+ if (source != 0 && source != m_bg_widget)
+ set->insert(source, source);
+
+ if (target != 0 && target != m_bg_widget)
+ set->insert(target, target);
+}
+
+void ConnectionEdit::paintEvent(QPaintEvent *e)
+{
+ QPainter p(this);
+ p.setClipRegion(e->region());
+
+ WidgetSet heavy_highlight_set, light_highlight_set;
+
+ foreach (Connection *con, m_con_list) {
+ if (!con->isVisible())
+ continue;
+
+ paintConnection(&p, con, &heavy_highlight_set, &light_highlight_set);
+ }
+
+ if (m_tmp_con != 0)
+ paintConnection(&p, m_tmp_con, &heavy_highlight_set, &light_highlight_set);
+
+ if (!m_widget_under_mouse.isNull() && m_widget_under_mouse != m_bg_widget)
+ heavy_highlight_set.insert(m_widget_under_mouse, m_widget_under_mouse);
+
+ QColor c = m_active_color;
+ p.setPen(c);
+ c.setAlpha(BG_ALPHA);
+ p.setBrush(c);
+
+ foreach (QWidget *w, heavy_highlight_set) {
+ p.drawRect(fixRect(widgetRect(w)));
+ light_highlight_set.remove(w);
+ }
+
+ c = m_inactive_color;
+ p.setPen(c);
+ c.setAlpha(BG_ALPHA);
+ p.setBrush(c);
+
+ foreach (QWidget *w, light_highlight_set)
+ p.drawRect(fixRect(widgetRect(w)));
+
+ p.setBrush(palette().color(QPalette::Base));
+ p.setPen(palette().color(QPalette::Text));
+ foreach (Connection *con, m_con_list) {
+ if (!con->isVisible())
+ continue;
+
+ paintLabel(&p, EndPoint::Source, con);
+ paintLabel(&p, EndPoint::Target, con);
+ }
+
+ p.setPen(m_active_color);
+ p.setBrush(m_active_color);
+
+ foreach (Connection *con, m_con_list) {
+ if (!selected(con) || !con->isVisible())
+ continue;
+
+ paintEndPoint(&p, con->endPointPos(EndPoint::Source));
+
+ if (con->widget(EndPoint::Target) != 0)
+ paintEndPoint(&p, con->endPointPos(EndPoint::Target));
+ }
+}
+
+void ConnectionEdit::abortConnection()
+{
+ m_tmp_con->update();
+ delete m_tmp_con;
+ m_tmp_con = 0;
+#ifndef QT_NO_CURSOR
+ setCursor(QCursor());
+#endif
+ if (m_widget_under_mouse == m_bg_widget)
+ m_widget_under_mouse = 0;
+}
+
+void ConnectionEdit::mousePressEvent(QMouseEvent *e)
+{
+ // Right click only to cancel
+ const Qt::MouseButton button = e->button();
+ const State cstate = state();
+ if (button != Qt::LeftButton && !(button == Qt::RightButton && cstate == Connecting)) {
+ QWidget::mousePressEvent(e);
+ return;
+ }
+
+ e->accept();
+ // Prefer a non-background widget over the connection,
+ // otherwise, widgets covered by the connection labels cannot be accessed
+ Connection *con_under_mouse = 0;
+ if (!m_widget_under_mouse || m_widget_under_mouse == m_bg_widget)
+ con_under_mouse = connectionAt(e->pos());
+
+ m_start_connection_on_drag = false;
+ switch (cstate) {
+ case Connecting:
+ if (button == Qt::RightButton)
+ abortConnection();
+ break;
+ case Dragging:
+ break;
+ case Editing:
+ if (!m_end_point_under_mouse.isNull()) {
+ if (!(e->modifiers() & Qt::ShiftModifier)) {
+ startDrag(m_end_point_under_mouse, e->pos());
+ }
+ } else if (con_under_mouse != 0) {
+ if (!(e->modifiers() & Qt::ShiftModifier)) {
+ selectNone();
+ setSelected(con_under_mouse, true);
+ } else {
+ setSelected(con_under_mouse, !selected(con_under_mouse));
+ }
+ } else {
+ if (!(e->modifiers() & Qt::ShiftModifier)) {
+ selectNone();
+ if (!m_widget_under_mouse.isNull())
+ m_start_connection_on_drag = true;
+ }
+ }
+ break;
+ }
+}
+
+void ConnectionEdit::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ if (e->button() != Qt::LeftButton) {
+ QWidget::mouseDoubleClickEvent(e);
+ return;
+ }
+
+ e->accept();
+ switch (state()) {
+ case Connecting:
+ abortConnection();
+ break;
+ case Dragging:
+ break;
+ case Editing:
+ if (!m_widget_under_mouse.isNull()) {
+ emit widgetActivated(m_widget_under_mouse);
+ } else if (m_sel_con_set.size() == 1) {
+ Connection *con = m_sel_con_set.keys().first();
+ modifyConnection(con);
+ }
+ break;
+ }
+
+}
+
+void ConnectionEdit::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() != Qt::LeftButton) {
+ QWidget::mouseReleaseEvent(e);
+ return;
+ }
+ e->accept();
+
+ switch (state()) {
+ case Connecting:
+ if (m_widget_under_mouse.isNull())
+ abortConnection();
+ else
+ endConnection(m_widget_under_mouse, e->pos());
+#ifndef QT_NO_CURSOR
+ setCursor(QCursor());
+#endif
+ break;
+ case Editing:
+ break;
+ case Dragging:
+ endDrag(e->pos());
+ break;
+ }
+}
+
+
+void ConnectionEdit::findObjectsUnderMouse(const QPoint &pos)
+{
+ Connection *con_under_mouse = connectionAt(pos);
+
+ QWidget *w = widgetAt(pos);
+ // Prefer a non-background widget over the connection,
+ // otherwise, widgets covered by the connection labels cannot be accessed
+ if (w == m_bg_widget && con_under_mouse)
+ w = 0;
+ else
+ con_under_mouse = 0;
+
+ if (w != m_widget_under_mouse) {
+ if (!m_widget_under_mouse.isNull())
+ update(widgetRect(m_widget_under_mouse));
+ m_widget_under_mouse = w;
+ if (!m_widget_under_mouse.isNull())
+ update(widgetRect(m_widget_under_mouse));
+ }
+
+ const EndPoint hs = endPointAt(pos);
+ if (hs != m_end_point_under_mouse) {
+#ifndef QT_NO_CURSOR
+ if (m_end_point_under_mouse.isNull())
+ setCursor(Qt::PointingHandCursor);
+ else
+ setCursor(QCursor());
+#endif
+ m_end_point_under_mouse = hs;
+ }
+}
+
+void ConnectionEdit::mouseMoveEvent(QMouseEvent *e)
+{
+ findObjectsUnderMouse(e->pos());
+ switch (state()) {
+ case Connecting:
+ continueConnection(m_widget_under_mouse, e->pos());
+ break;
+ case Editing:
+ if ((e->buttons() & Qt::LeftButton)
+ && m_start_connection_on_drag
+ && !m_widget_under_mouse.isNull()) {
+ m_start_connection_on_drag = false;
+ startConnection(m_widget_under_mouse, e->pos());
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::CrossCursor);
+#endif
+ }
+ break;
+ case Dragging:
+ continueDrag(e->pos());
+ break;
+ }
+
+ e->accept();
+}
+
+void ConnectionEdit::keyPressEvent(QKeyEvent *e)
+{
+ switch (e->key()) {
+ case Qt::Key_Delete:
+ if (state() == Editing)
+ deleteSelected();
+ break;
+ case Qt::Key_Escape:
+ if (state() == Connecting)
+ abortConnection();
+ break;
+ }
+
+ e->accept();
+}
+
+void ConnectionEdit::startConnection(QWidget *source, const QPoint &pos)
+{
+ Q_ASSERT(m_tmp_con == 0);
+
+ m_tmp_con = new Connection(this);
+ m_tmp_con->setEndPoint(EndPoint::Source, source, pos);
+}
+
+void ConnectionEdit::endConnection(QWidget *target, const QPoint &pos)
+{
+ Q_ASSERT(m_tmp_con != 0);
+
+ m_tmp_con->setEndPoint(EndPoint::Target, target, pos);
+
+ QWidget *source = m_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, m_tmp_con->endPointPos(EndPoint::Source));
+ new_con->setEndPoint(EndPoint::Target, target, m_tmp_con->endPointPos(EndPoint::Target));
+ m_undo_stack->push(new AddConnectionCommand(this, new_con));
+ emit connectionChanged(new_con);
+ }
+
+ delete m_tmp_con;
+ m_tmp_con = 0;
+
+ findObjectsUnderMouse(mapFromGlobal(QCursor::pos()));
+}
+
+void ConnectionEdit::continueConnection(QWidget *target, const QPoint &pos)
+{
+ Q_ASSERT(m_tmp_con != 0);
+
+ m_tmp_con->setEndPoint(EndPoint::Target, target, pos);
+}
+
+void ConnectionEdit::modifyConnection(Connection *)
+{
+}
+
+Connection *ConnectionEdit::createConnection(QWidget *source, QWidget *target)
+{
+ Connection *con = new Connection(this, source, target);
+ return con;
+}
+
+// Find all connections which in which a sequence of objects is involved
+template <class ObjectIterator>
+static ConnectionEdit::ConnectionSet findConnectionsOf(const ConnectionEdit::ConnectionList &cl, ObjectIterator oi1, const ObjectIterator &oi2)
+{
+ ConnectionEdit::ConnectionSet rc;
+
+ const ConnectionEdit::ConnectionList::const_iterator ccend = cl.constEnd();
+ for ( ; oi1 != oi2; ++oi1) {
+ for (ConnectionEdit::ConnectionList::const_iterator cit = cl.constBegin(); cit != ccend; ++cit) {
+ Connection *con = *cit;
+ if (con->object(ConnectionEdit::EndPoint::Source) == *oi1 || con->object(ConnectionEdit::EndPoint::Target) == *oi1)
+ rc.insert(con, con);
+ }
+ }
+ return rc;
+}
+
+void ConnectionEdit::widgetRemoved(QWidget *widget)
+{
+ // Remove all connections of that widget and its children.
+ if (m_con_list.empty())
+ return;
+
+ QWidgetList child_list = qFindChildren<QWidget*>(widget);
+ child_list.prepend(widget);
+
+ const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd());
+
+ if (!remove_set.isEmpty())
+ m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys()));
+
+ updateBackground();
+}
+
+void ConnectionEdit::objectRemoved(QObject *o)
+{
+ // Remove all connections of that object and its children (in case of action groups).
+ if (m_con_list.empty())
+ return;
+
+ QObjectList child_list = o->children();
+ child_list.prepend(o);
+ const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd());
+ if (!remove_set.isEmpty())
+ m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys()));
+
+ updateBackground();
+}
+
+void ConnectionEdit::setSelected(Connection *con, bool sel)
+{
+ if (!con || sel == m_sel_con_set.contains(con))
+ return;
+
+ if (sel) {
+ m_sel_con_set.insert(con, con);
+ emit connectionSelected(con);
+ } else {
+ m_sel_con_set.remove(con);
+ }
+
+ con->update();
+}
+
+bool ConnectionEdit::selected(const Connection *con) const
+{
+ return m_sel_con_set.contains(const_cast<Connection*>(con));
+}
+
+void ConnectionEdit::selectNone()
+{
+ foreach (Connection *con, m_sel_con_set)
+ con->update();
+
+ m_sel_con_set.clear();
+}
+
+void ConnectionEdit::selectAll()
+{
+ if (m_sel_con_set.size() == m_con_list.size())
+ return;
+ foreach (Connection *con, m_con_list)
+ setSelected(con, true);
+}
+
+Connection *ConnectionEdit::connectionAt(const QPoint &pos) const
+{
+ foreach (Connection *con, m_con_list) {
+ if (con->contains(pos))
+ return con;
+ }
+ return 0;
+}
+
+CETypes::EndPoint ConnectionEdit::endPointAt(const QPoint &pos) const
+{
+ foreach (Connection *con, m_con_list) {
+ if (!selected(con))
+ continue;
+ const QRect sr = con->endPointRect(EndPoint::Source);
+ const QRect tr = con->endPointRect(EndPoint::Target);
+
+ if (sr.contains(pos))
+ return EndPoint(con, EndPoint::Source);
+ if (tr.contains(pos))
+ return EndPoint(con, EndPoint::Target);
+ }
+ return EndPoint();
+}
+
+void ConnectionEdit::startDrag(const EndPoint &end_point, const QPoint &pos)
+{
+ Q_ASSERT(m_drag_end_point.isNull());
+ m_drag_end_point = end_point;
+ m_old_source_pos = m_drag_end_point.con->endPointPos(EndPoint::Source);
+ m_old_target_pos = m_drag_end_point.con->endPointPos(EndPoint::Target);
+ adjustHotSopt(m_drag_end_point, pos);
+}
+
+void ConnectionEdit::continueDrag(const QPoint &pos)
+{
+ Q_ASSERT(!m_drag_end_point.isNull());
+ adjustHotSopt(m_drag_end_point, pos);
+}
+
+void ConnectionEdit::endDrag(const QPoint &pos)
+{
+ Q_ASSERT(!m_drag_end_point.isNull());
+ adjustHotSopt(m_drag_end_point, pos);
+
+ Connection *con = m_drag_end_point.con;
+ const QPoint new_source_pos = con->endPointPos(EndPoint::Source);
+ const QPoint new_target_pos = con->endPointPos(EndPoint::Target);
+ m_undo_stack->push(new AdjustConnectionCommand(this, con, m_old_source_pos, m_old_target_pos,
+ new_source_pos, new_target_pos));
+
+ m_drag_end_point = EndPoint();
+}
+
+void ConnectionEdit::adjustHotSopt(const EndPoint &end_point, const QPoint &pos)
+{
+ QWidget *w = end_point.con->widget(end_point.type);
+ end_point.con->setEndPoint(end_point.type, w, pointInsideRect(widgetRect(w), pos));
+}
+
+void ConnectionEdit::deleteSelected()
+{
+ if (m_sel_con_set.isEmpty())
+ return;
+ m_undo_stack->push(new DeleteConnectionsCommand(this, m_sel_con_set.keys()));
+}
+
+void ConnectionEdit::addConnection(Connection *con)
+{
+ m_con_list.append(con);
+}
+
+void ConnectionEdit::updateLines()
+{
+ foreach (Connection *con, m_con_list)
+ con->checkWidgets();
+}
+
+void ConnectionEdit::resizeEvent(QResizeEvent *e)
+{
+ updateBackground();
+ QWidget::resizeEvent(e);
+}
+
+void ConnectionEdit::setSource(Connection *con, const QString &obj_name)
+{
+ QObject *object = 0;
+ if (!obj_name.isEmpty()) {
+ object = qFindChild<QObject*>(m_bg_widget, obj_name);
+ if (object == 0 && m_bg_widget->objectName() == obj_name)
+ object = m_bg_widget;
+
+ if (object == con->object(EndPoint::Source))
+ return;
+ }
+ m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Source, object));
+}
+
+void ConnectionEdit::setTarget(Connection *con, const QString &obj_name)
+{
+ QObject *object = 0;
+ if (!obj_name.isEmpty()) {
+ object = qFindChild<QObject*>(m_bg_widget, obj_name);
+ if (object == 0 && m_bg_widget->objectName() == obj_name)
+ object = m_bg_widget;
+
+ if (object == con->object(EndPoint::Target))
+ return;
+ }
+ m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Target, object));
+}
+
+Connection *ConnectionEdit::takeConnection(Connection *con)
+{
+ if (!m_con_list.contains(con))
+ return 0;
+ m_con_list.removeAll(con);
+ return con;
+}
+
+void ConnectionEdit::clearNewlyAddedConnection()
+{
+ delete m_tmp_con;
+ m_tmp_con = 0;
+}
+
+void ConnectionEdit::createContextMenu(QMenu &menu)
+{
+ // Select
+ QAction *selectAllAction = menu.addAction(tr("Select All"));
+ selectAllAction->setEnabled(connectionList().size());
+ connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
+ QAction *deselectAllAction = menu.addAction(tr("Deselect All"));
+ deselectAllAction->setEnabled(selection().size());
+ connect(deselectAllAction, SIGNAL(triggered()), this, SLOT(selectNone()));
+ menu.addSeparator();
+ // Delete
+ QAction *deleteAction = menu.addAction(tr("Delete"));
+ deleteAction->setShortcut(QKeySequence::Delete);
+ deleteAction->setEnabled(!selection().isEmpty());
+ connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteSelected()));
+}
+
+void ConnectionEdit::contextMenuEvent(QContextMenuEvent * event)
+{
+ QMenu menu;
+ createContextMenu(menu);
+ menu.exec(event->globalPos());
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/connectionedit_p.h b/tools/designer/src/lib/shared/connectionedit_p.h
new file mode 100644
index 0000000..c4f735a
--- /dev/null
+++ b/tools/designer/src/lib/shared/connectionedit_p.h
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** 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 CONNECTIONEDIT_H
+#define CONNECTIONEDIT_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QMultiMap>
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+
+#include <QtGui/QWidget>
+#include <QtGui/QPixmap>
+#include <QtGui/QPolygonF>
+
+#include <QtGui/QUndoCommand>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QUndoStack;
+class QMenu;
+
+namespace qdesigner_internal {
+
+class Connection;
+class ConnectionEdit;
+
+class QDESIGNER_SHARED_EXPORT CETypes
+{
+public:
+ typedef QList<Connection*> ConnectionList;
+ typedef QMap<Connection*, Connection*> ConnectionSet;
+ typedef QMap<QWidget*, QWidget*> WidgetSet;
+
+ class EndPoint {
+ public:
+ enum Type { Source, Target };
+ EndPoint(Connection *_con = 0, Type _type = Source) : con(_con), type(_type) {}
+ bool isNull() const { return con == 0; }
+ bool operator == (const EndPoint &other) const { return con == other.con && type == other.type; }
+ bool operator != (const EndPoint &other) const { return !operator == (other); }
+ Connection *con;
+ Type type;
+ };
+ enum LineDir { UpDir = 0, DownDir, RightDir, LeftDir };
+};
+
+class QDESIGNER_SHARED_EXPORT Connection : public CETypes
+{
+public:
+ explicit Connection(ConnectionEdit *edit);
+ explicit Connection(ConnectionEdit *edit, QObject *source, QObject *target);
+ virtual ~Connection() {}
+
+ QObject *object(EndPoint::Type type) const
+ {
+ return (type == EndPoint::Source ? m_source : m_target);
+ }
+
+ QWidget *widget(EndPoint::Type type) const
+ {
+ return qobject_cast<QWidget*>(object(type));
+ }
+
+ QPoint endPointPos(EndPoint::Type type) const;
+ QRect endPointRect(EndPoint::Type) const;
+ void setEndPoint(EndPoint::Type type, QObject *w, const QPoint &pos)
+ { type == EndPoint::Source ? setSource(w, pos) : setTarget(w, pos); }
+
+ bool isVisible() const;
+ virtual void updateVisibility();
+ void setVisible(bool b);
+
+ virtual QRegion region() const;
+ bool contains(const QPoint &pos) const;
+ virtual void paint(QPainter *p) const;
+
+ void update(bool update_widgets = true) const;
+ void checkWidgets();
+
+ QString label(EndPoint::Type type) const
+ { return type == EndPoint::Source ? m_source_label : m_target_label; }
+ void setLabel(EndPoint::Type type, const QString &text);
+ QRect labelRect(EndPoint::Type type) const;
+ QPixmap labelPixmap(EndPoint::Type type) const
+ { return type == EndPoint::Source ? m_source_label_pm : m_target_label_pm; }
+
+ ConnectionEdit *edit() const { return m_edit; }
+
+ virtual void inserted() {}
+ virtual void removed() {}
+
+private:
+ QPoint m_source_pos, m_target_pos;
+ QObject *m_source, *m_target;
+ QList<QPoint> m_knee_list;
+ QPolygonF m_arrow_head;
+ ConnectionEdit *m_edit;
+ QString m_source_label, m_target_label;
+ QPixmap m_source_label_pm, m_target_label_pm;
+ QRect m_source_rect, m_target_rect;
+ bool m_visible;
+
+ void setSource(QObject *source, const QPoint &pos);
+ void setTarget(QObject *target, const QPoint &pos);
+ void updateKneeList();
+ void trimLine();
+ void updatePixmap(EndPoint::Type type);
+ LineDir labelDir(EndPoint::Type type) const;
+ bool ground() const;
+ QRect groundRect() const;
+};
+
+class QDESIGNER_SHARED_EXPORT ConnectionEdit : public QWidget, public CETypes
+{
+ Q_OBJECT
+public:
+ ConnectionEdit(QWidget *parent, QDesignerFormWindowInterface *form);
+ virtual ~ConnectionEdit();
+
+ inline const QPointer<QWidget> &background() const { return m_bg_widget; }
+
+ void setSelected(Connection *con, bool sel);
+ bool selected(const Connection *con) const;
+
+ int connectionCount() const { return m_con_list.size(); }
+ Connection *connection(int i) const { return m_con_list.at(i); }
+ int indexOfConnection(Connection *con) const { return m_con_list.indexOf(con); }
+
+ virtual void setSource(Connection *con, const QString &obj_name);
+ virtual void setTarget(Connection *con, const QString &obj_name);
+
+ QUndoStack *undoStack() const { return m_undo_stack; }
+
+ void clear();
+
+ void showEvent(QShowEvent * /*e*/)
+ {
+ updateBackground();
+ }
+
+signals:
+ void aboutToAddConnection(int idx);
+ void connectionAdded(Connection *con);
+ void aboutToRemoveConnection(Connection *con);
+ void connectionRemoved(int idx);
+ void connectionSelected(Connection *con);
+ void widgetActivated(QWidget *wgt);
+ void connectionChanged(Connection *con);
+
+public slots:
+ void selectNone();
+ void selectAll();
+ virtual void deleteSelected();
+ virtual void setBackground(QWidget *background);
+ virtual void updateBackground();
+ virtual void widgetRemoved(QWidget *w);
+ virtual void objectRemoved(QObject *o);
+
+ void updateLines();
+ void enableUpdateBackground(bool enable);
+
+protected:
+ virtual void paintEvent(QPaintEvent *e);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+ virtual void mouseDoubleClickEvent(QMouseEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void contextMenuEvent(QContextMenuEvent * event);
+
+ virtual Connection *createConnection(QWidget *source, QWidget *target);
+ virtual void modifyConnection(Connection *con);
+
+ virtual QWidget *widgetAt(const QPoint &pos) const;
+ virtual void createContextMenu(QMenu &menu);
+ void addConnection(Connection *con);
+ QRect widgetRect(QWidget *w) const;
+
+ enum State { Editing, Connecting, Dragging };
+ State state() const;
+
+ virtual void endConnection(QWidget *target, const QPoint &pos);
+
+ const ConnectionList &connectionList() const { return m_con_list; }
+ const ConnectionSet &selection() const { return m_sel_con_set; }
+ Connection *takeConnection(Connection *con);
+ Connection *newlyAddedConnection() { return m_tmp_con; }
+ void clearNewlyAddedConnection();
+
+ void findObjectsUnderMouse(const QPoint &pos);
+
+private:
+ void startConnection(QWidget *source, const QPoint &pos);
+ void continueConnection(QWidget *target, const QPoint &pos);
+ void abortConnection();
+
+ void startDrag(const EndPoint &end_point, const QPoint &pos);
+ void continueDrag(const QPoint &pos);
+ void endDrag(const QPoint &pos);
+ void adjustHotSopt(const EndPoint &end_point, const QPoint &pos);
+ Connection *connectionAt(const QPoint &pos) const;
+ EndPoint endPointAt(const QPoint &pos) const;
+ void paintConnection(QPainter *p, Connection *con,
+ WidgetSet *heavy_highlight_set,
+ WidgetSet *light_highlight_set) const;
+ void paintLabel(QPainter *p, EndPoint::Type type, Connection *con);
+
+
+ QPointer<QWidget> m_bg_widget;
+ QUndoStack *m_undo_stack;
+ bool m_enable_update_background;
+
+ Connection *m_tmp_con; // the connection we are currently editing
+ ConnectionList m_con_list;
+ bool m_start_connection_on_drag;
+ EndPoint m_end_point_under_mouse;
+ QPointer<QWidget> m_widget_under_mouse;
+
+ EndPoint m_drag_end_point;
+ QPoint m_old_source_pos, m_old_target_pos;
+ ConnectionSet m_sel_con_set;
+ const QColor m_inactive_color;
+ const QColor m_active_color;
+
+private:
+ friend class Connection;
+ friend class AddConnectionCommand;
+ friend class DeleteConnectionsCommand;
+ friend class SetEndPointCommand;
+};
+
+class QDESIGNER_SHARED_EXPORT CECommand : public QUndoCommand, public CETypes
+{
+public:
+ explicit CECommand(ConnectionEdit *edit)
+ : m_edit(edit) {}
+
+ virtual bool mergeWith(const QUndoCommand *) { return false; }
+
+ ConnectionEdit *edit() const { return m_edit; }
+
+private:
+ ConnectionEdit *m_edit;
+};
+
+class QDESIGNER_SHARED_EXPORT AddConnectionCommand : public CECommand
+{
+public:
+ AddConnectionCommand(ConnectionEdit *edit, Connection *con);
+ virtual void redo();
+ virtual void undo();
+private:
+ Connection *m_con;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteConnectionsCommand : public CECommand
+{
+public:
+ DeleteConnectionsCommand(ConnectionEdit *edit, const ConnectionList &con_list);
+ virtual void redo();
+ virtual void undo();
+private:
+ ConnectionList m_con_list;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // CONNECTIONEDIT_H
diff --git a/tools/designer/src/lib/shared/csshighlighter.cpp b/tools/designer/src/lib/shared/csshighlighter.cpp
new file mode 100644
index 0000000..d5e045b
--- /dev/null
+++ b/tools/designer/src/lib/shared/csshighlighter.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** 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::StyleSheetEditorDialog
+*/
+
+#include "csshighlighter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+CssHighlighter::CssHighlighter(QTextDocument *document)
+: QSyntaxHighlighter(document)
+{
+}
+
+void CssHighlighter::highlightBlock(const QString& text)
+{
+ enum Token { ALNUM, LBRACE, RBRACE, COLON, SEMICOLON, COMMA, QUOTE, SLASH, STAR };
+ static const int transitions[10][9] = {
+ { Selector, Property, Selector, Pseudo, Property, Selector, Quote, MaybeComment, Selector }, // Selector
+ { Property, Property, Selector, Value, Property, Property, Quote, MaybeComment, Property }, // Property
+ { Value, Property, Selector, Value, Property, Value, Quote, MaybeComment, Value }, // Value
+ { Pseudo1, Property, Selector, Pseudo2, Selector, Selector, Quote, MaybeComment, Pseudo }, // Pseudo
+ { Pseudo1, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo1 }, // Pseudo1
+ { Pseudo2, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo2 }, // Pseudo2
+ { Quote, Quote, Quote, Quote, Quote, Quote, -1, Quote, Quote }, // Quote
+ { -1, -1, -1, -1, -1, -1, -1, -1, Comment }, // MaybeComment
+ { Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, MaybeCommentEnd }, // Comment
+ { Comment, Comment, Comment, Comment, Comment, Comment, Comment, -1, MaybeCommentEnd } // MaybeCommentEnd
+ };
+
+ int lastIndex = 0;
+ bool lastWasSlash = false;
+ int state = previousBlockState(), save_state;
+ if (state == -1) {
+ // As long as the text is empty, leave the state undetermined
+ if (text.isEmpty()) {
+ setCurrentBlockState(-1);
+ return;
+ }
+ // The initial state is based on the precense of a : and the absense of a {.
+ // This is because Qt style sheets support both a full stylesheet as well as
+ // an inline form with just properties.
+ state = save_state = (text.indexOf(QLatin1Char(':')) > -1 &&
+ text.indexOf(QLatin1Char('{')) == -1) ? Property : Selector;
+ } else {
+ save_state = state>>16;
+ state &= 0x00ff;
+ }
+
+ if (state == MaybeCommentEnd) {
+ state = Comment;
+ } else if (state == MaybeComment) {
+ state = save_state;
+ }
+
+ for (int i = 0; i < text.length(); i++) {
+ int token = ALNUM;
+ const QChar c = text.at(i);
+ const char a = c.toAscii();
+
+ if (state == Quote) {
+ if (a == '\\') {
+ lastWasSlash = true;
+ } else {
+ if (a == '\"' && !lastWasSlash) {
+ token = QUOTE;
+ }
+ lastWasSlash = false;
+ }
+ } else {
+ switch (a) {
+ case '{': token = LBRACE; break;
+ case '}': token = RBRACE; break;
+ case ':': token = COLON; break;
+ case ';': token = SEMICOLON; break;
+ case ',': token = COMMA; break;
+ case '\"': token = QUOTE; break;
+ case '/': token = SLASH; break;
+ case '*': token = STAR; break;
+ default: break;
+ }
+ }
+
+ int new_state = transitions[state][token];
+
+ if (new_state != state) {
+ bool include_token = new_state == MaybeCommentEnd || (state == MaybeCommentEnd && new_state!= Comment)
+ || state == Quote;
+ highlight(text, lastIndex, i-lastIndex+include_token, state);
+
+ if (new_state == Comment) {
+ lastIndex = i-1; // include the slash and star
+ } else {
+ lastIndex = i + ((token == ALNUM || new_state == Quote) ? 0 : 1);
+ }
+ }
+
+ if (new_state == -1) {
+ state = save_state;
+ } else if (state <= Pseudo2) {
+ save_state = state;
+ state = new_state;
+ } else {
+ state = new_state;
+ }
+ }
+
+ highlight(text, lastIndex, text.length() - lastIndex, state);
+ setCurrentBlockState(state + (save_state<<16));
+}
+
+void CssHighlighter::highlight(const QString &text, int start, int length, int state)
+{
+ if (start >= text.length() || length <= 0)
+ return;
+
+ QTextCharFormat format;
+
+ switch (state) {
+ case Selector:
+ setFormat(start, length, Qt::darkRed);
+ break;
+ case Property:
+ setFormat(start, length, Qt::blue);
+ break;
+ case Value:
+ setFormat(start, length, Qt::black);
+ break;
+ case Pseudo1:
+ setFormat(start, length, Qt::darkRed);
+ break;
+ case Pseudo2:
+ setFormat(start, length, Qt::darkRed);
+ break;
+ case Quote:
+ setFormat(start, length, Qt::darkMagenta);
+ break;
+ case Comment:
+ case MaybeCommentEnd:
+ format.setForeground(Qt::darkGreen);
+ setFormat(start, length, format);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/csshighlighter_p.h b/tools/designer/src/lib/shared/csshighlighter_p.h
new file mode 100644
index 0000000..fa671ea
--- /dev/null
+++ b/tools/designer/src/lib/shared/csshighlighter_p.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$
+**
+****************************************************************************/
+
+//
+// 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 CSSHIGHLIGHTER_H
+#define CSSHIGHLIGHTER_H
+
+#include <QtGui/QSyntaxHighlighter>
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT CssHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ explicit CssHighlighter(QTextDocument *document);
+
+protected:
+ void highlightBlock(const QString&);
+ void highlight(const QString&, int, int, int/*State*/);
+
+private:
+ enum State { Selector, Property, Value, Pseudo, Pseudo1, Pseudo2, Quote,
+ MaybeComment, Comment, MaybeCommentEnd };
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // CSSHIGHLIGHTER_H
diff --git a/tools/designer/src/lib/shared/defaultgradients.xml b/tools/designer/src/lib/shared/defaultgradients.xml
new file mode 100644
index 0000000..70559ad
--- /dev/null
+++ b/tools/designer/src/lib/shared/defaultgradients.xml
@@ -0,0 +1,498 @@
+<gradients>
+ <gradient name="BlackWhite" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Czech" >
+ <gradientData centerX="0.5" centerY="0.5" spread="RepeatSpread" coordinateMode="StretchToDeviceMode" type="ConicalGradient" angle="0" >
+ <stopData position="0" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.373978669201521" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.3739913434727503" >
+ <colorData g="30" r="33" a="255" b="255" />
+ </stopData>
+ <stopData position="0.6240176679340937" >
+ <colorData g="30" r="33" a="255" b="255" />
+ </stopData>
+ <stopData position="0.6240430164765525" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Dutch" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="0" endY="1" >
+ <stopData position="0" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.3397947548460661" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.339798898163606" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.6624439732888147" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.6624690150250417" >
+ <colorData g="0" r="0" a="255" b="255" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="0" a="255" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Eye" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.5" spread="PadSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.1939699465240642" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.202312192513369" >
+ <colorData g="97" r="122" a="255" b="0" />
+ </stopData>
+ <stopData position="0.4955143315508022" >
+ <colorData g="58" r="76" a="255" b="0" />
+ </stopData>
+ <stopData position="0.5048191443850267" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.79" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="158" r="255" a="255" b="158" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Flare1" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.5" spread="PadSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.1" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.2" >
+ <colorData g="176" r="255" a="167" b="176" />
+ </stopData>
+ <stopData position="0.3" >
+ <colorData g="151" r="255" a="92" b="151" />
+ </stopData>
+ <stopData position="0.4" >
+ <colorData g="125" r="255" a="51" b="125" />
+ </stopData>
+ <stopData position="0.5" >
+ <colorData g="76" r="255" a="205" b="76" />
+ </stopData>
+ <stopData position="0.52" >
+ <colorData g="76" r="255" a="205" b="76" />
+ </stopData>
+ <stopData position="0.6" >
+ <colorData g="180" r="255" a="84" b="180" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="0" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Flare2" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.5" spread="PadSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="0" r="0" a="0" b="0" />
+ </stopData>
+ <stopData position="0.52" >
+ <colorData g="0" r="0" a="0" b="0" />
+ </stopData>
+ <stopData position="0.5649999999999999" >
+ <colorData g="121" r="82" a="33" b="76" />
+ </stopData>
+ <stopData position="0.65" >
+ <colorData g="235" r="159" a="64" b="148" />
+ </stopData>
+ <stopData position="0.7219251336898396" >
+ <colorData g="238" r="255" a="129" b="150" />
+ </stopData>
+ <stopData position="0.77" >
+ <colorData g="128" r="255" a="204" b="128" />
+ </stopData>
+ <stopData position="0.89" >
+ <colorData g="128" r="191" a="64" b="255" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="0" a="0" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Flare3" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.5" spread="PadSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="235" r="255" a="206" b="235" />
+ </stopData>
+ <stopData position="0.35" >
+ <colorData g="188" r="255" a="80" b="188" />
+ </stopData>
+ <stopData position="0.4" >
+ <colorData g="162" r="255" a="80" b="162" />
+ </stopData>
+ <stopData position="0.425" >
+ <colorData g="132" r="255" a="156" b="132" />
+ </stopData>
+ <stopData position="0.44" >
+ <colorData g="128" r="252" a="80" b="128" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="0" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="German" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="0" endY="1" >
+ <stopData position="0" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.33" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.34" >
+ <colorData g="30" r="255" a="255" b="30" />
+ </stopData>
+ <stopData position="0.66" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.67" >
+ <colorData g="255" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Golden" >
+ <gradientData centerX="0.5" centerY="0.5" spread="PadSpread" coordinateMode="StretchToDeviceMode" type="ConicalGradient" angle="0" >
+ <stopData position="0" >
+ <colorData g="40" r="35" a="255" b="3" />
+ </stopData>
+ <stopData position="0.16" >
+ <colorData g="106" r="136" a="255" b="22" />
+ </stopData>
+ <stopData position="0.225" >
+ <colorData g="140" r="166" a="255" b="41" />
+ </stopData>
+ <stopData position="0.285" >
+ <colorData g="181" r="204" a="255" b="74" />
+ </stopData>
+ <stopData position="0.345" >
+ <colorData g="219" r="235" a="255" b="102" />
+ </stopData>
+ <stopData position="0.415" >
+ <colorData g="236" r="245" a="255" b="112" />
+ </stopData>
+ <stopData position="0.52" >
+ <colorData g="190" r="209" a="255" b="76" />
+ </stopData>
+ <stopData position="0.57" >
+ <colorData g="156" r="187" a="255" b="51" />
+ </stopData>
+ <stopData position="0.635" >
+ <colorData g="142" r="168" a="255" b="42" />
+ </stopData>
+ <stopData position="0.695" >
+ <colorData g="174" r="202" a="255" b="68" />
+ </stopData>
+ <stopData position="0.75" >
+ <colorData g="202" r="218" a="255" b="86" />
+ </stopData>
+ <stopData position="0.8149999999999999" >
+ <colorData g="187" r="208" a="255" b="73" />
+ </stopData>
+ <stopData position="0.88" >
+ <colorData g="156" r="187" a="255" b="51" />
+ </stopData>
+ <stopData position="0.9350000000000001" >
+ <colorData g="108" r="137" a="255" b="26" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="40" r="35" a="255" b="3" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Japanese" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.5" spread="PadSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.4799044117647059" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.5226851604278074" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Norwegian" >
+ <gradientData spread="RepeatSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.17" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.18" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.2102117403738299" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.2202117403738299" >
+ <colorData g="16" r="0" a="255" b="255" />
+ </stopData>
+ <stopData position="0.2798973635190806" >
+ <colorData g="16" r="0" a="255" b="255" />
+ </stopData>
+ <stopData position="0.2898973635190806" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.32" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.33" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Pastels" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="224" r="245" a="255" b="176" />
+ </stopData>
+ <stopData position="0.09" >
+ <colorData g="189" r="246" a="255" b="237" />
+ </stopData>
+ <stopData position="0.14" >
+ <colorData g="207" r="194" a="255" b="246" />
+ </stopData>
+ <stopData position="0.19" >
+ <colorData g="160" r="184" a="255" b="168" />
+ </stopData>
+ <stopData position="0.25" >
+ <colorData g="186" r="171" a="255" b="248" />
+ </stopData>
+ <stopData position="0.32" >
+ <colorData g="248" r="243" a="255" b="224" />
+ </stopData>
+ <stopData position="0.385" >
+ <colorData g="162" r="249" a="255" b="183" />
+ </stopData>
+ <stopData position="0.47" >
+ <colorData g="115" r="100" a="255" b="124" />
+ </stopData>
+ <stopData position="0.58" >
+ <colorData g="205" r="251" a="255" b="202" />
+ </stopData>
+ <stopData position="0.65" >
+ <colorData g="128" r="170" a="255" b="185" />
+ </stopData>
+ <stopData position="0.75" >
+ <colorData g="222" r="252" a="255" b="204" />
+ </stopData>
+ <stopData position="0.805" >
+ <colorData g="122" r="206" a="255" b="218" />
+ </stopData>
+ <stopData position="0.86" >
+ <colorData g="223" r="254" a="255" b="175" />
+ </stopData>
+ <stopData position="0.91" >
+ <colorData g="236" r="254" a="255" b="244" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="191" r="255" a="255" b="221" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Polish" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="0" endY="1" >
+ <stopData position="0" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.495" >
+ <colorData g="255" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="0.505" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Rainbow" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.166" >
+ <colorData g="255" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.333" >
+ <colorData g="255" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.5" >
+ <colorData g="255" r="0" a="255" b="255" />
+ </stopData>
+ <stopData position="0.666" >
+ <colorData g="0" r="0" a="255" b="255" />
+ </stopData>
+ <stopData position="0.833" >
+ <colorData g="0" r="255" a="255" b="255" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="255" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Sky" >
+ <gradientData spread="PadSpread" startX="0" startY="1" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="0" endY="0" >
+ <stopData position="0" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="0.05" >
+ <colorData g="8" r="14" a="255" b="73" />
+ </stopData>
+ <stopData position="0.36" >
+ <colorData g="17" r="28" a="255" b="145" />
+ </stopData>
+ <stopData position="0.6" >
+ <colorData g="14" r="126" a="255" b="81" />
+ </stopData>
+ <stopData position="0.75" >
+ <colorData g="11" r="234" a="255" b="11" />
+ </stopData>
+ <stopData position="0.79" >
+ <colorData g="70" r="244" a="255" b="5" />
+ </stopData>
+ <stopData position="0.86" >
+ <colorData g="136" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.9350000000000001" >
+ <colorData g="236" r="239" a="255" b="55" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="SunRay" >
+ <gradientData centerX="0" centerY="0" spread="RepeatSpread" coordinateMode="StretchToDeviceMode" type="ConicalGradient" angle="135" >
+ <stopData position="0" >
+ <colorData g="255" r="255" a="69" b="0" />
+ </stopData>
+ <stopData position="0.375" >
+ <colorData g="255" r="255" a="69" b="0" />
+ </stopData>
+ <stopData position="0.4235329090018885" >
+ <colorData g="255" r="251" a="145" b="0" />
+ </stopData>
+ <stopData position="0.45" >
+ <colorData g="255" r="247" a="208" b="0" />
+ </stopData>
+ <stopData position="0.4775811200061043" >
+ <colorData g="244" r="255" a="130" b="71" />
+ </stopData>
+ <stopData position="0.5187165775401069" >
+ <colorData g="218" r="255" a="130" b="71" />
+ </stopData>
+ <stopData position="0.55" >
+ <colorData g="255" r="255" a="255" b="0" />
+ </stopData>
+ <stopData position="0.5775401069518716" >
+ <colorData g="203" r="255" a="130" b="0" />
+ </stopData>
+ <stopData position="0.625" >
+ <colorData g="255" r="255" a="69" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="255" r="255" a="69" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Tropical" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="41" r="9" a="255" b="4" />
+ </stopData>
+ <stopData position="0.08500000000000001" >
+ <colorData g="79" r="2" a="255" b="0" />
+ </stopData>
+ <stopData position="0.19" >
+ <colorData g="147" r="50" a="255" b="22" />
+ </stopData>
+ <stopData position="0.275" >
+ <colorData g="191" r="236" a="255" b="49" />
+ </stopData>
+ <stopData position="0.39" >
+ <colorData g="61" r="243" a="255" b="34" />
+ </stopData>
+ <stopData position="0.555" >
+ <colorData g="81" r="135" a="255" b="60" />
+ </stopData>
+ <stopData position="0.667" >
+ <colorData g="75" r="121" a="255" b="255" />
+ </stopData>
+ <stopData position="0.825" >
+ <colorData g="255" r="164" a="255" b="244" />
+ </stopData>
+ <stopData position="0.885" >
+ <colorData g="222" r="104" a="255" b="71" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="128" r="93" a="255" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Wave" >
+ <gradientData centerX="0.5" centerY="0.5" radius="0.077" spread="RepeatSpread" focalX="0.5" focalY="0.5" coordinateMode="StretchToDeviceMode" type="RadialGradient" >
+ <stopData position="0" >
+ <colorData g="169" r="0" a="147" b="255" />
+ </stopData>
+ <stopData position="0.4973262032085561" >
+ <colorData g="0" r="0" a="147" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="169" r="0" a="147" b="255" />
+ </stopData>
+ </gradientData>
+ </gradient>
+ <gradient name="Wood" >
+ <gradientData spread="PadSpread" startX="0" startY="0" coordinateMode="StretchToDeviceMode" type="LinearGradient" endX="1" endY="0" >
+ <stopData position="0" >
+ <colorData g="178" r="255" a="255" b="102" />
+ </stopData>
+ <stopData position="0.55" >
+ <colorData g="148" r="235" a="255" b="61" />
+ </stopData>
+ <stopData position="0.98" >
+ <colorData g="0" r="0" a="255" b="0" />
+ </stopData>
+ <stopData position="1" >
+ <colorData g="0" r="0" a="0" b="0" />
+ </stopData>
+ </gradientData>
+ </gradient>
+</gradients>
diff --git a/tools/designer/src/lib/shared/deviceprofile.cpp b/tools/designer/src/lib/shared/deviceprofile.cpp
new file mode 100644
index 0000000..c512ff5
--- /dev/null
+++ b/tools/designer/src/lib/shared/deviceprofile.cpp
@@ -0,0 +1,467 @@
+/****************************************************************************
+**
+** 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 "deviceprofile_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <widgetfactory_p.h>
+#include <qdesigner_utils_p.h>
+
+#include <QtGui/QApplication>
+#include <QtGui/QFont>
+#include <QtGui/QDesktopWidget>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleFactory>
+#include <QtGui/QApplication>
+
+#include <QtCore/QSharedData>
+#include <QtCore/QTextStream>
+
+#include <QtCore/QXmlStreamWriter>
+#include <QtCore/QXmlStreamReader>
+
+
+static const char *dpiXPropertyC = "_q_customDpiX";
+static const char *dpiYPropertyC = "_q_customDpiY";
+
+// XML serialization
+static const char *xmlVersionC="1.0";
+static const char *rootElementC="deviceprofile";
+static const char *nameElementC = "name";
+static const char *fontFamilyElementC = "fontfamily";
+static const char *fontPointSizeElementC = "fontpointsize";
+static const char *dPIXElementC = "dpix";
+static const char *dPIYElementC = "dpiy";
+static const char *styleElementC = "style";
+
+/* DeviceProfile:
+ * For preview purposes (preview, widget box, new form dialog), the
+ * QDesignerFormBuilder applies the settings to the form main container
+ * (Point being here that the DPI must be set directly for size calculations
+ * to be correct).
+ * For editing purposes, FormWindow applies the settings to the form container
+ * as not to interfere with the font settings of the form main container.
+ * In addition, the widgetfactory maintains the system settings style
+ * and applies it when creating widgets. */
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// ---------------- DeviceProfileData
+class DeviceProfileData : public QSharedData {
+public:
+ DeviceProfileData();
+ void fromSystem();
+ void clear();
+
+ QString m_fontFamily;
+ int m_fontPointSize;
+ QString m_style;
+ int m_dpiX;
+ int m_dpiY;
+ QString m_name;
+};
+
+DeviceProfileData::DeviceProfileData() :
+ m_fontPointSize(-1),
+ m_dpiX(-1),
+ m_dpiY(-1)
+{
+}
+
+void DeviceProfileData::clear()
+{
+ m_fontPointSize = -1;
+ m_dpiX = 0;
+ m_dpiY = 0;
+ m_name.clear();
+ m_style.clear();
+}
+
+void DeviceProfileData::fromSystem()
+{
+ const QFont appFont = QApplication::font();
+ m_fontFamily = appFont.family();
+ m_fontPointSize = appFont.pointSize();
+ DeviceProfile::systemResolution(&m_dpiX, &m_dpiY);
+ m_style.clear();
+}
+
+// ---------------- DeviceProfile
+DeviceProfile::DeviceProfile() :
+ m_d(new DeviceProfileData)
+{
+}
+
+DeviceProfile::DeviceProfile(const DeviceProfile &o) :
+ m_d(o.m_d)
+
+{
+}
+
+DeviceProfile& DeviceProfile::operator=(const DeviceProfile &o)
+{
+ m_d.operator=(o.m_d);
+ return *this;
+}
+
+DeviceProfile::~DeviceProfile()
+{
+}
+
+void DeviceProfile::clear()
+{
+ m_d->clear();
+}
+
+bool DeviceProfile::isEmpty() const
+{
+ return m_d->m_name.isEmpty();
+}
+
+QString DeviceProfile::fontFamily() const
+{
+ return m_d->m_fontFamily;
+}
+
+void DeviceProfile::setFontFamily(const QString &f)
+{
+ m_d->m_fontFamily = f;
+}
+
+int DeviceProfile::fontPointSize() const
+{
+ return m_d->m_fontPointSize;
+}
+
+void DeviceProfile::setFontPointSize(int p)
+{
+ m_d->m_fontPointSize = p;
+}
+
+QString DeviceProfile::style() const
+{
+ return m_d->m_style;
+}
+
+void DeviceProfile::setStyle(const QString &s)
+{
+ m_d->m_style = s;
+}
+
+int DeviceProfile::dpiX() const
+{
+ return m_d->m_dpiX;
+}
+
+void DeviceProfile::setDpiX(int d)
+{
+ m_d->m_dpiX = d;
+}
+
+int DeviceProfile::dpiY() const
+{
+ return m_d->m_dpiY;
+}
+
+void DeviceProfile::setDpiY(int d)
+{
+ m_d->m_dpiY = d;
+}
+
+void DeviceProfile::fromSystem()
+{
+ m_d->fromSystem();
+}
+
+QString DeviceProfile::name() const
+{
+ return m_d->m_name;
+}
+
+void DeviceProfile::setName(const QString &n)
+{
+ m_d->m_name = n;
+}
+
+void DeviceProfile::systemResolution(int *dpiX, int *dpiY)
+{
+ const QDesktopWidget *dw = qApp->desktop();
+ *dpiX = dw->logicalDpiX();
+ *dpiY = dw->logicalDpiY();
+}
+
+class FriendlyWidget : public QWidget {
+ friend class DeviceProfile;
+};
+
+void DeviceProfile::widgetResolution(const QWidget *w, int *dpiX, int *dpiY)
+{
+ const FriendlyWidget *fw = static_cast<const FriendlyWidget*>(w);
+ *dpiX = fw->metric(QPaintDevice::PdmDpiX);
+ *dpiY = fw->metric(QPaintDevice::PdmDpiY);
+}
+
+QString DeviceProfile::toString() const
+{
+ const DeviceProfileData &d = *m_d;
+ QString rc;
+ QTextStream(&rc) << "DeviceProfile:name=" << d.m_name << " Font=" << d.m_fontFamily << ' '
+ << d.m_fontPointSize << " Style=" << d.m_style << " DPI=" << d.m_dpiX << ',' << d.m_dpiY;
+ return rc;
+}
+
+// Apply font to widget
+static void applyFont(const QString &family, int size, DeviceProfile::ApplyMode am, QWidget *widget)
+{
+ QFont currentFont = widget->font();
+ if (currentFont.pointSize() == size && currentFont.family() == family)
+ return;
+ switch (am) {
+ case DeviceProfile::ApplyFormParent:
+ // Invisible form parent: Apply all
+ widget->setFont(QFont(family, size));
+ break;
+ case DeviceProfile::ApplyPreview: {
+ // Preview: Apply only subproperties that have not been changed by designer properties
+ bool apply = false;
+ const uint resolve = currentFont.resolve();
+ if (!(resolve & QFont::FamilyResolved)) {
+ currentFont.setFamily(family);
+ apply = true;
+ }
+ if (!(resolve & QFont::SizeResolved)) {
+ currentFont.setPointSize(size);
+ apply = true;
+ }
+ if (apply)
+ widget->setFont(currentFont);
+ }
+ break;
+ }
+}
+
+void DeviceProfile::applyDPI(int dpiX, int dpiY, QWidget *widget)
+{
+ int sysDPIX, sysDPIY; // Set dynamic variables in case values are different from system DPI
+ systemResolution(&sysDPIX, &sysDPIY);
+ if (dpiX != sysDPIX && dpiY != sysDPIY) {
+ widget->setProperty(dpiXPropertyC, QVariant(dpiX));
+ widget->setProperty(dpiYPropertyC, QVariant(dpiY));
+ }
+}
+
+void DeviceProfile::apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const
+{
+ if (isEmpty())
+ return;
+
+ const DeviceProfileData &d = *m_d;
+
+ if (!d.m_fontFamily.isEmpty())
+ applyFont(d.m_fontFamily, d.m_fontPointSize, am, widget);
+
+ applyDPI(d.m_dpiX, d.m_dpiY, widget);
+
+ if (!d.m_style.isEmpty()) {
+ if (WidgetFactory *wf = qobject_cast<qdesigner_internal::WidgetFactory *>(core->widgetFactory()))
+ wf->applyStyleTopLevel(d.m_style, widget);
+ }
+}
+
+bool DeviceProfile::equals(const DeviceProfile& rhs) const
+{
+ const DeviceProfileData &d = *m_d;
+ const DeviceProfileData &rhs_d = *rhs.m_d;
+ return d.m_fontPointSize == rhs_d.m_fontPointSize &&
+ d.m_dpiX == rhs_d.m_dpiX && d.m_dpiY == rhs_d.m_dpiY && d.m_fontFamily == rhs_d.m_fontFamily &&
+ d.m_style == rhs_d.m_style && d.m_name == rhs_d.m_name;
+}
+
+static inline void writeElement(QXmlStreamWriter &writer, const QString &element, const QString &cdata)
+{
+ writer.writeStartElement(element);
+ writer.writeCharacters(cdata);
+ writer.writeEndElement();
+}
+
+QString DeviceProfile::toXml() const
+{
+ const DeviceProfileData &d = *m_d;
+ QString rc;
+ QXmlStreamWriter writer(&rc);
+ writer.writeStartDocument(QLatin1String(xmlVersionC));
+ writer.writeStartElement(QLatin1String(rootElementC));
+ writeElement(writer, QLatin1String(nameElementC), d.m_name);
+
+ if (!d.m_fontFamily.isEmpty())
+ writeElement(writer, QLatin1String(fontFamilyElementC), d.m_fontFamily);
+ if (d.m_fontPointSize >= 0)
+ writeElement(writer, QLatin1String(fontPointSizeElementC), QString::number(d.m_fontPointSize));
+ if (d.m_dpiX > 0)
+ writeElement(writer, QLatin1String(dPIXElementC), QString::number(d.m_dpiX));
+ if (d.m_dpiY > 0)
+ writeElement(writer, QLatin1String(dPIYElementC), QString::number(d.m_dpiY));
+ if (!d.m_style.isEmpty())
+ writeElement(writer, QLatin1String(styleElementC), d.m_style);
+
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ return rc;
+}
+
+/* Switch stages when encountering a start element (state table) */
+enum ParseStage { ParseBeginning, ParseWithinRoot,
+ ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle,
+ ParseError };
+
+static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement)
+{
+ switch (currentStage) {
+ case ParseBeginning:
+ if (startElement == QLatin1String(rootElementC))
+ return ParseWithinRoot;
+ break;
+ case ParseWithinRoot:
+ case ParseName:
+ case ParseFontFamily:
+ case ParseFontPointSize:
+ case ParseDPIX:
+ case ParseDPIY:
+ case ParseStyle:
+ if (startElement == QLatin1String(nameElementC))
+ return ParseName;
+ if (startElement == QLatin1String(fontFamilyElementC))
+ return ParseFontFamily;
+ if (startElement == QLatin1String(fontPointSizeElementC))
+ return ParseFontPointSize;
+ if (startElement == QLatin1String(dPIXElementC))
+ return ParseDPIX;
+ if (startElement == QLatin1String(dPIYElementC))
+ return ParseDPIY;
+ if (startElement == QLatin1String(styleElementC))
+ return ParseStyle;
+ break;
+ case ParseError:
+ break;
+ }
+ return ParseError;
+}
+
+static bool readIntegerElement(QXmlStreamReader &reader, int *v)
+{
+ const QString e = reader.readElementText();
+ bool ok;
+ *v = e.toInt(&ok);
+ //: Reading a number for an embedded device profile
+ if (!ok)
+ reader.raiseError(QApplication::translate("DeviceProfile", "'%1' is not a number.").arg(e));
+ return ok;
+}
+
+bool DeviceProfile::fromXml(const QString &xml, QString *errorMessage)
+{
+ DeviceProfileData &d = *m_d;
+ d.fromSystem();
+
+ QXmlStreamReader reader(xml);
+
+ ParseStage ps = ParseBeginning;
+ QXmlStreamReader::TokenType tt = QXmlStreamReader::NoToken;
+ int iv = 0;
+ do {
+ tt = reader.readNext();
+ if (tt == QXmlStreamReader::StartElement) {
+ ps = nextStage(ps, reader.name());
+ switch (ps) {
+ case ParseBeginning:
+ case ParseWithinRoot:
+ break;
+ case ParseError:
+ reader.raiseError(QApplication::translate("DeviceProfile", "An invalid tag <%1> was encountered.").arg(reader.name().toString()));
+ tt = QXmlStreamReader::Invalid;
+ break;
+ case ParseName:
+ d.m_name = reader.readElementText();
+ break;
+ case ParseFontFamily:
+ d.m_fontFamily = reader.readElementText();
+ break;
+ case ParseFontPointSize:
+ if (readIntegerElement(reader, &iv)) {
+ d.m_fontPointSize = iv;
+ } else {
+ tt = QXmlStreamReader::Invalid;
+ }
+ break;
+ case ParseDPIX:
+ if (readIntegerElement(reader, &iv)) {
+ d.m_dpiX = iv;
+ } else {
+ tt = QXmlStreamReader::Invalid;
+ }
+ break;
+ case ParseDPIY:
+ if (readIntegerElement(reader, &iv)) {
+ d.m_dpiY = iv;
+ } else {
+ tt = QXmlStreamReader::Invalid;
+ }
+ break;
+ case ParseStyle:
+ d.m_style = reader.readElementText();
+ break;
+ }
+ }
+ } while (tt != QXmlStreamReader::Invalid && tt != QXmlStreamReader::EndDocument);
+
+ if (reader.hasError()) {
+ *errorMessage = reader.errorString();
+ return false;
+ }
+
+ return true;
+}
+}
+
+QT_END_NAMESPACE
+
diff --git a/tools/designer/src/lib/shared/deviceprofile_p.h b/tools/designer/src/lib/shared/deviceprofile_p.h
new file mode 100644
index 0000000..a1a36e3
--- /dev/null
+++ b/tools/designer/src/lib/shared/deviceprofile_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 DEVICEPROFILE_H
+#define DEVICEPROFILE_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QSharedDataPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QWidget;
+class QStyle;
+
+namespace qdesigner_internal {
+
+class DeviceProfileData;
+
+/* DeviceProfile for embedded design. They influence
+ * default properties (for example, fonts), dpi and
+ * style of the form. This class represents a device
+ * profile. */
+
+class QDESIGNER_SHARED_EXPORT DeviceProfile {
+public:
+ DeviceProfile();
+
+ DeviceProfile(const DeviceProfile&);
+ DeviceProfile& operator=(const DeviceProfile&);
+ ~DeviceProfile();
+
+ void clear();
+
+ // Device name
+ QString name() const;
+ void setName(const QString &);
+
+ // System settings active
+ bool isEmpty() const;
+
+ // Default font family of the embedded system
+ QString fontFamily() const;
+ void setFontFamily(const QString &);
+
+ // Default font size of the embedded system
+ int fontPointSize() const;
+ void setFontPointSize(int p);
+
+ // Display resolution of the embedded system
+ int dpiX() const;
+ void setDpiX(int d);
+ int dpiY() const;
+ void setDpiY(int d);
+
+ // Style
+ QString style() const;
+ void setStyle(const QString &);
+
+ // Initialize from desktop system
+ void fromSystem();
+
+ static void systemResolution(int *dpiX, int *dpiY);
+ static void widgetResolution(const QWidget *w, int *dpiX, int *dpiY);
+
+ bool equals(const DeviceProfile& rhs) const;
+
+ // Apply to form/preview (using font inheritance)
+ enum ApplyMode {
+ /* Pre-Apply to parent widget of form being edited: Apply font
+ * and make use of property inheritance to be able to modify the
+ * font property freely. */
+ ApplyFormParent,
+ /* Post-Apply to preview widget: Change only inherited font
+ * sub properties. */
+ ApplyPreview
+ };
+ void apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const;
+
+ static void applyDPI(int dpiX, int dpiY, QWidget *widget);
+
+ QString toString() const;
+
+ QString toXml() const;
+ bool fromXml(const QString &xml, QString *errorMessage);
+
+private:
+ QSharedDataPointer<DeviceProfileData> m_d;
+};
+
+inline bool operator==(const DeviceProfile &s1, const DeviceProfile &s2)
+ { return s1.equals(s2); }
+inline bool operator!=(const DeviceProfile &s1, const DeviceProfile &s2)
+ { return !s1.equals(s2); }
+
+}
+
+
+QT_END_NAMESPACE
+
+#endif // DEVICEPROFILE_H
diff --git a/tools/designer/src/lib/shared/dialoggui.cpp b/tools/designer/src/lib/shared/dialoggui.cpp
new file mode 100644
index 0000000..ef9dbae
--- /dev/null
+++ b/tools/designer/src/lib/shared/dialoggui.cpp
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** 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 "dialoggui_p.h"
+
+#include <QtGui/QFileIconProvider>
+#include <QtGui/QIcon>
+#include <QtGui/QImage>
+#include <QtGui/QImageReader>
+#include <QtGui/QPixmap>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QSet>
+
+// QFileDialog on X11 does not provide an image preview. Display icons.
+#ifdef Q_WS_X11
+# define IMAGE_PREVIEW
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// Icon provider that reads out the known image formats
+class IconProvider : public QFileIconProvider {
+ Q_DISABLE_COPY(IconProvider)
+
+public:
+ IconProvider();
+ virtual QIcon icon (const QFileInfo &info) const;
+
+ inline bool loadCheck(const QFileInfo &info) const;
+ QImage loadImage(const QString &fileName) const;
+
+private:
+ QSet<QString> m_imageFormats;
+};
+
+IconProvider::IconProvider()
+{
+ // Determine a list of readable extensions (upper and lower case)
+ typedef QList<QByteArray> ByteArrayList;
+ const ByteArrayList fmts = QImageReader::supportedImageFormats();
+ const ByteArrayList::const_iterator cend = fmts.constEnd();
+ for (ByteArrayList::const_iterator it = fmts.constBegin(); it != cend; ++it) {
+ const QString suffix = QString::fromUtf8(it->constData());
+ m_imageFormats.insert(suffix.toLower());
+ m_imageFormats.insert(suffix.toUpper());
+
+ }
+}
+
+// Check by extension and type if this appears to be a loadable image
+bool IconProvider::loadCheck(const QFileInfo &info) const
+{
+ if (info.isFile() && info.isReadable()) {
+ const QString suffix = info.suffix();
+ if (!suffix.isEmpty())
+ return m_imageFormats.contains(suffix);
+ }
+ return false;
+}
+
+QImage IconProvider::loadImage(const QString &fileName) const
+{
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ QImageReader imgReader(&file);
+ if (imgReader.canRead()) {
+ QImage image;
+ if (imgReader.read(&image))
+ return image;
+ }
+ }
+ return QImage();
+}
+
+QIcon IconProvider::icon (const QFileInfo &info) const
+{
+ // Don't get stuck on large images.
+ const qint64 maxSize = 131072;
+ if (loadCheck(info) && info.size() < maxSize) {
+ const QImage image = loadImage(info.absoluteFilePath());
+ if (!image.isNull())
+ return QIcon(QPixmap::fromImage(image, Qt::ThresholdDither|Qt::AutoColor));
+ }
+ return QFileIconProvider::icon(info);
+}
+
+// ---------------- DialogGui
+DialogGui::DialogGui() :
+ m_iconProvider(0)
+{
+}
+
+DialogGui::~DialogGui()
+{
+ delete m_iconProvider;
+}
+
+QFileIconProvider *DialogGui::ensureIconProvider()
+{
+ if (!m_iconProvider)
+ m_iconProvider = new IconProvider;
+ return m_iconProvider;
+}
+
+QMessageBox::StandardButton
+ DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon,
+ const QString &title, const QString &text, QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton)
+{
+ QMessageBox::StandardButton rc = QMessageBox::NoButton;
+ switch (icon) {
+ case QMessageBox::Information:
+ rc = QMessageBox::information(parent, title, text, buttons, defaultButton);
+ break;
+ case QMessageBox::Warning:
+ rc = QMessageBox::warning(parent, title, text, buttons, defaultButton);
+ break;
+ case QMessageBox::Critical:
+ rc = QMessageBox::critical(parent, title, text, buttons, defaultButton);
+ break;
+ case QMessageBox::Question:
+ rc = QMessageBox::question(parent, title, text, buttons, defaultButton);
+ break;
+ case QMessageBox::NoIcon:
+ break;
+ }
+ return rc;
+}
+
+QMessageBox::StandardButton
+ DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon,
+ const QString &title, const QString &text, const QString &informativeText,
+ QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
+{
+ QMessageBox msgBox(icon, title, text, buttons, parent);
+ msgBox.setDefaultButton(defaultButton);
+ msgBox.setInformativeText(informativeText);
+ return static_cast<QMessageBox::StandardButton>(msgBox.exec());
+}
+
+QMessageBox::StandardButton
+ DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon,
+ const QString &title, const QString &text, const QString &informativeText, const QString &detailedText,
+ QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
+{
+ QMessageBox msgBox(icon, title, text, buttons, parent);
+ msgBox.setDefaultButton(defaultButton);
+ msgBox.setInformativeText(informativeText);
+ msgBox.setDetailedText(detailedText);
+ return static_cast<QMessageBox::StandardButton>(msgBox.exec());
+}
+
+QString DialogGui::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options)
+{
+ return QFileDialog::getExistingDirectory(parent, caption, dir, options);
+}
+
+QString DialogGui::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
+{
+ return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
+}
+
+QStringList DialogGui::getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
+{
+ return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options);
+}
+
+QString DialogGui::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
+{
+ return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options);
+}
+
+void DialogGui::initializeImageFileDialog(QFileDialog &fileDialog, QFileDialog::Options options, QFileDialog::FileMode fm)
+{
+ fileDialog.setConfirmOverwrite( !(options & QFileDialog::DontConfirmOverwrite) );
+ fileDialog.setResolveSymlinks( !(options & QFileDialog::DontResolveSymlinks) );
+ fileDialog.setIconProvider(ensureIconProvider());
+ fileDialog.setFileMode(fm);
+}
+
+QString DialogGui::getOpenImageFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options )
+{
+
+#ifdef IMAGE_PREVIEW
+ QFileDialog fileDialog(parent, caption, dir, filter);
+ initializeImageFileDialog(fileDialog, options, QFileDialog::ExistingFile);
+ if (fileDialog.exec() != QDialog::Accepted)
+ return QString();
+
+ const QStringList selectedFiles = fileDialog.selectedFiles();
+ if (selectedFiles.empty())
+ return QString();
+
+ if (selectedFilter)
+ *selectedFilter = fileDialog.selectedFilter();
+
+ return selectedFiles.front();
+#else
+ return getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
+#endif
+}
+
+QStringList DialogGui::getOpenImageFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options )
+{
+#ifdef IMAGE_PREVIEW
+ QFileDialog fileDialog(parent, caption, dir, filter);
+ initializeImageFileDialog(fileDialog, options, QFileDialog::ExistingFiles);
+ if (fileDialog.exec() != QDialog::Accepted)
+ return QStringList();
+
+ const QStringList selectedFiles = fileDialog.selectedFiles();
+ if (!selectedFiles.empty() && selectedFilter)
+ *selectedFilter = fileDialog.selectedFilter();
+
+ return selectedFiles;
+#else
+ return getOpenFileNames(parent, caption, dir, filter, selectedFilter, options);
+#endif
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/dialoggui_p.h b/tools/designer/src/lib/shared/dialoggui_p.h
new file mode 100644
index 0000000..753e130
--- /dev/null
+++ b/tools/designer/src/lib/shared/dialoggui_p.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 DIALOGGUI
+#define DIALOGGUI
+
+//
+// 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.
+//
+
+#include "shared_global_p.h"
+#include <abstractdialoggui_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFileIconProvider;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT DialogGui : public QDesignerDialogGuiInterface
+{
+public:
+ DialogGui();
+ virtual ~DialogGui();
+
+ virtual QMessageBox::StandardButton
+ message(QWidget *parent, Message context, QMessageBox::Icon icon,
+ const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
+ QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
+
+ virtual QMessageBox::StandardButton
+ message(QWidget *parent, Message context, QMessageBox::Icon icon,
+ const QString &title, const QString &text, const QString &informativeText,
+ QMessageBox::StandardButtons buttons = QMessageBox::Ok,
+ QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
+
+ virtual QMessageBox::StandardButton
+ message(QWidget *parent, Message context, QMessageBox::Icon icon,
+ const QString &title, const QString &text, const QString &informativeText, const QString &detailedText,
+ QMessageBox::StandardButtons buttons = QMessageBox::Ok,
+ QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
+
+ virtual QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly);
+ virtual QString getOpenFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
+ virtual QStringList getOpenFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
+ virtual QString getSaveFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
+
+ virtual QString getOpenImageFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
+ virtual QStringList getOpenImageFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
+
+private:
+ QFileIconProvider *ensureIconProvider();
+ void initializeImageFileDialog(QFileDialog &fd, QFileDialog::Options options, QFileDialog::FileMode);
+
+ QFileIconProvider *m_iconProvider;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // DIALOGGUI
diff --git a/tools/designer/src/lib/shared/extensionfactory_p.h b/tools/designer/src/lib/shared/extensionfactory_p.h
new file mode 100644
index 0000000..10649c4
--- /dev/null
+++ b/tools/designer/src/lib/shared/extensionfactory_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 SHARED_EXTENSIONFACTORY_H
+#define SHARED_EXTENSIONFACTORY_H
+
+#include <QtDesigner/default_extensionfactory.h>
+#include <QtDesigner/QExtensionManager>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// Extension factory for registering an extension for an object type.
+template <class ExtensionInterface, class Object, class Extension>
+class ExtensionFactory: public QExtensionFactory
+{
+public:
+ explicit ExtensionFactory(const QString &iid, QExtensionManager *parent = 0);
+
+ // Convenience for registering the extension. Do not use for derived classes.
+ static void registerExtension(QExtensionManager *mgr, const QString &iid);
+
+protected:
+ virtual QObject *createExtension(QObject *qObject, const QString &iid, QObject *parent) const;
+
+private:
+ // Can be overwritten to perform checks on the object.
+ // Default does a qobject_cast to the desired class.
+ virtual Object *checkObject(QObject *qObject) const;
+
+ const QString m_iid;
+};
+
+template <class ExtensionInterface, class Object, class Extension>
+ExtensionFactory<ExtensionInterface, Object, Extension>::ExtensionFactory(const QString &iid, QExtensionManager *parent) :
+ QExtensionFactory(parent),
+ m_iid(iid)
+{
+}
+
+template <class ExtensionInterface, class Object, class Extension>
+Object *ExtensionFactory<ExtensionInterface, Object, Extension>::checkObject(QObject *qObject) const
+{
+ return qobject_cast<Object*>(qObject);
+}
+
+template <class ExtensionInterface, class Object, class Extension>
+QObject *ExtensionFactory<ExtensionInterface, Object, Extension>::createExtension(QObject *qObject, const QString &iid, QObject *parent) const
+{
+ if (iid != m_iid)
+ return 0;
+
+ Object *object = checkObject(qObject);
+ if (!object)
+ return 0;
+
+ return new Extension(object, parent);
+}
+
+template <class ExtensionInterface, class Object, class Extension>
+void ExtensionFactory<ExtensionInterface, Object, Extension>::registerExtension(QExtensionManager *mgr, const QString &iid)
+{
+ ExtensionFactory *factory = new ExtensionFactory(iid, mgr);
+ mgr->registerExtensions(factory, iid);
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // SHARED_EXTENSIONFACTORY_H
diff --git a/tools/designer/src/lib/shared/filterwidget.cpp b/tools/designer/src/lib/shared/filterwidget.cpp
new file mode 100644
index 0000000..f0a77c3
--- /dev/null
+++ b/tools/designer/src/lib/shared/filterwidget.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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 "filterwidget_p.h"
+#include "iconloader_p.h"
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QPushButton>
+#include <QtGui/QLineEdit>
+#include <QtGui/QFocusEvent>
+#include <QtGui/QPalette>
+#include <QtGui/QCursor>
+
+#include <QtCore/QDebug>
+
+enum { debugFilter = 0 };
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+HintLineEdit::HintLineEdit(QWidget *parent) :
+ QLineEdit(parent),
+ m_defaultFocusPolicy(focusPolicy()),
+ m_hintColor(QColor(0xbbbbbb)),
+ m_refuseFocus(false),
+ m_showingHintText(false)
+{
+}
+
+bool HintLineEdit::refuseFocus() const
+{
+ return m_refuseFocus;
+}
+
+void HintLineEdit::setRefuseFocus(bool v)
+{
+ if (v == m_refuseFocus)
+ return;
+ m_refuseFocus = v;
+ setFocusPolicy(m_refuseFocus ? Qt::NoFocus : m_defaultFocusPolicy);
+}
+
+void HintLineEdit::mousePressEvent(QMouseEvent *e)
+{
+ if (debugFilter)
+ qDebug() << Q_FUNC_INFO;
+ // Explicitly focus on click.
+ if (m_refuseFocus && !hasFocus())
+ setFocus(Qt::OtherFocusReason);
+ QLineEdit::mousePressEvent(e);
+}
+
+void HintLineEdit::focusInEvent(QFocusEvent *e)
+{
+ if (debugFilter)
+ qDebug() << Q_FUNC_INFO;
+ if (m_refuseFocus) {
+ // Refuse the focus if the mouse it outside. In addition to the mouse
+ // press logic, this prevents a re-focussing which occurs once
+ // we actually had focus
+ const Qt::FocusReason reason = e->reason();
+ if (reason == Qt::ActiveWindowFocusReason || reason == Qt::PopupFocusReason) {
+ const QPoint mousePos = mapFromGlobal(QCursor::pos());
+ const bool refuse = !geometry().contains(mousePos);
+ if (debugFilter)
+ qDebug() << Q_FUNC_INFO << refuse ;
+ if (refuse) {
+ e->ignore();
+ return;
+ }
+ }
+ }
+
+ hideHintText();
+ QLineEdit::focusInEvent(e);
+}
+
+void HintLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ if (debugFilter)
+ qDebug() << Q_FUNC_INFO;
+ // Focus out: Switch to displaying the hint text unless there is user input
+ showHintText();
+ QLineEdit::focusOutEvent(e);
+}
+
+QString HintLineEdit::hintText() const
+{
+ return m_hintText;
+}
+
+void HintLineEdit::setHintText(const QString &ht)
+{
+ if (ht == m_hintText)
+ return;
+ hideHintText();
+ m_hintText = ht;
+ if (!hasFocus() && !ht.isEmpty())
+ showHintText();
+}
+
+void HintLineEdit::showHintText(bool force)
+{
+ if (m_showingHintText || m_hintText.isEmpty())
+ return;
+ if (force || text().isEmpty()) {
+ m_showingHintText = true;
+ setText(m_hintText);
+ setTextColor(m_hintColor, &m_textColor);
+ }
+}
+void HintLineEdit::hideHintText()
+{
+ if (m_showingHintText && !m_hintText.isEmpty()) {
+ m_showingHintText = false;
+ setText(QString());
+ setTextColor(m_textColor);
+ }
+}
+
+bool HintLineEdit::isShowingHintText() const
+{
+ return m_showingHintText;
+}
+
+QString HintLineEdit::typedText() const
+{
+ return m_showingHintText ? QString() : text();
+}
+
+void HintLineEdit::setTextColor(const QColor &newColor, QColor *oldColor)
+{
+ QPalette pal = palette();
+ if (oldColor)
+ *oldColor = pal.color(QPalette::Text);
+ pal.setColor(QPalette::Text, newColor);
+ setPalette(pal);}
+
+// ------------------- FilterWidget
+FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) :
+ QWidget(parent),
+ m_button(new QPushButton),
+ m_editor(new HintLineEdit)
+{
+ m_editor->setHintText(tr("<Filter>"));
+ QHBoxLayout *l = new QHBoxLayout(this);
+ l->setMargin(0);
+ l->setSpacing(0);
+
+ if (lm == LayoutAlignRight)
+ l->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+ l->addWidget(m_editor);
+
+ m_button->setIcon(createIconSet(QLatin1String("resetproperty.png")));
+ m_button->setIconSize(QSize(8, 8));
+ m_button->setFlat(true);
+ l->addWidget(m_button);
+
+ connect(m_button, SIGNAL(clicked()), this, SLOT(reset()));
+ connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(checkButton(QString)));
+ connect(m_editor, SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString)));
+}
+
+QString FilterWidget::text() const
+{
+ return m_editor->typedText();
+}
+
+void FilterWidget::checkButton(const QString &)
+{
+ m_button->setEnabled(!text().isEmpty());
+}
+
+void FilterWidget::reset()
+{
+ if (debugFilter)
+ qDebug() << Q_FUNC_INFO;
+ if (!text().isEmpty()) {
+ // Editor has lost focus once this is pressed
+ m_editor->showHintText(true);
+ emit filterChanged(QString());
+ }
+}
+
+bool FilterWidget::refuseFocus() const
+{
+ return m_editor->refuseFocus();
+}
+
+void FilterWidget::setRefuseFocus(bool v)
+{
+ m_editor->setRefuseFocus(v);
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/filterwidget_p.h b/tools/designer/src/lib/shared/filterwidget_p.h
new file mode 100644
index 0000000..3d1f64e
--- /dev/null
+++ b/tools/designer/src/lib/shared/filterwidget_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 FILTERWIDGET_H
+#define FILTERWIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QLineEdit>
+#include <QtGui/QColor>
+
+QT_BEGIN_NAMESPACE
+
+class QPushButton;
+
+namespace qdesigner_internal {
+
+/* A line edit that displays a grayed hintText (like "Type Here to Filter")
+ * when not focussed and empty. When connecting to the changed signals and
+ * querying text, one has to be aware that the text is set to that hint
+ * text if isShowingHintText() returns true (that is, does not contain
+ * valid user input). This widget should never have initial focus
+ * (ie, be the first widget of a dialog, else, the hint cannot be displayed.
+ * For situations, where it is the only focusable control (widget box),
+ * there is a special "refuseFocus()" mode, in which it clears the focus
+ * policy and focusses explicitly on click (note that setting Qt::ClickFocus
+ * is not sufficient for that as an ActivationFocus will occur). */
+
+class QDESIGNER_SHARED_EXPORT HintLineEdit : public QLineEdit {
+ Q_OBJECT
+public:
+ explicit HintLineEdit(QWidget *parent = 0);
+
+ QString hintText() const;
+
+ bool isShowingHintText() const;
+
+ // Convenience for accessing the text that returns "" in case of isShowingHintText().
+ QString typedText() const;
+
+ bool refuseFocus() const;
+ void setRefuseFocus(bool v);
+
+public slots:
+ void setHintText(const QString &ht);
+ void showHintText(bool force = false);
+ void hideHintText();
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void focusInEvent(QFocusEvent *e);
+ virtual void focusOutEvent(QFocusEvent *e);
+
+private:
+ void setTextColor(const QColor &newColor, QColor *oldColor = 0);
+
+ const Qt::FocusPolicy m_defaultFocusPolicy;
+ const QColor m_hintColor;
+ QColor m_textColor;
+ bool m_refuseFocus;
+ QString m_hintText;
+ bool m_showingHintText;
+};
+
+// FilterWidget: For filtering item views, with reset button Uses HintLineEdit.
+
+class QDESIGNER_SHARED_EXPORT FilterWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ enum LayoutMode {
+ // For use in toolbars: Expand to the right
+ LayoutAlignRight,
+ // No special alignment
+ LayoutAlignNone
+ };
+
+ explicit FilterWidget(QWidget *parent = 0, LayoutMode lm = LayoutAlignRight);
+
+ QString text() const;
+
+ bool refuseFocus() const; // see HintLineEdit
+ void setRefuseFocus(bool v);
+
+signals:
+ void filterChanged(const QString &);
+
+public slots:
+ void reset();
+
+private slots:
+ void checkButton(const QString &text);
+
+private:
+ QPushButton *m_button;
+ HintLineEdit *m_editor;
+};
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/formlayoutmenu.cpp b/tools/designer/src/lib/shared/formlayoutmenu.cpp
new file mode 100644
index 0000000..c2966a1
--- /dev/null
+++ b/tools/designer/src/lib/shared/formlayoutmenu.cpp
@@ -0,0 +1,534 @@
+/****************************************************************************
+**
+** 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 "formlayoutmenu_p.h"
+#include "layoutinfo_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "ui_formlayoutrowdialog.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+
+#include <QtGui/QAction>
+#include <QtGui/QWidget>
+#include <QtGui/QFormLayout>
+#include <QtGui/QUndoStack>
+#include <QtGui/QDialog>
+#include <QtGui/QPushButton>
+#include <QtGui/QRegExpValidator>
+
+#include <QtCore/QPair>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QRegExp>
+#include <QtCore/QMultiHash>
+#include <QtCore/QDebug>
+
+static const char *buddyPropertyC = "buddy";
+static const char *fieldWidgetBaseClasses[] = {
+ "QLineEdit", "QComboBox", "QSpinBox", "QDoubleSpinBox", "QCheckBox",
+ "QDateEdit", "QTimeEdit", "QDateTimeEdit", "QDial", "QWidget"
+};
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// Struct that describes a row of controls (descriptive label and control) to
+// be added to a form layout.
+struct FormLayoutRow {
+ FormLayoutRow() : buddy(false) {}
+
+ QString labelName;
+ QString labelText;
+ QString fieldClassName;
+ QString fieldName;
+ bool buddy;
+};
+
+// A Dialog to edit a FormLayoutRow. Lets the user input a label text, label
+// name, field widget type, field object name and buddy setting. As the
+// user types the label text; the object names to be used for label and field
+// are updated. It also checks the buddy setting depending on whether the
+// label text contains a buddy marker.
+class FormLayoutRowDialog : public QDialog {
+ Q_DISABLE_COPY(FormLayoutRowDialog)
+ Q_OBJECT
+public:
+ explicit FormLayoutRowDialog(QDesignerFormEditorInterface *core,
+ QWidget *parent);
+
+ FormLayoutRow formLayoutRow() const;
+
+ bool buddy() const;
+ void setBuddy(bool);
+
+ // Accessors for form layout row numbers using 0..[n-1] convention
+ int row() const;
+ void setRow(int);
+ void setRowRange(int, int);
+
+ QString fieldClass() const;
+ QString labelText() const;
+
+ static QStringList fieldWidgetClasses(QDesignerFormEditorInterface *core);
+
+private slots:
+ void labelTextEdited(const QString &text);
+ void labelNameEdited(const QString &text);
+ void fieldNameEdited(const QString &text);
+ void buddyClicked();
+ void fieldClassChanged(int);
+
+private:
+ bool isValid() const;
+ void updateObjectNames(bool updateLabel, bool updateField);
+ void updateOkButton();
+
+ // Check for buddy marker in string
+ const QRegExp m_buddyMarkerRegexp;
+
+ Ui::FormLayoutRowDialog m_ui;
+ bool m_labelNameEdited;
+ bool m_fieldNameEdited;
+ bool m_buddyClicked;
+};
+
+FormLayoutRowDialog::FormLayoutRowDialog(QDesignerFormEditorInterface *core,
+ QWidget *parent) :
+ QDialog(parent),
+ m_buddyMarkerRegexp(QLatin1String("\\&[^&]")),
+ m_labelNameEdited(false),
+ m_fieldNameEdited(false),
+ m_buddyClicked(false)
+{
+ Q_ASSERT(m_buddyMarkerRegexp.isValid());
+
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setModal(true);
+ m_ui.setupUi(this);
+ connect(m_ui.labelTextLineEdit, SIGNAL(textEdited(QString)), this, SLOT(labelTextEdited(QString)));
+
+ QRegExpValidator *nameValidator = new QRegExpValidator(QRegExp(QLatin1String("^[a-zA-Z0-9_]+$")), this);
+ Q_ASSERT(nameValidator->regExp().isValid());
+
+ m_ui.labelNameLineEdit->setValidator(nameValidator);
+ connect(m_ui.labelNameLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(labelNameEdited(QString)));
+
+ m_ui.fieldNameLineEdit->setValidator(nameValidator);
+ connect(m_ui.fieldNameLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(fieldNameEdited(QString)));
+
+ connect(m_ui.buddyCheckBox, SIGNAL(clicked()), this, SLOT(buddyClicked()));
+
+ m_ui.fieldClassComboBox->addItems(fieldWidgetClasses(core));
+ m_ui.fieldClassComboBox->setCurrentIndex(0);
+ connect(m_ui.fieldClassComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(fieldClassChanged(int)));
+
+ updateOkButton();
+}
+
+FormLayoutRow FormLayoutRowDialog::formLayoutRow() const
+{
+ FormLayoutRow rc;
+ rc.labelText = labelText();
+ rc.labelName = m_ui.labelNameLineEdit->text();
+ rc.fieldClassName = fieldClass();
+ rc.fieldName = m_ui.fieldNameLineEdit->text();
+ rc.buddy = buddy();
+ return rc;
+}
+
+bool FormLayoutRowDialog::buddy() const
+{
+ return m_ui.buddyCheckBox->checkState() == Qt::Checked;
+}
+
+void FormLayoutRowDialog::setBuddy(bool b)
+{
+ m_ui.buddyCheckBox->setCheckState(b ? Qt::Checked : Qt::Unchecked);
+}
+
+// Convert rows to 1..n convention for users
+int FormLayoutRowDialog::row() const
+{
+ return m_ui.rowSpinBox->value() - 1;
+}
+
+void FormLayoutRowDialog::setRow(int row)
+{
+ m_ui.rowSpinBox->setValue(row + 1);
+}
+
+void FormLayoutRowDialog::setRowRange(int from, int to)
+{
+ m_ui.rowSpinBox->setMinimum(from + 1);
+ m_ui.rowSpinBox->setMaximum(to + 1);
+ m_ui.rowSpinBox->setEnabled(to - from > 0);
+}
+
+QString FormLayoutRowDialog::fieldClass() const
+{
+ return m_ui.fieldClassComboBox->itemText(m_ui.fieldClassComboBox->currentIndex());
+}
+
+QString FormLayoutRowDialog::labelText() const
+{
+ return m_ui.labelTextLineEdit->text();
+}
+
+bool FormLayoutRowDialog::isValid() const
+{
+ // Check for non-empty names and presence of buddy marker if checked
+ const QString name = labelText();
+ if (name.isEmpty() || m_ui.labelNameLineEdit->text().isEmpty() || m_ui.fieldNameLineEdit->text().isEmpty())
+ return false;
+ if (buddy() && !name.contains(m_buddyMarkerRegexp))
+ return false;
+ return true;
+}
+
+void FormLayoutRowDialog::updateOkButton()
+{
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid());
+}
+
+void FormLayoutRowDialog::labelTextEdited(const QString &text)
+{
+ updateObjectNames(true, true);
+ // Set buddy if '&' is present unless the user changed it
+ if (!m_buddyClicked)
+ setBuddy(text.contains(m_buddyMarkerRegexp));
+
+ updateOkButton();
+}
+
+// Get a suitable object name postfix from a class name:
+// "namespace::QLineEdit"->"LineEdit"
+static inline QString postFixFromClassName(QString className)
+{
+ const int index = className.lastIndexOf(QLatin1String("::"));
+ if (index != -1)
+ className.remove(0, index + 2);
+ if (className.size() > 2)
+ if (className.at(0) == QLatin1Char('Q') || className.at(0) == QLatin1Char('K'))
+ if (className.at(1).isUpper())
+ className.remove(0, 1);
+ return className;
+}
+
+// Helper routines to filter out characters for converting texts into
+// class name prefixes. Only accepts ASCII characters/digits and underscores.
+
+enum PrefixCharacterKind { PC_Digit, PC_UpperCaseLetter, PC_LowerCaseLetter,
+ PC_Other, PC_Invalid };
+
+static inline PrefixCharacterKind prefixCharacterKind(const QChar &c)
+{
+ switch (c.category()) {
+ case QChar::Number_DecimalDigit:
+ return PC_Digit;
+ case QChar::Letter_Lowercase: {
+ const char a = c.toAscii();
+ if (a >= 'a' && a <= 'z')
+ return PC_LowerCaseLetter;
+ }
+ break;
+ case QChar::Letter_Uppercase: {
+ const char a = c.toAscii();
+ if (a >= 'A' && a <= 'Z')
+ return PC_UpperCaseLetter;
+ }
+ break;
+ case QChar::Punctuation_Connector:
+ if (c.toAscii() == '_')
+ return PC_Other;
+ break;
+ default:
+ break;
+ }
+ return PC_Invalid;
+}
+
+// Convert the text the user types into a usable class name prefix by filtering
+// characters, lower-casing the first character and camel-casing subsequent
+// words. ("zip code:") --> ("zipCode").
+
+static QString prefixFromLabel(const QString &prefix)
+{
+ QString rc;
+ const int length = prefix.size();
+ bool lastWasAcceptable = false;
+ for (int i = 0 ; i < length; i++) {
+ const QChar c = prefix.at(i);
+ const PrefixCharacterKind kind = prefixCharacterKind(c);
+ const bool acceptable = kind != PC_Invalid;
+ if (acceptable) {
+ if (rc.isEmpty()) {
+ // Lower-case first character
+ rc += kind == PC_UpperCaseLetter ? c.toLower() : c;
+ } else {
+ // Camel-case words
+ rc += !lastWasAcceptable && kind == PC_LowerCaseLetter ? c.toUpper() : c;
+ }
+ }
+ lastWasAcceptable = acceptable;
+ }
+ return rc;
+}
+
+void FormLayoutRowDialog::updateObjectNames(bool updateLabel, bool updateField)
+{
+ // Generate label + field object names from the label text, that is,
+ // "&Zip code:" -> "zipcodeLabel", "zipcodeLineEdit" unless the user
+ // edited it.
+ const bool doUpdateLabel = !m_labelNameEdited && updateLabel;
+ const bool doUpdateField = !m_fieldNameEdited && updateField;
+ if (!doUpdateLabel && !doUpdateField)
+ return;
+
+ const QString prefix = prefixFromLabel(labelText());
+ // Set names
+ if (doUpdateLabel)
+ m_ui.labelNameLineEdit->setText(prefix + QLatin1String("Label"));
+ if (doUpdateField)
+ m_ui.fieldNameLineEdit->setText(prefix + postFixFromClassName(fieldClass()));
+}
+
+void FormLayoutRowDialog::fieldClassChanged(int)
+{
+ updateObjectNames(false, true);
+}
+
+void FormLayoutRowDialog::labelNameEdited(const QString & /*text*/)
+{
+ m_labelNameEdited = true; // stop auto-updating after user change
+ updateOkButton();
+}
+
+void FormLayoutRowDialog::fieldNameEdited(const QString & /*text*/)
+{
+ m_fieldNameEdited = true; // stop auto-updating after user change
+ updateOkButton();
+}
+
+void FormLayoutRowDialog::buddyClicked()
+{
+ m_buddyClicked = true; // stop auto-updating after user change
+ updateOkButton();
+}
+
+/* Create a list of classes suitable for field widgets. Take the fixed base
+ * classes provided and look in the widget database for custom widgets derived
+ * from them ("QLineEdit", "CustomLineEdit", "QComboBox"...). */
+QStringList FormLayoutRowDialog::fieldWidgetClasses(QDesignerFormEditorInterface *core)
+{
+ // Base class -> custom widgets map
+ typedef QMultiHash<QString, QString> ClassMap;
+
+ static QStringList rc;
+ if (rc.empty()) {
+ const int fwCount = sizeof(fieldWidgetBaseClasses)/sizeof(const char*);
+ // Turn known base classes into list
+ QStringList baseClasses;
+ for (int i = 0; i < fwCount; i++)
+ baseClasses.push_back(QLatin1String(fieldWidgetBaseClasses[i]));
+ // Scan for custom widgets that inherit them and store them in a
+ // multimap of base class->custom widgets unless we have a language
+ // extension installed which might do funny things with custom widgets.
+ ClassMap customClassMap;
+ if (qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core) == 0) {
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ const int wdbCount = wdb->count();
+ for (int w = 0; w < wdbCount; ++w) {
+ // Check for non-container custom types that extend the
+ // respective base class.
+ const QDesignerWidgetDataBaseItemInterface *dbItem = wdb->item(w);
+ if (!dbItem->isPromoted() && !dbItem->isContainer() && dbItem->isCustom()) {
+ const int index = baseClasses.indexOf(dbItem->extends());
+ if (index != -1)
+ customClassMap.insert(baseClasses.at(index), dbItem->name());
+ }
+ }
+ }
+ // Compile final list, taking each base class and append custom widgets
+ // based on it.
+ for (int i = 0; i < fwCount; i++) {
+ rc.push_back(baseClasses.at(i));
+ rc += customClassMap.values(baseClasses.at(i));
+ }
+ }
+ return rc;
+}
+
+// ------------------ Utilities
+
+static QFormLayout *managedFormLayout(const QDesignerFormEditorInterface *core, const QWidget *w)
+{
+ QLayout *l = 0;
+ if (LayoutInfo::managedLayoutType(core, w, &l) == LayoutInfo::Form)
+ return qobject_cast<QFormLayout *>(l);
+ return 0;
+}
+
+// Create the widgets of a control row and apply text properties contained
+// in the struct, called by addFormLayoutRow()
+static QPair<QWidget *,QWidget *>
+ createWidgets(const FormLayoutRow &row, QWidget *parent,
+ QDesignerFormWindowInterface *formWindow)
+{
+ QDesignerFormEditorInterface *core = formWindow->core();
+ QDesignerWidgetFactoryInterface *wf = core->widgetFactory();
+
+ QPair<QWidget *,QWidget *> rc = QPair<QWidget *,QWidget *>(wf->createWidget(QLatin1String("QLabel"), parent),
+ wf->createWidget(row.fieldClassName, parent));
+ // Set up properties of the label
+ const QString objectNameProperty = QLatin1String("objectName");
+ QDesignerPropertySheetExtension *labelSheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), rc.first);
+ int nameIndex = labelSheet->indexOf(objectNameProperty);
+ labelSheet->setProperty(nameIndex, qVariantFromValue(PropertySheetStringValue(row.labelName)));
+ labelSheet->setChanged(nameIndex, true);
+ formWindow->ensureUniqueObjectName(rc.first);
+ const int textIndex = labelSheet->indexOf(QLatin1String("text"));
+ labelSheet->setProperty(textIndex, qVariantFromValue(PropertySheetStringValue(row.labelText)));
+ labelSheet->setChanged(textIndex, true);
+ // Set up properties of the control
+ QDesignerPropertySheetExtension *controlSheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), rc.second);
+ nameIndex = controlSheet->indexOf(objectNameProperty);
+ controlSheet->setProperty(nameIndex, qVariantFromValue(PropertySheetStringValue(row.fieldName)));
+ controlSheet->setChanged(nameIndex, true);
+ formWindow->ensureUniqueObjectName(rc.second);
+ return rc;
+}
+
+// Create a command sequence on the undo stack of the form window that creates
+// the widgets of the row and inserts them into the form layout.
+static void addFormLayoutRow(const FormLayoutRow &formLayoutRow, int row, QWidget *w,
+ QDesignerFormWindowInterface *formWindow)
+{
+ QFormLayout *formLayout = managedFormLayout(formWindow->core(), w);
+ Q_ASSERT(formLayout);
+ QUndoStack *undoStack = formWindow->commandHistory();
+ const QString macroName = QCoreApplication::translate("Command", "Add '%1' to '%2'").arg(formLayoutRow.labelText, formLayout->objectName());
+ undoStack->beginMacro(macroName);
+
+ // Create a list of widget insertion commands and pass them a cell position
+ const QPair<QWidget *,QWidget *> widgetPair = createWidgets(formLayoutRow, w, formWindow);
+
+ InsertWidgetCommand *labelCmd = new InsertWidgetCommand(formWindow);
+ labelCmd->init(widgetPair.first, false, row, 0);
+ undoStack->push(labelCmd);
+ InsertWidgetCommand *controlCmd = new InsertWidgetCommand(formWindow);
+ controlCmd->init(widgetPair.second, false, row, 1);
+ undoStack->push(controlCmd);
+ if (formLayoutRow.buddy) {
+ SetPropertyCommand *buddyCommand = new SetPropertyCommand(formWindow);
+ buddyCommand->init(widgetPair.first, QLatin1String(buddyPropertyC), widgetPair.second->objectName());
+ undoStack->push(buddyCommand);
+ }
+ undoStack->endMacro();
+}
+
+// ---------------- FormLayoutMenu
+FormLayoutMenu::FormLayoutMenu(QObject *parent) :
+ QObject(parent),
+ m_separator1(new QAction(this)),
+ m_populateFormAction(new QAction(tr("Add form layout row..."), this)),
+ m_separator2(new QAction(this))
+{
+ m_separator1->setSeparator(true);
+ connect(m_populateFormAction, SIGNAL(triggered()), this, SLOT(slotAddRow()));
+ m_separator2->setSeparator(true);
+}
+
+void FormLayoutMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList &actions)
+{
+ switch (LayoutInfo::managedLayoutType(fw->core(), w)) {
+ case LayoutInfo::Form:
+ if (!actions.empty() && !actions.back()->isSeparator())
+ actions.push_back(m_separator1);
+ actions.push_back(m_populateFormAction);
+ actions.push_back(m_separator2);
+ m_widget = w;
+ break;
+ default:
+ m_widget = 0;
+ break;
+ }
+}
+
+void FormLayoutMenu::slotAddRow()
+{
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_widget);
+ Q_ASSERT(m_widget && fw);
+ const int rowCount = managedFormLayout(fw->core(), m_widget)->rowCount();
+
+ FormLayoutRowDialog dialog(fw->core(), fw);
+ dialog.setRowRange(0, rowCount);
+ dialog.setRow(rowCount);
+
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ addFormLayoutRow(dialog.formLayoutRow(), dialog.row(), m_widget, fw);
+}
+
+QAction *FormLayoutMenu::preferredEditAction(QWidget *w, QDesignerFormWindowInterface *fw)
+{
+ if (LayoutInfo::managedLayoutType(fw->core(), w) == LayoutInfo::Form) {
+ m_widget = w;
+ return m_populateFormAction;
+ }
+ return 0;
+}
+}
+
+QT_END_NAMESPACE
+
+#include "formlayoutmenu.moc"
+
diff --git a/tools/designer/src/lib/shared/formlayoutmenu_p.h b/tools/designer/src/lib/shared/formlayoutmenu_p.h
new file mode 100644
index 0000000..a575468
--- /dev/null
+++ b/tools/designer/src/lib/shared/formlayoutmenu_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef FORMLAYOUTMENU
+#define FORMLAYOUTMENU
+
+//
+// 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.
+//
+
+#include "shared_global_p.h"
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+class QAction;
+class QWidget;
+
+namespace qdesigner_internal {
+
+// Task menu to be used for form layouts. Offers an options "Add row" which
+// pops up a dialog in which the user can specify label name, text and buddy.
+class QDESIGNER_SHARED_EXPORT FormLayoutMenu : public QObject
+{
+ Q_DISABLE_COPY(FormLayoutMenu)
+ Q_OBJECT
+public:
+ typedef QList<QAction *> ActionList;
+
+ explicit FormLayoutMenu(QObject *parent);
+
+ // Populate a list of actions with the form layout actions.
+ void populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList &actions);
+ // For implementing QDesignerTaskMenuExtension::preferredEditAction():
+ // Return appropriate action for double clicking.
+ QAction *preferredEditAction(QWidget *w, QDesignerFormWindowInterface *fw);
+
+private slots:
+ void slotAddRow();
+
+private:
+ QAction *m_separator1;
+ QAction *m_populateFormAction;
+ QAction *m_separator2;
+ QPointer<QWidget> m_widget;
+};
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // FORMLAYOUTMENU
diff --git a/tools/designer/src/lib/shared/formlayoutrowdialog.ui b/tools/designer/src/lib/shared/formlayoutrowdialog.ui
new file mode 100644
index 0000000..c0e0cfe
--- /dev/null
+++ b/tools/designer/src/lib/shared/formlayoutrowdialog.ui
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FormLayoutRowDialog</class>
+ <widget class="QDialog" name="FormLayoutRowDialog">
+ <property name="windowTitle">
+ <string>Add Form Layout Row</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelTextLabel">
+ <property name="text">
+ <string>&amp;Label text:</string>
+ </property>
+ <property name="buddy">
+ <cstring>labelTextLineEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="labelTextLineEdit">
+ <property name="minimumSize">
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="labelNameLineEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="fieldClassLabel">
+ <property name="text">
+ <string>Field &amp;type:</string>
+ </property>
+ <property name="buddy">
+ <cstring>fieldClassComboBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="fieldClassComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="fieldNameLabel">
+ <property name="text">
+ <string>&amp;Field name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>fieldNameLineEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="buddyLabel">
+ <property name="text">
+ <string>&amp;Buddy:</string>
+ </property>
+ <property name="buddy">
+ <cstring>buddyCheckBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="buddyCheckBox">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="rowLabel">
+ <property name="text">
+ <string>&amp;Row:</string>
+ </property>
+ <property name="buddy">
+ <cstring>rowSpinBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QSpinBox" name="rowSpinBox"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="fieldNameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelNameLabel">
+ <property name="text">
+ <string>Label &amp;name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>labelNameLineEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>FormLayoutRowDialog</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>FormLayoutRowDialog</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/lib/shared/formwindowbase.cpp b/tools/designer/src/lib/shared/formwindowbase.cpp
new file mode 100644
index 0000000..3e7e17b
--- /dev/null
+++ b/tools/designer/src/lib/shared/formwindowbase.cpp
@@ -0,0 +1,487 @@
+/****************************************************************************
+**
+** 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::FormWindowBase
+*/
+
+#include "formwindowbase_p.h"
+#include "connectionedit_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertysheet_p.h"
+#include "qdesigner_propertyeditor_p.h"
+#include "qdesigner_menu_p.h"
+#include "qdesigner_menubar_p.h"
+#include "shared_settings_p.h"
+#include "grid_p.h"
+#include "deviceprofile_p.h"
+#include "qdesigner_utils_p.h"
+
+#include <abstractformbuilder.h>
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerTaskMenuExtension>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/QList>
+#include <QtCore/QTimer>
+#include <QtGui/QMenu>
+#include <QtGui/QListWidget>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QTableWidget>
+#include <QtGui/QComboBox>
+#include <QtGui/QTabWidget>
+#include <QtGui/QToolBox>
+#include <QtGui/QToolBar>
+#include <QtGui/QStatusBar>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class FormWindowBasePrivate {
+public:
+ explicit FormWindowBasePrivate(QDesignerFormEditorInterface *core);
+
+ static Grid m_defaultGrid;
+
+ QDesignerFormWindowInterface::Feature m_feature;
+ Grid m_grid;
+ bool m_hasFormGrid;
+ DesignerPixmapCache *m_pixmapCache;
+ DesignerIconCache *m_iconCache;
+ QtResourceSet *m_resourceSet;
+ QMap<QDesignerPropertySheet *, QMap<int, bool> > m_reloadableResources; // bool is dummy, QMap used as QSet
+ QMap<QDesignerPropertySheet *, QObject *> m_reloadablePropertySheets;
+ const DeviceProfile m_deviceProfile;
+ FormWindowBase::LineTerminatorMode m_lineTerminatorMode;
+ FormWindowBase::SaveResourcesBehaviour m_saveResourcesBehaviour;
+};
+
+FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) :
+ m_feature(QDesignerFormWindowInterface::DefaultFeature),
+ m_grid(m_defaultGrid),
+ m_hasFormGrid(false),
+ m_pixmapCache(0),
+ m_iconCache(0),
+ m_resourceSet(0),
+ m_deviceProfile(QDesignerSharedSettings(core).currentDeviceProfile()),
+ m_lineTerminatorMode(FormWindowBase::NativeLineTerminator),
+ m_saveResourcesBehaviour(FormWindowBase::SaveAll)
+{
+}
+
+Grid FormWindowBasePrivate::m_defaultGrid;
+
+FormWindowBase::FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) :
+ QDesignerFormWindowInterface(parent, flags),
+ m_d(new FormWindowBasePrivate(core))
+{
+ syncGridFeature();
+ m_d->m_pixmapCache = new DesignerPixmapCache(this);
+ m_d->m_iconCache = new DesignerIconCache(m_d->m_pixmapCache, this);
+}
+
+FormWindowBase::~FormWindowBase()
+{
+ delete m_d;
+}
+
+DesignerPixmapCache *FormWindowBase::pixmapCache() const
+{
+ return m_d->m_pixmapCache;
+}
+
+DesignerIconCache *FormWindowBase::iconCache() const
+{
+ return m_d->m_iconCache;
+}
+
+QtResourceSet *FormWindowBase::resourceSet() const
+{
+ return m_d->m_resourceSet;
+}
+
+void FormWindowBase::setResourceSet(QtResourceSet *resourceSet)
+{
+ m_d->m_resourceSet = resourceSet;
+}
+
+void FormWindowBase::addReloadableProperty(QDesignerPropertySheet *sheet, int index)
+{
+ m_d->m_reloadableResources[sheet][index] = true;
+}
+
+void FormWindowBase::removeReloadableProperty(QDesignerPropertySheet *sheet, int index)
+{
+ m_d->m_reloadableResources[sheet].remove(index);
+ if (m_d->m_reloadableResources[sheet].count() == 0)
+ m_d->m_reloadableResources.remove(sheet);
+}
+
+void FormWindowBase::addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object)
+{
+ if (qobject_cast<QTreeWidget *>(object) ||
+ qobject_cast<QTableWidget *>(object) ||
+ qobject_cast<QListWidget *>(object) ||
+ qobject_cast<QComboBox *>(object))
+ m_d->m_reloadablePropertySheets[sheet] = object;
+}
+
+void FormWindowBase::removeReloadablePropertySheet(QDesignerPropertySheet *sheet)
+{
+ m_d->m_reloadablePropertySheets.remove(sheet);
+}
+
+void FormWindowBase::reloadProperties()
+{
+ pixmapCache()->clear();
+ iconCache()->clear();
+ QMapIterator<QDesignerPropertySheet *, QMap<int, bool> > itSheet(m_d->m_reloadableResources);
+ while (itSheet.hasNext()) {
+ QDesignerPropertySheet *sheet = itSheet.next().key();
+ QMapIterator<int, bool> itIndex(itSheet.value());
+ while (itIndex.hasNext()) {
+ const int index = itIndex.next().key();
+ sheet->setProperty(index, sheet->property(index));
+ }
+ if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(sheet->object())) {
+ const int count = tabWidget->count();
+ const int current = tabWidget->currentIndex();
+ const QString currentTabIcon = QLatin1String("currentTabIcon");
+ for (int i = 0; i < count; i++) {
+ tabWidget->setCurrentIndex(i);
+ const int index = sheet->indexOf(currentTabIcon);
+ sheet->setProperty(index, sheet->property(index));
+ }
+ tabWidget->setCurrentIndex(current);
+ } else if (QToolBox *toolBox = qobject_cast<QToolBox *>(sheet->object())) {
+ const int count = toolBox->count();
+ const int current = toolBox->currentIndex();
+ const QString currentItemIcon = QLatin1String("currentItemIcon");
+ for (int i = 0; i < count; i++) {
+ toolBox->setCurrentIndex(i);
+ const int index = sheet->indexOf(currentItemIcon);
+ sheet->setProperty(index, sheet->property(index));
+ }
+ toolBox->setCurrentIndex(current);
+ }
+ }
+ QMapIterator<QDesignerPropertySheet *, QObject *> itSh(m_d->m_reloadablePropertySheets);
+ while (itSh.hasNext()) {
+ QObject *object = itSh.next().value();
+ reloadIconResources(iconCache(), object);
+ }
+}
+
+void FormWindowBase::resourceSetActivated(QtResourceSet *resource, bool resourceSetChanged)
+{
+ if (resource == resourceSet() && resourceSetChanged) {
+ reloadProperties();
+ emit pixmapCache()->reloaded();
+ emit iconCache()->reloaded();
+ if (QDesignerPropertyEditor *propertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor()))
+ propertyEditor->reloadResourceProperties();
+ }
+}
+
+QVariantMap FormWindowBase::formData()
+{
+ QVariantMap rc;
+ if (m_d->m_hasFormGrid)
+ m_d->m_grid.addToVariantMap(rc, true);
+ return rc;
+}
+
+void FormWindowBase::setFormData(const QVariantMap &vm)
+{
+ Grid formGrid;
+ m_d->m_hasFormGrid = formGrid.fromVariantMap(vm);
+ if (m_d->m_hasFormGrid)
+ m_d->m_grid = formGrid;
+}
+
+QPoint FormWindowBase::grid() const
+{
+ return QPoint(m_d->m_grid.deltaX(), m_d->m_grid.deltaY());
+}
+
+void FormWindowBase::setGrid(const QPoint &grid)
+{
+ m_d->m_grid.setDeltaX(grid.x());
+ m_d->m_grid.setDeltaY(grid.y());
+}
+
+bool FormWindowBase::hasFeature(Feature f) const
+{
+ return f & m_d->m_feature;
+}
+
+static void recursiveUpdate(QWidget *w)
+{
+ w->update();
+
+ const QObjectList &l = w->children();
+ const QObjectList::const_iterator cend = l.constEnd();
+ for (QObjectList::const_iterator it = l.constBegin(); it != cend; ++it) {
+ if (QWidget *w = qobject_cast<QWidget*>(*it))
+ recursiveUpdate(w);
+ }
+}
+
+void FormWindowBase::setFeatures(Feature f)
+{
+ m_d->m_feature = f;
+ const bool enableGrid = f & GridFeature;
+ m_d->m_grid.setVisible(enableGrid);
+ m_d->m_grid.setSnapX(enableGrid);
+ m_d->m_grid.setSnapY(enableGrid);
+ emit featureChanged(f);
+ recursiveUpdate(this);
+}
+
+FormWindowBase::Feature FormWindowBase::features() const
+{
+ return m_d->m_feature;
+}
+
+bool FormWindowBase::gridVisible() const
+{
+ return m_d->m_grid.visible() && currentTool() == 0;
+}
+
+FormWindowBase::SaveResourcesBehaviour FormWindowBase::saveResourcesBehaviour() const
+{
+ return m_d->m_saveResourcesBehaviour;
+}
+
+void FormWindowBase::setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour)
+{
+ m_d->m_saveResourcesBehaviour = behaviour;
+}
+
+void FormWindowBase::syncGridFeature()
+{
+ if (m_d->m_grid.snapX() || m_d->m_grid.snapY())
+ m_d->m_feature |= GridFeature;
+ else
+ m_d->m_feature &= ~GridFeature;
+}
+
+void FormWindowBase::setDesignerGrid(const Grid& grid)
+{
+ m_d->m_grid = grid;
+ syncGridFeature();
+ recursiveUpdate(this);
+}
+
+const Grid &FormWindowBase::designerGrid() const
+{
+ return m_d->m_grid;
+}
+
+bool FormWindowBase::hasFormGrid() const
+{
+ return m_d->m_hasFormGrid;
+}
+
+void FormWindowBase::setHasFormGrid(bool b)
+{
+ m_d->m_hasFormGrid = b;
+}
+
+void FormWindowBase::setDefaultDesignerGrid(const Grid& grid)
+{
+ FormWindowBasePrivate::m_defaultGrid = grid;
+}
+
+const Grid &FormWindowBase::defaultDesignerGrid()
+{
+ return FormWindowBasePrivate::m_defaultGrid;
+}
+
+QMenu *FormWindowBase::initializePopupMenu(QWidget * /*managedWidget*/)
+{
+ return 0;
+}
+
+// Widget under mouse for finding the Widget to highlight
+// when doing DnD. Restricts to pages by geometry if a container with
+// a container extension (or one of its helper widgets) is hit; otherwise
+// returns the widget as such (be it managed/unmanaged)
+
+QWidget *FormWindowBase::widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode /* wum */)
+{
+ // widget_under_mouse might be some temporary thing like the dropLine. We need
+ // the actual widget that's part of the edited GUI.
+ QWidget *rc = widgetAt(formPos);
+ if (!rc || qobject_cast<ConnectionEdit*>(rc))
+ return 0;
+
+ if (rc == mainContainer()) {
+ // Refuse main container areas if the main container has a container extension,
+ // for example when hitting QToolBox/QTabWidget empty areas.
+ if (qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), rc))
+ return 0;
+ return rc;
+ }
+
+ // If we hit on container extension type container, make sure
+ // we use the top-most current page
+ if (QWidget *container = findContainer(rc, false))
+ if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), container)) {
+ // For container that do not have a "stacked" nature (QToolBox, QMdiArea),
+ // make sure the position is within the current page
+ const int ci = c->currentIndex();
+ if (ci < 0)
+ return 0;
+ QWidget *page = c->widget(ci);
+ QRect pageGeometry = page->geometry();
+ pageGeometry.moveTo(page->mapTo(this, pageGeometry.topLeft()));
+ if (!pageGeometry.contains(formPos))
+ return 0;
+ return page;
+ }
+
+ return rc;
+}
+
+void FormWindowBase::deleteWidgetList(const QWidgetList &widget_list)
+{
+ // We need a macro here even for single widgets because the some components (for example,
+ // the signal slot editor are connected to widgetRemoved() and add their
+ // own commands (for example, to delete w's connections)
+ const QString description = widget_list.size() == 1 ?
+ tr("Delete '%1'").arg(widget_list.front()->objectName()) : tr("Delete");
+
+ commandHistory()->beginMacro(description);
+ foreach (QWidget *w, widget_list) {
+ emit widgetRemoved(w);
+ DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this);
+ cmd->init(w);
+ commandHistory()->push(cmd);
+ }
+ commandHistory()->endMacro();
+}
+
+QMenu *FormWindowBase::createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator)
+{
+ typedef QList<QAction *> ActionList;
+ ActionList actions;
+ // 1) Standard public extension
+ QExtensionManager *em = fw->core()->extensionManager();
+ if (const QDesignerTaskMenuExtension *extTaskMenu = qt_extension<QDesignerTaskMenuExtension*>(em, o))
+ actions += extTaskMenu->taskActions();
+ if (const QDesignerTaskMenuExtension *intTaskMenu = qobject_cast<QDesignerTaskMenuExtension *>(em->extension(o, QLatin1String("QDesignerInternalTaskMenuExtension")))) {
+ if (!actions.empty()) {
+ QAction *a = new QAction(fw);
+ a->setSeparator(true);
+ actions.push_back(a);
+ }
+ actions += intTaskMenu->taskActions();
+ }
+ if (actions.empty())
+ return 0;
+ if (trailingSeparator && !actions.back()->isSeparator()) {
+ QAction *a = new QAction(fw);
+ a->setSeparator(true);
+ actions.push_back(a);
+ }
+ QMenu *rc = new QMenu;
+ const ActionList::const_iterator cend = actions.constEnd();
+ for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
+ rc->addAction(*it);
+ return rc;
+}
+
+void FormWindowBase::emitObjectRemoved(QObject *o)
+{
+ emit objectRemoved(o);
+}
+
+DeviceProfile FormWindowBase::deviceProfile() const
+{
+ return m_d->m_deviceProfile;
+}
+
+QString FormWindowBase::styleName() const
+{
+ return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.style();
+}
+
+void FormWindowBase::emitWidgetRemoved(QWidget *w)
+{
+ emit widgetRemoved(w);
+}
+
+QString FormWindowBase::deviceProfileName() const
+{
+ return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.name();
+}
+
+void FormWindowBase::setLineTerminatorMode(FormWindowBase::LineTerminatorMode mode)
+{
+ m_d->m_lineTerminatorMode = mode;
+}
+
+FormWindowBase::LineTerminatorMode FormWindowBase::lineTerminatorMode() const
+{
+ return m_d->m_lineTerminatorMode;
+}
+
+void FormWindowBase::triggerDefaultAction(QWidget *widget)
+{
+ if (QAction *action = qdesigner_internal::preferredEditAction(core(), widget))
+ QTimer::singleShot(0, action, SIGNAL(triggered()));
+}
+
+void FormWindowBase::setupDefaultAction(QDesignerFormWindowInterface *fw)
+{
+ QObject::connect(fw, SIGNAL(activated(QWidget*)), fw, SLOT(triggerDefaultAction(QWidget*)));
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/formwindowbase_p.h b/tools/designer/src/lib/shared/formwindowbase_p.h
new file mode 100644
index 0000000..68e977e
--- /dev/null
+++ b/tools/designer/src/lib/shared/formwindowbase_p.h
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** 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 FORMWINDOWBASE_H
+#define FORMWINDOWBASE_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtCore/QVariantMap>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerDnDItemInterface;
+class QMenu;
+class QtResourceSet;
+class QDesignerPropertySheet;
+
+namespace qdesigner_internal {
+
+class QEditorFormBuilder;
+class DeviceProfile;
+class Grid;
+
+class DesignerPixmapCache;
+class DesignerIconCache;
+class FormWindowBasePrivate;
+
+class QDESIGNER_SHARED_EXPORT FormWindowBase: public QDesignerFormWindowInterface
+{
+ Q_OBJECT
+public:
+ enum HighlightMode { Restore, Highlight };
+ enum SaveResourcesBehaviour { SaveAll, SaveOnlyUsedQrcFiles, DontSaveQrcFiles };
+
+ explicit FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~FormWindowBase();
+
+ QVariantMap formData();
+ void setFormData(const QVariantMap &vm);
+
+ // Return the widget containing the form. This is used to
+ // apply embedded design settings to that are inherited (for example font).
+ // These are meant to be applied to the form only and not to the other editors
+ // in the widget stack.
+ virtual QWidget *formContainer() const = 0;
+
+ // Deprecated
+ virtual QPoint grid() const;
+
+ // Deprecated
+ virtual void setGrid(const QPoint &grid);
+
+ virtual bool hasFeature(Feature f) const;
+ virtual Feature features() const;
+ virtual void setFeatures(Feature f);
+
+ const Grid &designerGrid() const;
+ void setDesignerGrid(const Grid& grid);
+
+ bool hasFormGrid() const;
+ void setHasFormGrid(bool b);
+
+ bool gridVisible() const;
+
+ SaveResourcesBehaviour saveResourcesBehaviour() const;
+ void setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour);
+
+ static const Grid &defaultDesignerGrid();
+ static void setDefaultDesignerGrid(const Grid& grid);
+
+ // Overwrite to initialize and return a full popup menu for a managed widget
+ virtual QMenu *initializePopupMenu(QWidget *managedWidget);
+ // Helper to create a basic popup menu from task menu extensions (internal/public)
+ static QMenu *createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator = true);
+
+ virtual bool dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, QWidget *target,
+ const QPoint &global_mouse_pos) = 0;
+
+ // Helper to find the widget at the mouse position with some flags.
+ enum WidgetUnderMouseMode { FindSingleSelectionDropTarget, FindMultiSelectionDropTarget };
+ QWidget *widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode m);
+
+ virtual QWidget *widgetAt(const QPoint &pos) = 0;
+ virtual QWidget *findContainer(QWidget *w, bool excludeLayout) const = 0;
+
+ void deleteWidgetList(const QWidgetList &widget_list);
+
+ virtual void highlightWidget(QWidget *w, const QPoint &pos, HighlightMode mode = Highlight) = 0;
+
+ enum PasteMode { PasteAll, PasteActionsOnly };
+ virtual void paste(PasteMode pasteMode) = 0;
+
+ // Factory method to create a form builder
+ virtual QEditorFormBuilder *createFormBuilder() = 0;
+
+ virtual bool blockSelectionChanged(bool blocked) = 0;
+ virtual void emitSelectionChanged() = 0;
+
+ DesignerPixmapCache *pixmapCache() const;
+ DesignerIconCache *iconCache() const;
+ QtResourceSet *resourceSet() const;
+ void setResourceSet(QtResourceSet *resourceSet);
+ void addReloadableProperty(QDesignerPropertySheet *sheet, int index);
+ void removeReloadableProperty(QDesignerPropertySheet *sheet, int index);
+ void addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object);
+ void removeReloadablePropertySheet(QDesignerPropertySheet *sheet);
+ void reloadProperties();
+
+ void emitWidgetRemoved(QWidget *w);
+ void emitObjectRemoved(QObject *o);
+
+ DeviceProfile deviceProfile() const;
+ QString styleName() const;
+ QString deviceProfileName() const;
+
+ enum LineTerminatorMode {
+ LFLineTerminator,
+ CRLFLineTerminator,
+ NativeLineTerminator =
+#if defined (Q_OS_WIN)
+ CRLFLineTerminator
+#else
+ LFLineTerminator
+#endif
+ };
+
+ void setLineTerminatorMode(LineTerminatorMode mode);
+ LineTerminatorMode lineTerminatorMode() const;
+
+ // Connect the 'activated' (doubleclicked) signal of the form window to a
+ // slot triggering the default action (of the task menu)
+ static void setupDefaultAction(QDesignerFormWindowInterface *fw);
+
+public slots:
+ void resourceSetActivated(QtResourceSet *resourceSet, bool resourceSetChanged);
+
+private slots:
+ void triggerDefaultAction(QWidget *w);
+
+private:
+ void syncGridFeature();
+
+ FormWindowBasePrivate *m_d;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // FORMWINDOWBASE_H
diff --git a/tools/designer/src/lib/shared/grid.cpp b/tools/designer/src/lib/shared/grid.cpp
new file mode 100644
index 0000000..99dbcee
--- /dev/null
+++ b/tools/designer/src/lib/shared/grid.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** 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 "grid_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtGui/QPainter>
+#include <QtGui/QWidget>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+static const bool defaultSnap = true;
+static const bool defaultVisible = true;
+static const int DEFAULT_GRID = 10;
+static const char* KEY_VISIBLE = "gridVisible";
+static const char* KEY_SNAPX = "gridSnapX";
+static const char* KEY_SNAPY = "gridSnapY";
+static const char* KEY_DELTAX = "gridDeltaX";
+static const char* KEY_DELTAY = "gridDeltaY";
+
+// Insert a value into the serialization map unless default
+template <class T>
+ static inline void valueToVariantMap(T value, T defaultValue, const QString &key, QVariantMap &v, bool forceKey) {
+ if (forceKey || value != defaultValue)
+ v.insert(key, QVariant(value));
+ }
+
+// Obtain a value form QVariantMap
+template <class T>
+ static inline bool valueFromVariantMap(const QVariantMap &v, const QString &key, T &value) {
+ const QVariantMap::const_iterator it = v.constFind(key);
+ const bool found = it != v.constEnd();
+ if (found)
+ value = qVariantValue<T>(it.value());
+ return found;
+ }
+
+namespace qdesigner_internal
+{
+
+Grid::Grid() :
+ m_visible(defaultVisible),
+ m_snapX(defaultSnap),
+ m_snapY(defaultSnap),
+ m_deltaX(DEFAULT_GRID),
+ m_deltaY(DEFAULT_GRID)
+{
+}
+
+bool Grid::fromVariantMap(const QVariantMap& vm)
+{
+ *this = Grid();
+ valueFromVariantMap(vm, QLatin1String(KEY_VISIBLE), m_visible);
+ valueFromVariantMap(vm, QLatin1String(KEY_SNAPX), m_snapX);
+ valueFromVariantMap(vm, QLatin1String(KEY_SNAPY), m_snapY);
+ valueFromVariantMap(vm, QLatin1String(KEY_DELTAX), m_deltaX);
+ return valueFromVariantMap(vm, QLatin1String(KEY_DELTAY), m_deltaY);
+}
+
+QVariantMap Grid::toVariantMap(bool forceKeys) const
+{
+ QVariantMap rc;
+ addToVariantMap(rc, forceKeys);
+ return rc;
+}
+
+void Grid::addToVariantMap(QVariantMap& vm, bool forceKeys) const
+{
+ valueToVariantMap(m_visible, defaultVisible, QLatin1String(KEY_VISIBLE), vm, forceKeys);
+ valueToVariantMap(m_snapX, defaultSnap, QLatin1String(KEY_SNAPX), vm, forceKeys);
+ valueToVariantMap(m_snapY, defaultSnap, QLatin1String(KEY_SNAPY), vm, forceKeys);
+ valueToVariantMap(m_deltaX, DEFAULT_GRID, QLatin1String(KEY_DELTAX), vm, forceKeys);
+ valueToVariantMap(m_deltaY, DEFAULT_GRID, QLatin1String(KEY_DELTAY), vm, forceKeys);
+}
+
+void Grid::paint(QWidget *widget, QPaintEvent *e) const
+{
+ QPainter p(widget);
+ paint(p, widget, e);
+}
+
+void Grid::paint(QPainter &p, const QWidget *widget, QPaintEvent *e) const
+{
+ p.setPen(widget->palette().dark().color());
+
+ if (m_visible) {
+ const int xstart = (e->rect().x() / m_deltaX) * m_deltaX;
+ const int ystart = (e->rect().y() / m_deltaY) * m_deltaY;
+
+ const int xend = e->rect().right();
+ const int yend = e->rect().bottom();
+
+ typedef QVector<QPointF> Points;
+ static Points points;
+ points.clear();
+
+ for (int x = xstart; x <= xend; x += m_deltaX) {
+ points.reserve((yend - ystart) / m_deltaY + 1);
+ for (int y = ystart; y <= yend; y += m_deltaY)
+ points.push_back(QPointF(x, y));
+ p.drawPoints( &(*points.begin()), points.count());
+ points.clear();
+ }
+ }
+}
+
+int Grid::snapValue(int value, int grid) const
+{
+ const int rest = value % grid;
+ const int absRest = (rest < 0) ? -rest : rest;
+ int offset = 0;
+ if (2 * absRest > grid)
+ offset = 1;
+ if (rest < 0)
+ offset *= -1;
+ return (value / grid + offset) * grid;
+}
+
+QPoint Grid::snapPoint(const QPoint &p) const
+{
+ const int sx = m_snapX ? snapValue(p.x(), m_deltaX) : p.x();
+ const int sy = m_snapY ? snapValue(p.y(), m_deltaY) : p.y();
+ return QPoint(sx, sy);
+}
+
+int Grid::widgetHandleAdjustX(int x) const
+{
+ return m_snapX ? (x / m_deltaX) * m_deltaX + 1 : x;
+}
+
+int Grid::widgetHandleAdjustY(int y) const
+{
+ return m_snapY ? (y / m_deltaY) * m_deltaY + 1 : y;
+}
+
+bool Grid::equals(const Grid &rhs) const
+{
+ return m_visible == rhs.m_visible &&
+ m_snapX == rhs.m_snapX &&
+ m_snapY == rhs.m_snapY &&
+ m_deltaX == rhs.m_deltaX &&
+ m_deltaY == rhs.m_deltaY;
+}
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/grid_p.h b/tools/designer/src/lib/shared/grid_p.h
new file mode 100644
index 0000000..b07217f
--- /dev/null
+++ b/tools/designer/src/lib/shared/grid_p.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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_GRID_H
+#define QDESIGNER_GRID_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QVariantMap>
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+class QPaintEvent;
+class QPainter;
+
+namespace qdesigner_internal {
+
+// Designer grid which is able to serialize to QVariantMap
+class QDESIGNER_SHARED_EXPORT Grid
+{
+public:
+ Grid();
+
+ bool fromVariantMap(const QVariantMap& vm);
+
+ void addToVariantMap(QVariantMap& vm, bool forceKeys = false) const;
+ QVariantMap toVariantMap(bool forceKeys = false) const;
+
+ inline bool visible() const { return m_visible; }
+ void setVisible(bool visible) { m_visible = visible; }
+
+ inline bool snapX() const { return m_snapX; }
+ void setSnapX(bool snap) { m_snapX = snap; }
+
+ inline bool snapY() const { return m_snapY; }
+ void setSnapY(bool snap) { m_snapY = snap; }
+
+ inline int deltaX() const { return m_deltaX; }
+ void setDeltaX(int dx) { m_deltaX = dx; }
+
+ inline int deltaY() const { return m_deltaY; }
+ void setDeltaY(int dy) { m_deltaY = dy; }
+
+ void paint(QWidget *widget, QPaintEvent *e) const;
+ void paint(QPainter &p, const QWidget *widget, QPaintEvent *e) const;
+
+ QPoint snapPoint(const QPoint &p) const;
+
+ int widgetHandleAdjustX(int x) const;
+ int widgetHandleAdjustY(int y) const;
+
+ inline bool operator==(const Grid &rhs) const { return equals(rhs); }
+ inline bool operator!=(const Grid &rhs) const { return !equals(rhs); }
+
+private:
+ bool equals(const Grid &rhs) const;
+ int snapValue(int value, int grid) const;
+ bool m_visible;
+ bool m_snapX;
+ bool m_snapY;
+ int m_deltaX;
+ int m_deltaY;
+};
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_GRID_H
diff --git a/tools/designer/src/lib/shared/gridpanel.cpp b/tools/designer/src/lib/shared/gridpanel.cpp
new file mode 100644
index 0000000..f7658ba
--- /dev/null
+++ b/tools/designer/src/lib/shared/gridpanel.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 "gridpanel_p.h"
+#include "ui_gridpanel.h"
+#include "grid_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+GridPanel::GridPanel(QWidget *parentWidget) :
+ QWidget(parentWidget)
+{
+ m_ui = new Ui::GridPanel;
+ m_ui->setupUi(this);
+
+ connect(m_ui->m_resetButton, SIGNAL(clicked()), this, SLOT(reset()));
+}
+
+GridPanel::~GridPanel()
+{
+ delete m_ui;
+}
+
+void GridPanel::setGrid(const Grid &g)
+{
+ m_ui->m_deltaXSpinBox->setValue(g.deltaX());
+ m_ui->m_deltaYSpinBox->setValue(g.deltaY());
+ m_ui->m_visibleCheckBox->setCheckState(g.visible() ? Qt::Checked : Qt::Unchecked);
+ m_ui->m_snapXCheckBox->setCheckState(g.snapX() ? Qt::Checked : Qt::Unchecked);
+ m_ui->m_snapYCheckBox->setCheckState(g.snapY() ? Qt::Checked : Qt::Unchecked);
+}
+
+void GridPanel::setTitle(const QString &title)
+{
+ m_ui->m_gridGroupBox->setTitle(title);
+}
+
+Grid GridPanel::grid() const
+{
+ Grid rc;
+ rc.setDeltaX(m_ui->m_deltaXSpinBox->value());
+ rc.setDeltaY(m_ui->m_deltaYSpinBox->value());
+ rc.setSnapX(m_ui->m_snapXCheckBox->checkState() == Qt::Checked);
+ rc.setSnapY(m_ui->m_snapYCheckBox->checkState() == Qt::Checked);
+ rc.setVisible(m_ui->m_visibleCheckBox->checkState() == Qt::Checked);
+ return rc;
+}
+
+void GridPanel::reset()
+{
+ setGrid(Grid());
+}
+
+void GridPanel::setCheckable (bool c)
+{
+ m_ui->m_gridGroupBox->setCheckable(c);
+}
+
+bool GridPanel::isCheckable () const
+{
+ return m_ui->m_gridGroupBox->isCheckable ();
+}
+
+bool GridPanel::isChecked () const
+{
+ return m_ui->m_gridGroupBox->isChecked ();
+}
+
+void GridPanel::setChecked(bool c)
+{
+ m_ui->m_gridGroupBox->setChecked(c);
+}
+
+void GridPanel::setResetButtonVisible(bool v)
+{
+ m_ui->m_resetButton->setVisible(v);
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/gridpanel.ui b/tools/designer/src/lib/shared/gridpanel.ui
new file mode 100644
index 0000000..adfdd36
--- /dev/null
+++ b/tools/designer/src/lib/shared/gridpanel.ui
@@ -0,0 +1,144 @@
+<ui version="4.0" >
+ <class>qdesigner_internal::GridPanel</class>
+ <widget class="QWidget" name="qdesigner_internal::GridPanel" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>393</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="m_gridGroupBox" >
+ <property name="title" >
+ <string>Grid</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QCheckBox" name="m_visibleCheckBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Visible</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Grid &amp;X</string>
+ </property>
+ <property name="buddy" >
+ <cstring>m_deltaXSpinBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QSpinBox" name="m_deltaXSpinBox" >
+ <property name="minimum" >
+ <number>2</number>
+ </property>
+ <property name="maximum" >
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QCheckBox" name="m_snapXCheckBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Snap</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="m_resetButton" >
+ <property name="text" >
+ <string>Reset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Grid &amp;Y</string>
+ </property>
+ <property name="buddy" >
+ <cstring>m_deltaYSpinBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QSpinBox" name="m_deltaYSpinBox" >
+ <property name="minimum" >
+ <number>2</number>
+ </property>
+ <property name="maximum" >
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QCheckBox" name="m_snapYCheckBox" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Snap</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/gridpanel_p.h b/tools/designer/src/lib/shared/gridpanel_p.h
new file mode 100644
index 0000000..c51b08c
--- /dev/null
+++ b/tools/designer/src/lib/shared/gridpanel_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 the Qt tools. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef GRIDPANEL_H
+#define GRIDPANEL_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class Grid;
+
+namespace Ui {
+ class GridPanel;
+}
+
+class QDESIGNER_SHARED_EXPORT GridPanel : public QWidget
+{
+ Q_OBJECT
+public:
+ GridPanel(QWidget *parent = 0);
+ ~GridPanel();
+
+ void setTitle(const QString &title);
+
+ void setGrid(const Grid &g);
+ Grid grid() const;
+
+ void setCheckable (bool c);
+ bool isCheckable () const;
+
+ bool isChecked () const;
+ void setChecked(bool c);
+
+ void setResetButtonVisible(bool v);
+
+private slots:
+ void reset();
+
+private:
+ Ui::GridPanel *m_ui;
+};
+
+} // qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // GRIDPANEL_H
diff --git a/tools/designer/src/lib/shared/htmlhighlighter.cpp b/tools/designer/src/lib/shared/htmlhighlighter.cpp
new file mode 100644
index 0000000..ba07673
--- /dev/null
+++ b/tools/designer/src/lib/shared/htmlhighlighter.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** 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/QTextStream>
+
+#include "htmlhighlighter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+HtmlHighlighter::HtmlHighlighter(QTextEdit *textEdit)
+ : QSyntaxHighlighter(textEdit)
+{
+ QTextCharFormat entityFormat;
+ entityFormat.setForeground(Qt::red);
+ setFormatFor(Entity, entityFormat);
+
+ QTextCharFormat tagFormat;
+ tagFormat.setForeground(Qt::darkMagenta);
+ tagFormat.setFontWeight(QFont::Bold);
+ setFormatFor(Tag, tagFormat);
+
+ QTextCharFormat commentFormat;
+ commentFormat.setForeground(Qt::gray);
+ commentFormat.setFontItalic(true);
+ setFormatFor(Comment, commentFormat);
+
+ QTextCharFormat attributeFormat;
+ attributeFormat.setForeground(Qt::black);
+ attributeFormat.setFontWeight(QFont::Bold);
+ setFormatFor(Attribute, attributeFormat);
+
+ QTextCharFormat valueFormat;
+ valueFormat.setForeground(Qt::blue);
+ setFormatFor(Value, valueFormat);
+}
+
+void HtmlHighlighter::setFormatFor(Construct construct,
+ const QTextCharFormat &format)
+{
+ m_formats[construct] = format;
+ rehighlight();
+}
+
+void HtmlHighlighter::highlightBlock(const QString &text)
+{
+ static const QLatin1Char tab = QLatin1Char('\t');
+ static const QLatin1Char space = QLatin1Char(' ');
+ static const QLatin1Char amp = QLatin1Char('&');
+ static const QLatin1Char startTag = QLatin1Char('<');
+ static const QLatin1Char endTag = QLatin1Char('>');
+ static const QLatin1Char quot = QLatin1Char('"');
+ static const QLatin1Char apos = QLatin1Char('\'');
+ static const QLatin1Char semicolon = QLatin1Char(';');
+ static const QLatin1Char equals = QLatin1Char('=');
+ static const QLatin1String startComment = QLatin1String("<!--");
+ static const QLatin1String endComment = QLatin1String("-->");
+ static const QLatin1String endElement = QLatin1String("/>");
+
+ int state = previousBlockState();
+ int len = text.length();
+ int start = 0;
+ int pos = 0;
+
+ while (pos < len) {
+ switch (state) {
+ case NormalState:
+ default:
+ while (pos < len) {
+ QChar ch = text.at(pos);
+ if (ch == startTag) {
+ if (text.mid(pos, 4) == startComment) {
+ state = InComment;
+ } else {
+ state = InTag;
+ start = pos;
+ while (pos < len && text.at(pos) != space
+ && text.at(pos) != endTag
+ && text.at(pos) != tab
+ && text.mid(pos, 2) != endElement)
+ ++pos;
+ if (text.mid(pos, 2) == endElement)
+ ++pos;
+ setFormat(start, pos - start,
+ m_formats[Tag]);
+ break;
+ }
+ break;
+ } else if (ch == amp) {
+ start = pos;
+ while (pos < len && text.at(pos++) != semicolon)
+ ;
+ setFormat(start, pos - start,
+ m_formats[Entity]);
+ } else {
+ // No tag, comment or entity started, continue...
+ ++pos;
+ }
+ }
+ break;
+ case InComment:
+ start = pos;
+ while (pos < len) {
+ if (text.mid(pos, 3) == endComment) {
+ pos += 3;
+ state = NormalState;
+ break;
+ } else {
+ ++pos;
+ }
+ }
+ setFormat(start, pos - start, m_formats[Comment]);
+ break;
+ case InTag:
+ QChar quote = QChar::Null;
+ while (pos < len) {
+ QChar ch = text.at(pos);
+ if (quote.isNull()) {
+ start = pos;
+ if (ch == apos || ch == quot) {
+ quote = ch;
+ } else if (ch == endTag) {
+ ++pos;
+ setFormat(start, pos - start, m_formats[Tag]);
+ state = NormalState;
+ break;
+ } else if (text.mid(pos, 2) == endElement) {
+ pos += 2;
+ setFormat(start, pos - start, m_formats[Tag]);
+ state = NormalState;
+ break;
+ } else if (ch != space && text.at(pos) != tab) {
+ // Tag not ending, not a quote and no whitespace, so
+ // we must be dealing with an attribute.
+ ++pos;
+ while (pos < len && text.at(pos) != space
+ && text.at(pos) != tab
+ && text.at(pos) != equals)
+ ++pos;
+ setFormat(start, pos - start, m_formats[Attribute]);
+ start = pos;
+ }
+ } else if (ch == quote) {
+ quote = QChar::Null;
+
+ // Anything quoted is a value
+ setFormat(start, pos - start, m_formats[Value]);
+ }
+ ++pos;
+ }
+ break;
+ }
+ }
+ setCurrentBlockState(state);
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/htmlhighlighter_p.h b/tools/designer/src/lib/shared/htmlhighlighter_p.h
new file mode 100644
index 0000000..e841ec7
--- /dev/null
+++ b/tools/designer/src/lib/shared/htmlhighlighter_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 HTMLHIGHLIGHTER_H
+#define HTMLHIGHLIGHTER_H
+
+#include <QtGui/QSyntaxHighlighter>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+/* HTML syntax highlighter based on Qt Quarterly example */
+class HtmlHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+
+public:
+ enum Construct {
+ Entity,
+ Tag,
+ Comment,
+ Attribute,
+ Value,
+ LastConstruct = Value
+ };
+
+ HtmlHighlighter(QTextEdit *textEdit);
+
+ void setFormatFor(Construct construct, const QTextCharFormat &format);
+
+ QTextCharFormat formatFor(Construct construct) const
+ { return m_formats[construct]; }
+
+protected:
+ enum State {
+ NormalState = -1,
+ InComment,
+ InTag
+ };
+
+ void highlightBlock(const QString &text);
+
+private:
+ QTextCharFormat m_formats[LastConstruct + 1];
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // HTMLHIGHLIGHTER_H
diff --git a/tools/designer/src/lib/shared/iconloader.cpp b/tools/designer/src/lib/shared/iconloader.cpp
new file mode 100644
index 0000000..b2df262
--- /dev/null
+++ b/tools/designer/src/lib/shared/iconloader.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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 "iconloader_p.h"
+
+#include <QtCore/QFile>
+#include <QtGui/QIcon>
+#include <QtGui/QPixmap>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+QDESIGNER_SHARED_EXPORT QIcon createIconSet(const QString &name)
+{
+ QStringList candidates = QStringList()
+ << (QString::fromUtf8(":/trolltech/formeditor/images/") + name)
+#ifdef Q_WS_MAC
+ << (QString::fromUtf8(":/trolltech/formeditor/images/mac/") + name)
+#else
+ << (QString::fromUtf8(":/trolltech/formeditor/images/win/") + name)
+#endif
+ << (QString::fromUtf8(":/trolltech/formeditor/images/designer_") + name);
+
+ foreach (QString f, candidates) {
+ if (QFile::exists(f))
+ return QIcon(f);
+ }
+
+ return QIcon();
+}
+
+QDESIGNER_SHARED_EXPORT QIcon emptyIcon()
+{
+ static const QIcon empty_icon(QLatin1String(":/trolltech/formeditor/images/emptyicon.png"));
+ return empty_icon;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
diff --git a/tools/designer/src/lib/shared/iconloader_p.h b/tools/designer/src/lib/shared/iconloader_p.h
new file mode 100644
index 0000000..572aab9
--- /dev/null
+++ b/tools/designer/src/lib/shared/iconloader_p.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$
+**
+****************************************************************************/
+
+//
+// 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 ICONLOADER_H
+#define ICONLOADER_H
+
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QIcon;
+
+namespace qdesigner_internal {
+
+QDESIGNER_SHARED_EXPORT QIcon createIconSet(const QString &name);
+QDESIGNER_SHARED_EXPORT QIcon emptyIcon();
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // ICONLOADER_H
diff --git a/tools/designer/src/lib/shared/iconselector.cpp b/tools/designer/src/lib/shared/iconselector.cpp
new file mode 100644
index 0000000..02a3dee
--- /dev/null
+++ b/tools/designer/src/lib/shared/iconselector.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 "iconselector_p.h"
+#include "qdesigner_utils_p.h"
+#include "qtresourcemodel_p.h"
+#include "qtresourceview_p.h"
+#include "iconloader_p.h"
+#include "qdesigner_integration_p.h"
+#include "formwindowbase_p.h"
+
+#include <abstractdialoggui_p.h>
+#include <qdesigner_integration_p.h>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerResourceBrowserInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QToolButton>
+#include <QtCore/QSignalMapper>
+#include <QtGui/QComboBox>
+#include <QtGui/QAction>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QPushButton>
+#include <QtGui/QDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QApplication>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QImageReader>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QVBoxLayout>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// -------------------- LanguageResourceDialogPrivate
+class LanguageResourceDialogPrivate {
+ LanguageResourceDialog *q_ptr;
+ Q_DECLARE_PUBLIC(LanguageResourceDialog)
+
+public:
+ LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb);
+ void init(LanguageResourceDialog *p);
+
+ void setCurrentPath(const QString &filePath);
+ QString currentPath() const;
+
+ void slotAccepted();
+ void slotPathChanged(const QString &);
+
+private:
+ void setOkButtonEnabled(bool v) { m_dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(v); }
+ static bool checkPath(const QString &p);
+
+ QDesignerResourceBrowserInterface *m_browser;
+ QDialogButtonBox *m_dialogButtonBox;
+};
+
+LanguageResourceDialogPrivate::LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb) :
+ q_ptr(0),
+ m_browser(rb),
+ m_dialogButtonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel))
+{
+ setOkButtonEnabled(false);
+}
+
+void LanguageResourceDialogPrivate::init(LanguageResourceDialog *p)
+{
+ q_ptr = p;
+ QLayout *layout = new QVBoxLayout(p);
+ layout->addWidget(m_browser);
+ layout->addWidget(m_dialogButtonBox);
+ QObject::connect(m_dialogButtonBox, SIGNAL(accepted()), p, SLOT(slotAccepted()));
+ QObject::connect(m_dialogButtonBox, SIGNAL(rejected()), p, SLOT(reject()));
+ QObject::connect(m_browser, SIGNAL(currentPathChanged(QString)), p, SLOT(slotPathChanged(QString)));
+ QObject::connect(m_browser, SIGNAL(pathActivated(QString)), p, SLOT(slotAccepted()));
+ p->setModal(true);
+ p->setWindowTitle(LanguageResourceDialog::tr("Choose Resource"));
+ p->setWindowFlags(p->windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setOkButtonEnabled(false);
+}
+
+void LanguageResourceDialogPrivate::setCurrentPath(const QString &filePath)
+{
+ m_browser->setCurrentPath(filePath);
+ setOkButtonEnabled(checkPath(filePath));
+}
+
+QString LanguageResourceDialogPrivate::currentPath() const
+{
+ return m_browser->currentPath();
+}
+
+bool LanguageResourceDialogPrivate::checkPath(const QString &p)
+{
+ return p.isEmpty() ? false : IconSelector::checkPixmap(p, IconSelector::CheckFast);
+}
+
+void LanguageResourceDialogPrivate::slotAccepted()
+{
+ if (checkPath(currentPath()))
+ q_ptr->accept();
+}
+
+void LanguageResourceDialogPrivate::slotPathChanged(const QString &p)
+{
+ setOkButtonEnabled(checkPath(p));
+}
+
+// ------------ LanguageResourceDialog
+LanguageResourceDialog::LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent) :
+ QDialog(parent),
+ d_ptr(new LanguageResourceDialogPrivate(rb))
+{
+ d_ptr->init( this);
+}
+
+LanguageResourceDialog::~LanguageResourceDialog()
+{
+ delete d_ptr;
+}
+
+void LanguageResourceDialog::setCurrentPath(const QString &filePath)
+{
+ d_ptr->setCurrentPath(filePath);
+}
+
+QString LanguageResourceDialog::currentPath() const
+{
+ return d_ptr->currentPath();
+}
+
+LanguageResourceDialog* LanguageResourceDialog::create(QDesignerFormEditorInterface *core, QWidget *parent)
+{
+ if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core))
+ if (QDesignerResourceBrowserInterface *rb = lang->createResourceBrowser(0))
+ return new LanguageResourceDialog(rb, parent);
+ if (QDesignerIntegration *di = qobject_cast<QDesignerIntegration*>(core->integration()))
+ if (QDesignerResourceBrowserInterface *rb = di->createResourceBrowser(0))
+ return new LanguageResourceDialog(rb, parent);
+ return 0;
+}
+
+// ------------ IconSelectorPrivate
+class IconSelectorPrivate
+{
+ IconSelector *q_ptr;
+ Q_DECLARE_PUBLIC(IconSelector)
+public:
+ IconSelectorPrivate();
+
+ void slotStateActivated();
+ void slotSetActivated();
+ void slotSetResourceActivated();
+ void slotSetFileActivated();
+ void slotResetActivated();
+ void slotResetAllActivated();
+ void slotUpdate();
+
+ QList<QPair<QPair<QIcon::Mode, QIcon::State>, QString> > m_stateToName; // could be static map
+
+ QMap<QPair<QIcon::Mode, QIcon::State>, int> m_stateToIndex;
+ QMap<int, QPair<QIcon::Mode, QIcon::State> > m_indexToState;
+
+ QIcon m_emptyIcon;
+ QComboBox *m_stateComboBox;
+ QToolButton *m_iconButton;
+ QAction *m_resetAction;
+ QAction *m_resetAllAction;
+ PropertySheetIconValue m_icon;
+ DesignerIconCache *m_iconCache;
+ DesignerPixmapCache *m_pixmapCache;
+ QtResourceModel *m_resourceModel;
+ QDesignerFormEditorInterface *m_core;
+};
+
+IconSelectorPrivate::IconSelectorPrivate() :
+ q_ptr(0),
+ m_stateComboBox(0),
+ m_iconButton(0),
+ m_resetAction(0),
+ m_resetAllAction(0),
+ m_iconCache(0),
+ m_pixmapCache(0),
+ m_resourceModel(0),
+ m_core(0)
+{
+}
+void IconSelectorPrivate::slotUpdate()
+{
+ QIcon icon;
+ if (m_iconCache)
+ icon = m_iconCache->icon(m_icon);
+
+ QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> paths = m_icon.paths();
+ QMapIterator<QPair<QIcon::Mode, QIcon::State>, int> itIndex(m_stateToIndex);
+ while (itIndex.hasNext()) {
+ const QPair<QIcon::Mode, QIcon::State> state = itIndex.next().key();
+ const PropertySheetPixmapValue pixmap = paths.value(state);
+ const int index = itIndex.value();
+
+ QIcon pixmapIcon = QIcon(icon.pixmap(16, 16, state.first, state.second));
+ if (pixmapIcon.isNull())
+ pixmapIcon = m_emptyIcon;
+ m_stateComboBox->setItemIcon(index, pixmapIcon);
+ QFont font = q_ptr->font();
+ if (!pixmap.path().isEmpty())
+ font.setBold(true);
+ m_stateComboBox->setItemData(index, font, Qt::FontRole);
+ }
+
+ QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
+ PropertySheetPixmapValue currentPixmap = paths.value(state);
+ m_resetAction->setEnabled(!currentPixmap.path().isEmpty());
+ m_resetAllAction->setEnabled(!paths.isEmpty());
+ m_stateComboBox->update();
+}
+
+void IconSelectorPrivate::slotStateActivated()
+{
+ slotUpdate();
+}
+
+void IconSelectorPrivate::slotSetActivated()
+{
+ QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
+ const PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
+ // Default to resource
+ const PropertySheetPixmapValue::PixmapSource ps = pixmap.path().isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : pixmap.pixmapSource(m_core);
+ switch (ps) {
+ case PropertySheetPixmapValue::LanguageResourcePixmap:
+ case PropertySheetPixmapValue::ResourcePixmap:
+ slotSetResourceActivated();
+ break;
+ case PropertySheetPixmapValue::FilePixmap:
+ slotSetFileActivated();
+ break;
+ }
+}
+
+// Choose a pixmap from resource; use language-dependent resource browser if present
+QString IconSelector::choosePixmapResource(QDesignerFormEditorInterface *core, QtResourceModel *resourceModel, const QString &oldPath, QWidget *parent)
+{
+ Q_UNUSED(resourceModel)
+ QString rc;
+
+ if (LanguageResourceDialog* ldlg = LanguageResourceDialog::create(core, parent)) {
+ ldlg->setCurrentPath(oldPath);
+ if (ldlg->exec() == QDialog::Accepted)
+ rc = ldlg->currentPath();
+ delete ldlg;
+ } else {
+ QtResourceViewDialog dlg(core, parent);
+
+ QDesignerIntegration *designerIntegration = qobject_cast<QDesignerIntegration *>(core->integration());
+ if (designerIntegration)
+ dlg.setResourceEditingEnabled(designerIntegration->isResourceEditingEnabled());
+
+ dlg.selectResource(oldPath);
+ if (dlg.exec() == QDialog::Accepted)
+ rc = dlg.selectedResource();
+ }
+ return rc;
+}
+
+void IconSelectorPrivate::slotSetResourceActivated()
+{
+ const QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
+
+ PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
+ const QString oldPath = pixmap.path();
+ const QString newPath = IconSelector::choosePixmapResource(m_core, m_resourceModel, oldPath, q_ptr);
+ if (newPath.isEmpty() || newPath == oldPath)
+ return;
+ const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath);
+ if (newPixmap != pixmap) {
+ m_icon.setPixmap(state.first, state.second, newPixmap);
+ slotUpdate();
+ emit q_ptr->iconChanged(m_icon);
+ }
+}
+
+// Helpers for choosing image files: Check for valid image.
+bool IconSelector::checkPixmap(const QString &fileName, CheckMode cm, QString *errorMessage)
+{
+ const QFileInfo fi(fileName);
+ if (!fi.exists() || !fi.isFile() || !fi.isReadable()) {
+ if (errorMessage)
+ *errorMessage = tr("The pixmap file '%1' cannot be read.").arg(fileName);
+ return false;
+ }
+ QImageReader reader(fileName);
+ if (!reader.canRead()) {
+ if (errorMessage)
+ *errorMessage = tr("The file '%1' does not appear to be a valid pixmap file: %2").arg(fileName).arg(reader.errorString());
+ return false;
+ }
+ if (cm == CheckFast)
+ return true;
+
+ const QImage image = reader.read();
+ if (image.isNull()) {
+ if (errorMessage)
+ *errorMessage = tr("The file '%1' could not be read: %2").arg(fileName).arg(reader.errorString());
+ return false;
+ }
+ return true;
+}
+
+// Helpers for choosing image files: Return an image filter for QFileDialog, courtesy of StyledButton
+static QString imageFilter()
+{
+ QString filter = QApplication::translate("IconSelector", "All Pixmaps (");
+ const QList<QByteArray> supportedImageFormats = QImageReader::supportedImageFormats();
+ const QString jpeg = QLatin1String("JPEG");
+ const int count = supportedImageFormats.count();
+ for (int i = 0; i< count; ++i) {
+ if (i)
+ filter += QLatin1Char(' ');
+ filter += QLatin1String("*.");
+ const QString outputFormat = QString::fromUtf8(supportedImageFormats.at(i));
+ if (outputFormat != jpeg)
+ filter += outputFormat.toLower();
+ else
+ filter += QLatin1String("jpg *.jpeg");
+ }
+ filter += QLatin1Char(')');
+ return filter;
+}
+
+// Helpers for choosing image files: Choose a file
+QString IconSelector::choosePixmapFile(const QString &directory, QDesignerDialogGuiInterface *dlgGui,QWidget *parent)
+{
+ QString errorMessage;
+ QString newPath;
+ do {
+ const QString title = tr("Choose a Pixmap");
+ static const QString filter = imageFilter();
+ newPath = dlgGui->getOpenImageFileName(parent, title, directory, filter);
+ if (newPath.isEmpty())
+ break;
+ if (checkPixmap(newPath, CheckFully, &errorMessage))
+ break;
+ dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, tr("Pixmap Read Error"), errorMessage);
+ } while(true);
+ return newPath;
+}
+
+void IconSelectorPrivate::slotSetFileActivated()
+{
+ QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
+
+ PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
+ const QString newPath = IconSelector::choosePixmapFile(pixmap.path(), m_core->dialogGui(), q_ptr);
+ if (!newPath.isEmpty()) {
+ const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath);
+ if (!(newPixmap == pixmap)) {
+ m_icon.setPixmap(state.first, state.second, newPixmap);
+ slotUpdate();
+ emit q_ptr->iconChanged(m_icon);
+ }
+ }
+}
+
+void IconSelectorPrivate::slotResetActivated()
+{
+ QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
+
+ PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
+ const PropertySheetPixmapValue newPixmap;
+ if (!(newPixmap == pixmap)) {
+ m_icon.setPixmap(state.first, state.second, newPixmap);
+ slotUpdate();
+ emit q_ptr->iconChanged(m_icon);
+ }
+}
+
+void IconSelectorPrivate::slotResetAllActivated()
+{
+ const PropertySheetIconValue newIcon;
+ if (!(m_icon == newIcon)) {
+ m_icon = newIcon;
+ slotUpdate();
+ emit q_ptr->iconChanged(m_icon);
+ }
+}
+
+// ------------- IconSelector
+IconSelector::IconSelector(QWidget *parent) :
+ QWidget(parent)
+{
+ d_ptr = new IconSelectorPrivate();
+ d_ptr->q_ptr = this;
+
+ d_ptr->m_stateComboBox = new QComboBox(this);
+
+ QHBoxLayout *l = new QHBoxLayout(this);
+ d_ptr->m_iconButton = new QToolButton(this);
+ d_ptr->m_iconButton->setText(tr("..."));
+ d_ptr->m_iconButton->setPopupMode(QToolButton::MenuButtonPopup);
+ l->addWidget(d_ptr->m_stateComboBox);
+ l->addWidget(d_ptr->m_iconButton);
+ l->setMargin(0);
+
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal, QIcon::Off), tr("Normal Off") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal, QIcon::On), tr("Normal On") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::Off), tr("Disabled Off") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::On), tr("Disabled On") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active, QIcon::Off), tr("Active Off") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active, QIcon::On), tr("Active On") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::Off), tr("Selected Off") );
+ d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::On), tr("Selected On") );
+
+ QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ d_ptr->m_emptyIcon = QIcon(QPixmap::fromImage(img));
+
+ QMenu *setMenu = new QMenu(this);
+
+ QAction *setResourceAction = new QAction(tr("Choose Resource..."), this);
+ QAction *setFileAction = new QAction(tr("Choose File..."), this);
+ d_ptr->m_resetAction = new QAction(tr("Reset"), this);
+ d_ptr->m_resetAllAction = new QAction(tr("Reset All"), this);
+ d_ptr->m_resetAction->setEnabled(false);
+ d_ptr->m_resetAllAction->setEnabled(false);
+ //d_ptr->m_resetAction->setIcon(createIconSet(QString::fromUtf8("resetproperty.png")));
+
+ setMenu->addAction(setResourceAction);
+ setMenu->addAction(setFileAction);
+ setMenu->addSeparator();
+ setMenu->addAction(d_ptr->m_resetAction);
+ setMenu->addAction(d_ptr->m_resetAllAction);
+
+ int index = 0;
+ QStringList items;
+ QListIterator<QPair<QPair<QIcon::Mode, QIcon::State>, QString> > itName(d_ptr->m_stateToName);
+ while (itName.hasNext()) {
+ QPair<QPair<QIcon::Mode, QIcon::State>, QString> item = itName.next();
+ const QPair<QIcon::Mode, QIcon::State> state = item.first;
+ const QString name = item.second;
+
+ items.append(name);
+ d_ptr->m_stateToIndex[state] = index;
+ d_ptr->m_indexToState[index] = state;
+ index++;
+ }
+ d_ptr->m_stateComboBox->addItems(items);
+
+ d_ptr->m_iconButton->setMenu(setMenu);
+
+ connect(d_ptr->m_stateComboBox, SIGNAL(activated(int)), this, SLOT(slotStateActivated()));
+ connect(d_ptr->m_iconButton, SIGNAL(clicked()), this, SLOT(slotSetActivated()));
+ connect(setResourceAction, SIGNAL(triggered()), this, SLOT(slotSetResourceActivated()));
+ connect(setFileAction, SIGNAL(triggered()), this, SLOT(slotSetFileActivated()));
+ connect(d_ptr->m_resetAction, SIGNAL(triggered()), this, SLOT(slotResetActivated()));
+ connect(d_ptr->m_resetAllAction, SIGNAL(triggered()), this, SLOT(slotResetAllActivated()));
+
+ d_ptr->slotUpdate();
+}
+
+IconSelector::~IconSelector()
+{
+ delete d_ptr;
+}
+
+void IconSelector::setIcon(const PropertySheetIconValue &icon)
+{
+ if (d_ptr->m_icon == icon)
+ return;
+
+ d_ptr->m_icon = icon;
+ d_ptr->slotUpdate();
+}
+
+PropertySheetIconValue IconSelector::icon() const
+{
+ return d_ptr->m_icon;
+}
+
+void IconSelector::setFormEditor(QDesignerFormEditorInterface *core)
+{
+ d_ptr->m_core = core;
+ d_ptr->m_resourceModel = core->resourceModel();
+ d_ptr->slotUpdate();
+}
+
+void IconSelector::setIconCache(DesignerIconCache *iconCache)
+{
+ d_ptr->m_iconCache = iconCache;
+ connect(iconCache, SIGNAL(reloaded()), this, SLOT(slotUpdate()));
+ d_ptr->slotUpdate();
+}
+
+void IconSelector::setPixmapCache(DesignerPixmapCache *pixmapCache)
+{
+ d_ptr->m_pixmapCache = pixmapCache;
+ connect(pixmapCache, SIGNAL(reloaded()), this, SLOT(slotUpdate()));
+ d_ptr->slotUpdate();
+}
+
+} // qdesigner_internal
+
+QT_END_NAMESPACE
+
+#include "moc_iconselector_p.cpp"
+
diff --git a/tools/designer/src/lib/shared/iconselector_p.h b/tools/designer/src/lib/shared/iconselector_p.h
new file mode 100644
index 0000000..6b70cd2
--- /dev/null
+++ b/tools/designer/src/lib/shared/iconselector_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 ICONSELECTOR_H
+#define ICONSELECTOR_H
+
+#include "shared_global_p.h"
+#include <QtGui/QWidget>
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QtResourceModel;
+class QDesignerFormEditorInterface;
+class QDesignerDialogGuiInterface;
+class QDesignerResourceBrowserInterface;
+
+namespace qdesigner_internal {
+
+class DesignerIconCache;
+class DesignerPixmapCache;
+class PropertySheetIconValue;
+
+// Resource Dialog that embeds the language-dependent resource widget as returned by the language extension
+class QDESIGNER_SHARED_EXPORT LanguageResourceDialog : public QDialog
+{
+ Q_OBJECT
+
+ LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent = 0);
+
+public:
+ virtual ~LanguageResourceDialog();
+ // Factory: Returns 0 if the language extension does not provide a resource browser.
+ static LanguageResourceDialog* create(QDesignerFormEditorInterface *core, QWidget *parent);
+
+ void setCurrentPath(const QString &filePath);
+ QString currentPath() const;
+
+private:
+ class LanguageResourceDialogPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(LanguageResourceDialog)
+ Q_DISABLE_COPY(LanguageResourceDialog)
+ Q_PRIVATE_SLOT(d_func(), void slotAccepted())
+ Q_PRIVATE_SLOT(d_func(), void slotPathChanged(QString))
+
+};
+
+class QDESIGNER_SHARED_EXPORT IconSelector: public QWidget
+{
+ Q_OBJECT
+public:
+ IconSelector(QWidget *parent = 0);
+ virtual ~IconSelector();
+
+ void setFormEditor(QDesignerFormEditorInterface *core); // required for dialog gui.
+ void setIconCache(DesignerIconCache *iconCache);
+ void setPixmapCache(DesignerPixmapCache *pixmapCache);
+
+ void setIcon(const PropertySheetIconValue &icon);
+ PropertySheetIconValue icon() const;
+
+ // Check whether a pixmap may be read
+ enum CheckMode { CheckFast, CheckFully };
+ static bool checkPixmap(const QString &fileName, CheckMode cm = CheckFully, QString *errorMessage = 0);
+ // Choose a pixmap from file
+ static QString choosePixmapFile(const QString &directory, QDesignerDialogGuiInterface *dlgGui, QWidget *parent);
+ // Choose a pixmap from resource; use language-dependent resource browser if present
+ static QString choosePixmapResource(QDesignerFormEditorInterface *core, QtResourceModel *resourceModel, const QString &oldPath, QWidget *parent);
+
+signals:
+ void iconChanged(const PropertySheetIconValue &icon);
+private:
+ class IconSelectorPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(IconSelector)
+ Q_DISABLE_COPY(IconSelector)
+
+ Q_PRIVATE_SLOT(d_func(), void slotStateActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotSetActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotSetResourceActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotSetFileActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotResetActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotResetAllActivated())
+ Q_PRIVATE_SLOT(d_func(), void slotUpdate())
+};
+
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // ICONSELECTOR_H
+
diff --git a/tools/designer/src/lib/shared/invisible_widget.cpp b/tools/designer/src/lib/shared/invisible_widget.cpp
new file mode 100644
index 0000000..f88022c
--- /dev/null
+++ b/tools/designer/src/lib/shared/invisible_widget.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "invisible_widget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+InvisibleWidget::InvisibleWidget(QWidget *parent)
+ : QWidget()
+{
+ setAttribute(Qt::WA_NoChildEventsForParent);
+ setParent(parent);
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/invisible_widget_p.h b/tools/designer/src/lib/shared/invisible_widget_p.h
new file mode 100644
index 0000000..11c8f81
--- /dev/null
+++ b/tools/designer/src/lib/shared/invisible_widget_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 INVISIBLE_WIDGET_H
+#define INVISIBLE_WIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT InvisibleWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ InvisibleWidget(QWidget *parent = 0);
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // INVISIBLE_WIDGET_H
diff --git a/tools/designer/src/lib/shared/layout.cpp b/tools/designer/src/lib/shared/layout.cpp
new file mode 100644
index 0000000..b1fe02a
--- /dev/null
+++ b/tools/designer/src/lib/shared/layout.cpp
@@ -0,0 +1,1326 @@
+/****************************************************************************
+**
+** 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_p.h"
+#include "qdesigner_utils_p.h"
+#include "qlayout_widget_p.h"
+#include "spacer_widget_p.h"
+#include "layoutdecoration.h"
+#include "widgetfactory_p.h"
+#include "qdesigner_widgetitem_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/QVector>
+
+#include <QtGui/qevent.h>
+#include <QtGui/QGridLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QBitmap>
+#include <QtGui/QSplitter>
+#include <QtGui/QMainWindow>
+#include <QtGui/QApplication>
+#include <QtGui/QScrollArea>
+#include <QtGui/QFormLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QWizardPage>
+#include <QtGui/QWizard>
+#include <QtCore/QDebug>
+#include <QtCore/QSet>
+
+QT_BEGIN_NAMESPACE
+
+enum { FormLayoutColumns = 2 };
+
+namespace qdesigner_internal {
+
+/* The wizard has a policy of setting a size policy of its external children
+ * according to the page being expanding or not (in the latter case, the
+ * page will be pushed to the top). When setting/breaking layouts, this needs
+ * to be updated, which happens via a fake style change event. */
+
+void updateWizardLayout(QWidget *layoutBase);
+
+class FriendlyWizardPage : public QWizardPage {
+ friend void updateWizardLayout(QWidget *);
+};
+
+void updateWizardLayout(QWidget *layoutBase)
+{
+ if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(layoutBase))
+ if (QWizard *wizard = static_cast<FriendlyWizardPage*>(wizardPage)->wizard()) {
+ QEvent event(QEvent::StyleChange);
+ QApplication::sendEvent(wizard, &event);
+ }
+}
+
+/*!
+ \class Layout layout.h
+ \brief Baseclass for layouting widgets in the Designer (Helper for Layout commands)
+ \internal
+
+ Classes derived from this abstract base class are used for layouting
+ operations in the Designer (creating/breaking layouts).
+
+ Instances live in the Layout/BreakLayout commands.
+*/
+
+/*! \a p specifies the parent of the layoutBase \a lb. The parent
+ might be changed in setup(). If the layoutBase is a
+ container, the parent and the layoutBase are the same. Also they
+ always have to be a widget known to the designer (e.g. in the case
+ of the tabwidget parent and layoutBase are the tabwidget and not the
+ page which actually gets laid out. For actual usage the correct
+ widget is found later by Layout.)
+ */
+
+Layout::Layout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, LayoutInfo::Type layoutType) :
+ m_widgets(wl),
+ m_parentWidget(p),
+ m_layoutBase(lb),
+ m_formWindow(fw),
+ m_layoutType(layoutType),
+ m_reparentLayoutWidget(true),
+ m_isBreak(false)
+{
+ if (m_layoutBase)
+ m_oldGeometry = m_layoutBase->geometry();
+}
+
+Layout::~Layout()
+{
+}
+
+/*! The widget list we got in the constructor might contain too much
+ widgets (like widgets with different parents, already laid out
+ widgets, etc.). Here we set up the list and so the only the "best"
+ widgets get laid out.
+*/
+
+void Layout::setup()
+{
+ m_startPoint = QPoint(32767, 32767);
+
+ // Go through all widgets of the list we got. As we can only
+ // layout widgets which have the same parent, we first do some
+ // sorting which means create a list for each parent containing
+ // its child here. After that we keep working on the list of
+ // children which has the most entries.
+ // Widgets which are already laid out are thrown away here too
+
+ QMultiMap<QWidget*, QWidget*> lists;
+ foreach (QWidget *w, m_widgets) {
+ QWidget *p = w->parentWidget();
+
+ if (p && LayoutInfo::layoutType(m_formWindow->core(), p) != LayoutInfo::NoLayout
+ && m_formWindow->core()->metaDataBase()->item(p->layout()) != 0)
+ continue;
+
+ lists.insert(p, w);
+ }
+
+ QWidgetList lastList;
+ QWidgetList parents = lists.keys();
+ foreach (QWidget *p, parents) {
+ QWidgetList children = lists.values(p);
+
+ if (children.count() > lastList.count())
+ lastList = children;
+ }
+
+
+ // If we found no list (because no widget did fit at all) or the
+ // best list has only one entry and we do not layout a container,
+ // we leave here.
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase();
+ if (lastList.count() < 2 &&
+ (!m_layoutBase ||
+ (!widgetDataBase->isContainer(m_layoutBase, false) &&
+ m_layoutBase != m_formWindow->mainContainer()))
+ ) {
+ m_widgets.clear();
+ m_startPoint = QPoint(0, 0);
+ return;
+ }
+
+ // Now we have a new and clean widget list, which makes sense
+ // to layout
+ m_widgets = lastList;
+ // Also use the only correct parent later, so store it
+
+ Q_ASSERT(m_widgets.isEmpty() == false);
+
+ m_parentWidget = m_formWindow->core()->widgetFactory()->widgetOfContainer(m_widgets.first()->parentWidget());
+ // Now calculate the position where the layout-meta-widget should
+ // be placed and connect to widgetDestroyed() signals of the
+ // widgets to get informed if one gets deleted to be able to
+ // handle that and do not crash in this case
+ foreach (QWidget *w, m_widgets) {
+ connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
+ m_startPoint = QPoint(qMin(m_startPoint.x(), w->x()), qMin(m_startPoint.y(), w->y()));
+ const QRect rc(w->geometry());
+
+ m_geometries.insert(w, rc);
+ // Change the Z-order, as saving/loading uses the Z-order for
+ // writing/creating widgets and this has to be the same as in
+ // the layout. Else saving + loading will give different results
+ w->raise();
+ }
+
+ sort();
+}
+
+void Layout::widgetDestroyed()
+{
+ if (QWidget *w = qobject_cast<QWidget *>(sender())) {
+ m_widgets.removeAt(m_widgets.indexOf(w));
+ m_geometries.remove(w);
+ }
+}
+
+bool Layout::prepareLayout(bool &needMove, bool &needReparent)
+{
+ foreach (QWidget *widget, m_widgets) {
+ widget->raise();
+ }
+
+ needMove = !m_layoutBase;
+ needReparent = needMove || (m_reparentLayoutWidget && qobject_cast<QLayoutWidget*>(m_layoutBase)) || qobject_cast<QSplitter*>(m_layoutBase);
+
+ QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory();
+ QDesignerMetaDataBaseInterface *metaDataBase = m_formWindow->core()->metaDataBase();
+
+ if (m_layoutBase == 0) {
+ const bool useSplitter = m_layoutType == LayoutInfo::HSplitter || m_layoutType == LayoutInfo::VSplitter;
+ const QString baseWidgetClassName = useSplitter ? QLatin1String("QSplitter") : QLatin1String("QLayoutWidget");
+ m_layoutBase = widgetFactory->createWidget(baseWidgetClassName, widgetFactory->containerOfWidget(m_parentWidget));
+ if (useSplitter) {
+ m_layoutBase->setObjectName(QLatin1String("splitter"));
+ m_formWindow->ensureUniqueObjectName(m_layoutBase);
+ }
+ } else {
+ LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
+ }
+
+ metaDataBase->add(m_layoutBase);
+
+ Q_ASSERT(m_layoutBase->layout() == 0 || metaDataBase->item(m_layoutBase->layout()) == 0);
+
+ return true;
+}
+
+static bool isMainContainer(QDesignerFormWindowInterface *fw, const QWidget *w)
+{
+ return w && (w == fw || w == fw->mainContainer());
+}
+
+static bool isPageOfContainerWidget(QDesignerFormWindowInterface *fw, QWidget *widget)
+{
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(
+ fw->core()->extensionManager(), widget->parentWidget());
+
+ if (c != 0) {
+ for (int i = 0; i<c->count(); ++i) {
+ if (widget == c->widget(i))
+ return true;
+ }
+ }
+
+ return false;
+}
+void Layout::finishLayout(bool needMove, QLayout *layout)
+{
+ if (m_parentWidget == m_layoutBase) {
+ QWidget *widget = m_layoutBase;
+ m_oldGeometry = widget->geometry();
+
+ bool done = false;
+ while (!isMainContainer(m_formWindow, widget) && !done) {
+ if (!m_formWindow->isManaged(widget)) {
+ widget = widget->parentWidget();
+ continue;
+ } else if (LayoutInfo::isWidgetLaidout(m_formWindow->core(), widget)) {
+ widget = widget->parentWidget();
+ continue;
+ } else if (isPageOfContainerWidget(m_formWindow, widget)) {
+ widget = widget->parentWidget();
+ continue;
+ } else if (widget->parentWidget()) {
+ QScrollArea *area = qobject_cast<QScrollArea*>(widget->parentWidget()->parentWidget());
+ if (area && area->widget() == widget) {
+ widget = area;
+ continue;
+ }
+ }
+
+ done = true;
+ }
+ updateWizardLayout(m_layoutBase);
+ QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ // We don't want to resize the form window
+ if (!Utils::isCentralWidget(m_formWindow, widget))
+ widget->adjustSize();
+
+ return;
+ }
+
+ if (needMove)
+ m_layoutBase->move(m_startPoint);
+
+ const QRect g(m_layoutBase->pos(), m_layoutBase->size());
+
+ if (LayoutInfo::layoutType(m_formWindow->core(), m_layoutBase->parentWidget()) == LayoutInfo::NoLayout && !m_isBreak)
+ m_layoutBase->adjustSize();
+ else if (m_isBreak)
+ m_layoutBase->setGeometry(m_oldGeometry);
+
+ m_oldGeometry = g;
+ if (layout)
+ layout->invalidate();
+ m_layoutBase->show();
+
+ if (qobject_cast<QLayoutWidget*>(m_layoutBase) || qobject_cast<QSplitter*>(m_layoutBase)) {
+ m_formWindow->clearSelection(false);
+ m_formWindow->manageWidget(m_layoutBase);
+ m_formWindow->selectWidget(m_layoutBase);
+ }
+}
+
+void Layout::undoLayout()
+{
+ if (!m_widgets.count())
+ return;
+
+ m_formWindow->selectWidget(m_layoutBase, false);
+
+ QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory();
+ QHashIterator<QWidget *, QRect> it(m_geometries);
+ while (it.hasNext()) {
+ it.next();
+
+ if (!it.key())
+ continue;
+
+ QWidget* w = it.key();
+ const QRect rc = it.value();
+
+ const bool showIt = w->isVisibleTo(m_formWindow);
+ QWidget *container = widgetFactory->containerOfWidget(m_parentWidget);
+
+ // ### remove widget here
+ QWidget *parentWidget = w->parentWidget();
+ QDesignerFormEditorInterface *core = m_formWindow->core();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
+
+ if (deco)
+ deco->removeWidget(w);
+
+ w->setParent(container);
+ w->setGeometry(rc);
+
+ if (showIt)
+ w->show();
+ }
+
+ LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
+
+ if (m_parentWidget != m_layoutBase && !qobject_cast<QMainWindow*>(m_layoutBase)) {
+ m_formWindow->unmanageWidget(m_layoutBase);
+ m_layoutBase->hide();
+ } else {
+ QMainWindow *mw = qobject_cast<QMainWindow*>(m_formWindow->mainContainer());
+ if (m_layoutBase != m_formWindow->mainContainer() &&
+ (!mw || mw->centralWidget() != m_layoutBase))
+ m_layoutBase->setGeometry(m_oldGeometry);
+ }
+}
+
+void Layout::breakLayout()
+{
+ typedef QMap<QWidget *, QRect> WidgetRectMap;
+ WidgetRectMap rects;
+ /* Store the geometry of the widgets. The idea is to give the user space
+ * to rearrange them, so, we do a adjustSize() on them, unless they want
+ * to grow (expanding widgets like QTextEdit), in which the geometry is
+ * preserved. Note that historically, geometries were re-applied
+ * only after breaking splitters. */
+ foreach (QWidget *w, m_widgets) {
+ const QRect geom = w->geometry();
+ const QSize sizeHint = w->sizeHint();
+ const bool restoreGeometry = sizeHint.isEmpty() || sizeHint.width() > geom.width() || sizeHint.height() > geom.height();
+ rects.insert(w, restoreGeometry ? w->geometry() : QRect(geom.topLeft(), QSize()));
+ }
+ const QPoint m_layoutBasePos = m_layoutBase->pos();
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase();
+
+ LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
+
+ const bool needReparent = (m_reparentLayoutWidget && qobject_cast<QLayoutWidget*>(m_layoutBase)) ||
+ qobject_cast<QSplitter*>(m_layoutBase) ||
+ (!widgetDataBase->isContainer(m_layoutBase, false) &&
+ m_layoutBase != m_formWindow->mainContainer());
+ const bool add = m_geometries.isEmpty();
+
+ QMapIterator<QWidget*, QRect> it(rects);
+ while (it.hasNext()) {
+ it.next();
+
+ QWidget *w = it.key();
+ if (needReparent) {
+ w->setParent(m_layoutBase->parentWidget(), 0);
+ w->move(m_layoutBasePos + it.value().topLeft());
+ w->show();
+ }
+
+ const QRect oldGeometry = it.value();
+ if (oldGeometry.isEmpty()) {
+ w->adjustSize();
+ } else {
+ w->resize(oldGeometry.size());
+ }
+
+ if (add)
+ m_geometries.insert(w, QRect(w->pos(), w->size()));
+ }
+
+ if (needReparent) {
+ m_layoutBase->hide();
+ m_parentWidget = m_layoutBase->parentWidget();
+ m_formWindow->unmanageWidget(m_layoutBase);
+ } else {
+ m_parentWidget = m_layoutBase;
+ }
+ updateWizardLayout(m_layoutBase);
+
+ if (!m_widgets.isEmpty() && m_widgets.first() && m_widgets.first()->isVisibleTo(m_formWindow))
+ m_formWindow->selectWidget(m_widgets.first());
+ else
+ m_formWindow->selectWidget(m_formWindow);
+}
+
+static QString suggestLayoutName(const char *className)
+{
+ // Legacy
+ if (!qstrcmp(className, "QHBoxLayout"))
+ return QLatin1String("horizontalLayout");
+ if (!qstrcmp(className, "QVBoxLayout"))
+ return QLatin1String("verticalLayout");
+ if (!qstrcmp(className, "QGridLayout"))
+ return QLatin1String("gridLayout");
+
+ return qtify(QString::fromUtf8(className));
+}
+QLayout *Layout::createLayout(int type)
+{
+ Q_ASSERT(m_layoutType != LayoutInfo::HSplitter && m_layoutType != LayoutInfo::VSplitter);
+ QLayout *layout = m_formWindow->core()->widgetFactory()->createLayout(m_layoutBase, 0, type);
+ // set a name
+ layout->setObjectName(suggestLayoutName(layout->metaObject()->className()));
+ m_formWindow->ensureUniqueObjectName(layout);
+ // QLayoutWidget
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), layout);
+ if (sheet && qobject_cast<QLayoutWidget*>(m_layoutBase)) {
+ sheet->setProperty(sheet->indexOf(QLatin1String("leftMargin")), 0);
+ sheet->setProperty(sheet->indexOf(QLatin1String("topMargin")), 0);
+ sheet->setProperty(sheet->indexOf(QLatin1String("rightMargin")), 0);
+ sheet->setProperty(sheet->indexOf(QLatin1String("bottomMargin")), 0);
+ }
+ return layout;
+}
+
+void Layout::reparentToLayoutBase(QWidget *w)
+{
+ if (w->parent() != m_layoutBase) {
+ w->setParent(m_layoutBase, 0);
+ w->move(QPoint(0,0));
+ }
+}
+
+namespace { // within qdesigner_internal
+
+// ----- PositionSortPredicate: Predicate to be usable as LessThan function to sort widgets by position
+class PositionSortPredicate {
+public:
+ PositionSortPredicate(Qt::Orientation orientation) : m_orientation(orientation) {}
+ bool operator()(const QWidget* w1, const QWidget* w2) {
+ return m_orientation == Qt::Horizontal ? w1->x() < w2->x() : w1->y() < w2->y();
+ }
+ private:
+ const Qt::Orientation m_orientation;
+};
+
+// -------- BoxLayout
+class BoxLayout : public Layout
+{
+public:
+ BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
+ Qt::Orientation orientation);
+
+ virtual void doLayout();
+ virtual void sort();
+
+private:
+ const Qt::Orientation m_orientation;
+};
+
+BoxLayout::BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
+ Qt::Orientation orientation) :
+ Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox),
+ m_orientation(orientation)
+{
+}
+
+void BoxLayout::sort()
+{
+ QWidgetList wl = widgets();
+ qStableSort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation));
+ setWidgets(wl);
+}
+
+void BoxLayout::doLayout()
+{
+ bool needMove, needReparent;
+ if (!prepareLayout(needMove, needReparent))
+ return;
+
+ QBoxLayout *layout = static_cast<QBoxLayout *>(createLayout(m_orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox));
+
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+
+ const QWidgetList::const_iterator cend = widgets().constEnd();
+ for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) {
+ QWidget *w = *it;
+ if (needReparent)
+ reparentToLayoutBase(w);
+
+ if (const Spacer *spacer = qobject_cast<const Spacer*>(w))
+ layout->addWidget(w, 0, spacer->alignment());
+ else
+ layout->addWidget(w);
+ w->show();
+ }
+ finishLayout(needMove, layout);
+}
+
+// -------- SplitterLayout
+class SplitterLayout : public Layout
+{
+public:
+ SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
+ Qt::Orientation orientation);
+
+ virtual void doLayout();
+ virtual void sort();
+
+private:
+ const Qt::Orientation m_orientation;
+};
+
+SplitterLayout::SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
+ Qt::Orientation orientation) :
+ Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HSplitter : LayoutInfo::VSplitter),
+ m_orientation(orientation)
+{
+}
+
+void SplitterLayout::sort()
+{
+ QWidgetList wl = widgets();
+ qStableSort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation));
+ setWidgets(wl);
+}
+
+void SplitterLayout::doLayout()
+{
+ bool needMove, needReparent;
+ if (!prepareLayout(needMove, needReparent))
+ return;
+
+ QSplitter *splitter = qobject_cast<QSplitter*>(layoutBaseWidget());
+ Q_ASSERT(splitter != 0);
+
+
+ const QWidgetList::const_iterator cend = widgets().constEnd();
+ for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) {
+ QWidget *w = *it;
+ if (needReparent)
+ reparentToLayoutBase(w);
+ splitter->addWidget(w);
+ w->show();
+ }
+
+ splitter->setOrientation(m_orientation);
+ finishLayout(needMove);
+}
+
+// ---------- Grid: Helper for laying out grids
+
+class Grid
+{
+public:
+ enum Mode {
+ GridLayout, // Arbitrary size/supports span
+ FormLayout // 2-column/no span
+ };
+
+ Grid(Mode mode);
+ void resize(int nrows, int ncols);
+
+ ~Grid();
+
+ QWidget* cell(int row, int col) const { return m_cells[ row * m_ncols + col]; }
+
+ void setCells(const QRect &c, QWidget* w);
+
+ bool empty() const { return m_nrows * m_ncols; }
+ int numRows() const { return m_nrows; }
+ int numCols() const { return m_ncols; }
+
+ void simplify();
+ bool locateWidget(QWidget* w, int& row, int& col, int& rowspan, int& colspan) const;
+
+ QDebug debug(QDebug str) const;
+
+private:
+ void setCell(int row, int col, QWidget* w) { m_cells[ row * m_ncols + col] = w; }
+ void swapCells(int r1, int c1, int r2, int c2);
+ void shrink();
+ void reallocFormLayout();
+ int countRow(int r, int c) const;
+ int countCol(int r, int c) const;
+ void setRow(int r, int c, QWidget* w, int count);
+ void setCol(int r, int c, QWidget* w, int count);
+ bool isWidgetStartCol(int c) const;
+ bool isWidgetEndCol(int c) const;
+ bool isWidgetStartRow(int r) const;
+ bool isWidgetEndRow(int r) const;
+ bool isWidgetTopLeft(int r, int c) const;
+ void extendLeft();
+ void extendRight();
+ void extendUp();
+ void extendDown();
+ bool shrinkFormLayoutSpans();
+
+ const Mode m_mode;
+ int m_nrows;
+ int m_ncols;
+
+ QWidget** m_cells; // widget matrix w11, w12, w21...
+};
+
+Grid::Grid(Mode mode) :
+ m_mode(mode),
+ m_nrows(0),
+ m_ncols(0),
+ m_cells(0)
+{
+}
+
+Grid::~Grid()
+{
+ delete [] m_cells;
+}
+
+void Grid::resize(int nrows, int ncols)
+{
+ delete [] m_cells;
+ m_cells = 0;
+ m_nrows = nrows;
+ m_ncols = ncols;
+ if (const int allocSize = m_nrows * m_ncols) {
+ m_cells = new QWidget*[allocSize];
+ qFill(m_cells, m_cells + allocSize, static_cast<QWidget *>(0));
+ }
+}
+
+QDebug Grid::debug(QDebug str) const
+{
+ str << m_nrows << 'x' << m_ncols << '\n';
+ QSet<QWidget *> widgets;
+ const int cellCount = m_nrows * m_ncols;
+ int row, col, rowspan, colspan;
+ for (int c = 0; c < cellCount; c++)
+ if (QWidget *w = m_cells[c])
+ if (!widgets.contains(w)) {
+ widgets.insert(w);
+ locateWidget(w, row, col, rowspan, colspan);
+ str << w << " at " << row << col << rowspan << 'x' << colspan << '\n';
+ }
+ for (int r = 0; r < m_nrows; r++)
+ for (int c = 0; c < m_ncols; c++)
+ str << "At " << r << c << cell(r, c) << '\n';
+
+ return str;
+}
+
+static inline QDebug operator<<(QDebug str, const Grid &g) { return g.debug(str); }
+
+void Grid::setCells(const QRect &c, QWidget* w)
+{
+ const int bottom = c.top() + c.height();
+ const int width = c.width();
+
+ for (int r = c.top(); r < bottom; r++) {
+ QWidget **pos = m_cells + r * m_ncols + c.left();
+ qFill(pos, pos + width, w);
+ }
+}
+
+
+void Grid::swapCells(int r1, int c1, int r2, int c2)
+{
+ QWidget *w1 = cell(r1, c1);
+ setCell(r1, c1, cell(r2, c2));
+ setCell(r2, c2, w1);
+}
+
+int Grid::countRow(int r, int c) const
+{
+ QWidget* w = cell(r, c);
+ int i = c + 1;
+ while (i < m_ncols && cell(r, i) == w)
+ i++;
+ return i - c;
+}
+
+int Grid::countCol(int r, int c) const
+{
+ QWidget* w = cell(r, c);
+ int i = r + 1;
+ while (i < m_nrows && cell(i, c) == w)
+ i++;
+ return i - r;
+}
+
+void Grid::setCol(int r, int c, QWidget* w, int count)
+{
+ for (int i = 0; i < count; i++)
+ setCell(r + i, c, w);
+}
+
+void Grid::setRow(int r, int c, QWidget* w, int count)
+{
+ for (int i = 0; i < count; i++)
+ setCell(r, c + i, w);
+}
+
+bool Grid::isWidgetStartCol(int c) const
+{
+ for (int r = 0; r < m_nrows; r++) {
+ if (cell(r, c) && ((c==0) || (cell(r, c) != cell(r, c-1)))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Grid::isWidgetEndCol(int c) const
+{
+ for (int r = 0; r < m_nrows; r++) {
+ if (cell(r, c) && ((c == m_ncols-1) || (cell(r, c) != cell(r, c+1))))
+ return true;
+ }
+ return false;
+}
+
+bool Grid::isWidgetStartRow(int r) const
+{
+ for ( int c = 0; c < m_ncols; c++) {
+ if (cell(r, c) && ((r==0) || (cell(r, c) != cell(r-1, c))))
+ return true;
+ }
+ return false;
+}
+
+bool Grid::isWidgetEndRow(int r) const
+{
+ for (int c = 0; c < m_ncols; c++) {
+ if (cell(r, c) && ((r == m_nrows-1) || (cell(r, c) != cell(r+1, c))))
+ return true;
+ }
+ return false;
+}
+
+
+bool Grid::isWidgetTopLeft(int r, int c) const
+{
+ QWidget* w = cell(r, c);
+ if (!w)
+ return false;
+ return (!r || cell(r-1, c) != w) && (!c || cell(r, c-1) != w);
+}
+
+void Grid::extendLeft()
+{
+ for (int c = 1; c < m_ncols; c++) {
+ for (int r = 0; r < m_nrows; r++) {
+ QWidget* w = cell(r, c);
+ if (!w)
+ continue;
+
+ const int cc = countCol(r, c);
+ int stretch = 0;
+ for (int i = c-1; i >= 0; i--) {
+ if (cell(r, i))
+ break;
+ if (countCol(r, i) < cc)
+ break;
+ if (isWidgetEndCol(i))
+ break;
+ if (isWidgetStartCol(i)) {
+ stretch = c - i;
+ break;
+ }
+ }
+ if (stretch) {
+ for (int i = 0; i < stretch; i++)
+ setCol(r, c-i-1, w, cc);
+ }
+ }
+ }
+}
+
+
+void Grid::extendRight()
+{
+ for (int c = m_ncols - 2; c >= 0; c--) {
+ for (int r = 0; r < m_nrows; r++) {
+ QWidget* w = cell(r, c);
+ if (!w)
+ continue;
+ const int cc = countCol(r, c);
+ int stretch = 0;
+ for (int i = c+1; i < m_ncols; i++) {
+ if (cell(r, i))
+ break;
+ if (countCol(r, i) < cc)
+ break;
+ if (isWidgetStartCol(i))
+ break;
+ if (isWidgetEndCol(i)) {
+ stretch = i - c;
+ break;
+ }
+ }
+ if (stretch) {
+ for (int i = 0; i < stretch; i++)
+ setCol(r, c+i+1, w, cc);
+ }
+ }
+ }
+
+}
+
+void Grid::extendUp()
+{
+ for (int r = 1; r < m_nrows; r++) {
+ for (int c = 0; c < m_ncols; c++) {
+ QWidget* w = cell(r, c);
+ if (!w)
+ continue;
+ const int cr = countRow(r, c);
+ int stretch = 0;
+ for (int i = r-1; i >= 0; i--) {
+ if (cell(i, c))
+ break;
+ if (countRow(i, c) < cr)
+ break;
+ if (isWidgetEndRow(i))
+ break;
+ if (isWidgetStartRow(i)) {
+ stretch = r - i;
+ break;
+ }
+ }
+ if (stretch) {
+ for (int i = 0; i < stretch; i++)
+ setRow(r-i-1, c, w, cr);
+ }
+ }
+ }
+}
+
+void Grid::extendDown()
+{
+ for (int r = m_nrows - 2; r >= 0; r--) {
+ for (int c = 0; c < m_ncols; c++) {
+ QWidget* w = cell(r, c);
+ if (!w)
+ continue;
+ const int cr = countRow(r, c);
+ int stretch = 0;
+ for (int i = r+1; i < m_nrows; i++) {
+ if (cell(i, c))
+ break;
+ if (countRow(i, c) < cr)
+ break;
+ if (isWidgetStartRow(i))
+ break;
+ if (isWidgetEndRow(i)) {
+ stretch = i - r;
+ break;
+ }
+ }
+ if (stretch) {
+ for (int i = 0; i < stretch; i++)
+ setRow(r+i+1, c, w, cr);
+ }
+ }
+ }
+}
+
+void Grid::simplify()
+{
+ switch (m_mode) {
+ case GridLayout:
+ // Grid: Extend all widgets to occupy most space and delete
+ // rows/columns that are not bordering on a widget
+ extendLeft();
+ extendRight();
+ extendUp();
+ extendDown();
+ shrink();
+ break;
+ case FormLayout:
+ // Form: First treat it as a grid to get the same behaviour
+ // regarding spanning and shrinking. Then restrict the span to
+ // the horizontal span possible in the form, simplify again
+ // and spread the widgets over a 2-column layout
+ extendLeft();
+ extendRight();
+ extendUp();
+ extendDown();
+ shrink();
+ if (shrinkFormLayoutSpans())
+ shrink();
+ reallocFormLayout();
+ break;
+ }
+
+}
+
+void Grid::shrink()
+{
+ // tick off the occupied cols/rows (bordering on widget edges)
+ QVector<bool> columns(m_ncols, false);
+ QVector<bool> rows(m_nrows, false);
+
+ for (int c = 0; c < m_ncols; c++)
+ for (int r = 0; r < m_nrows; r++)
+ if (isWidgetTopLeft(r, c))
+ rows[r] = columns[c] = true;
+
+ // remove empty cols/rows
+ const int simplifiedNCols = columns.count(true);
+ const int simplifiedNRows = rows.count(true);
+ if (simplifiedNCols == m_ncols && simplifiedNRows == m_nrows)
+ return;
+ // reallocate and copy omitting the empty cells
+ QWidget **simplifiedCells = new QWidget*[simplifiedNCols * simplifiedNRows];
+ qFill(simplifiedCells, simplifiedCells + simplifiedNCols * simplifiedNRows, static_cast<QWidget *>(0));
+ QWidget **simplifiedPtr = simplifiedCells;
+
+ for (int r = 0; r < m_nrows; r++)
+ if (rows[r])
+ for (int c = 0; c < m_ncols; c++)
+ if (columns[c]) {
+ if (QWidget *w = cell(r, c))
+ *simplifiedPtr = w;
+ simplifiedPtr++;
+ }
+ Q_ASSERT(simplifiedPtr == simplifiedCells + simplifiedNCols * simplifiedNRows);
+ delete [] m_cells;
+ m_cells = simplifiedCells;
+ m_nrows = simplifiedNRows;
+ m_ncols = simplifiedNCols;
+}
+
+bool Grid::shrinkFormLayoutSpans()
+{
+ bool shrunk = false;
+ typedef QSet<QWidget*> WidgetSet;
+ // Determine unique set of widgets
+ WidgetSet widgets;
+ QWidget **end = m_cells + m_ncols * m_nrows;
+ for (QWidget **wptr = m_cells; wptr < end; wptr++)
+ if (QWidget *w = *wptr)
+ widgets.insert(w);
+ // Restrict the widget span: max horizontal span at column 0: 2, anything else: 1
+ const int maxRowSpan = 1;
+ const WidgetSet::const_iterator cend = widgets.constEnd();
+ for (WidgetSet::const_iterator it = widgets.constBegin(); it != cend ; ++it) {
+ QWidget *w = *it;
+ int row, col, rowspan, colspan;
+ locateWidget(w, row, col, rowspan, colspan);
+ const int maxColSpan = col == 0 ? 2 : 1;
+ const int newColSpan = qMin(colspan, maxColSpan);
+ const int newRowSpan = qMin(rowspan, maxRowSpan);
+ if (newColSpan != colspan || newRowSpan != rowspan) {
+ setCells(QRect(col, row, colspan, rowspan), 0);
+ setCells(QRect(col, row, newColSpan, newRowSpan), w);
+ shrunk = true;
+ }
+ }
+ return shrunk;
+}
+
+void Grid::reallocFormLayout()
+{
+ // Columns matching? -> happy!
+ if (m_ncols == FormLayoutColumns)
+ return;
+
+ // If there are offset columns (starting past the field column),
+ // move them to the left and squeeze them. This also prevents the
+ // following reallocation from creating empty form rows.
+ int pastRightWidgetCount = 0;
+ if (m_ncols > FormLayoutColumns) {
+ for (int r = 0; r < m_nrows; r++) {
+ // Try to find a column where the form columns are empty and
+ // there are widgets further to the right.
+ if (cell(r, 0) == 0 && cell(r, 1) == 0) {
+ int sourceCol = FormLayoutColumns;
+ QWidget *firstWidget = 0;
+ for ( ; sourceCol < m_ncols; sourceCol++)
+ if (QWidget *w = cell(r, sourceCol)) {
+ firstWidget = w;
+ break;
+ }
+ if (firstWidget) {
+ // Move/squeeze. Copy to beginning of column if it is a label, else field
+ int targetCol = qobject_cast<QLabel*>(firstWidget) ? 0 : 1;
+ for ( ; sourceCol < m_ncols; sourceCol++)
+ if (QWidget *w = cell(r, sourceCol))
+ setCell(r, targetCol++, w);
+ // Pad with zero
+ for ( ; targetCol < m_ncols; targetCol++)
+ setCell(r, targetCol, 0);
+ }
+ }
+ // Any protruding widgets left on that row?
+ for (int c = FormLayoutColumns; c < m_ncols; c++)
+ if (cell(r, c))
+ pastRightWidgetCount++;
+ }
+ }
+ // Reallocate with 2 columns. Just insert the protruding ones as fields.
+ const int formNRows = m_nrows + pastRightWidgetCount;
+ QWidget **formCells = new QWidget*[FormLayoutColumns * formNRows];
+ qFill(formCells, formCells + FormLayoutColumns * formNRows, static_cast<QWidget *>(0));
+ QWidget **formPtr = formCells;
+ const int matchingColumns = qMin(m_ncols, static_cast<int>(FormLayoutColumns));
+ for (int r = 0; r < m_nrows; r++) {
+ int c = 0;
+ for ( ; c < matchingColumns; c++) // Just copy over matching columns
+ *formPtr++ = cell(r, c);
+ formPtr += FormLayoutColumns - matchingColumns; // In case old format was 1 column
+ // protruding widgets: Insert as single-field rows
+ for ( ; c < m_ncols; c++)
+ if (QWidget *w = cell(r, c)) {
+ formPtr++;
+ *formPtr++ = w;
+ }
+ }
+ Q_ASSERT(formPtr == formCells + FormLayoutColumns * formNRows);
+ delete [] m_cells;
+ m_cells = formCells;
+ m_nrows = formNRows;
+ m_ncols = FormLayoutColumns;
+}
+
+bool Grid::locateWidget(QWidget *w, int &row, int &col, int &rowspan, int &colspan) const
+{
+ const int end = m_nrows * m_ncols;
+ const int startIndex = qFind(m_cells, m_cells + end, w) - m_cells;
+ if (startIndex == end)
+ return false;
+
+ row = startIndex / m_ncols;
+ col = startIndex % m_ncols;
+ for (rowspan = 1; row + rowspan < m_nrows && cell(row + rowspan, col) == w; rowspan++) {}
+ for (colspan = 1; col + colspan < m_ncols && cell(row, col + colspan) == w; colspan++) {}
+ return true;
+}
+
+// QGridLayout/QFormLayout Helpers: get item position/add item (overloads to make templates work)
+
+void getGridItemPosition(QGridLayout *gridLayout, int index, int *row, int *column, int *rowspan, int *colspan)
+{
+ gridLayout->getItemPosition(index, row, column, rowspan, colspan);
+}
+
+void addWidgetToGrid(QGridLayout *lt, QWidget * widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
+{
+ lt->addWidget(widget, row, column, rowSpan, columnSpan, alignment);
+}
+
+inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan)
+{
+ getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan);
+}
+
+inline void addWidgetToGrid(QFormLayout *lt, QWidget * widget, int row, int column, int, int columnSpan, Qt::Alignment)
+{
+ formLayoutAddWidget(lt, widget, QRect(column, row, columnSpan, 1), false);
+}
+
+// ----------- Base template for grid like layouts
+template <class GridLikeLayout, int LayoutType, int GridMode>
+class GridLayout : public Layout
+{
+public:
+ GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb);
+
+ virtual void doLayout();
+ virtual void sort() { setWidgets(buildGrid(widgets())); }
+
+protected:
+ QWidget *widgetAt(GridLikeLayout *layout, int row, int column) const;
+
+protected:
+ QWidgetList buildGrid(const QWidgetList &);
+ Grid m_grid;
+};
+
+template <class GridLikeLayout, int LayoutType, int GridMode>
+GridLayout<GridLikeLayout, LayoutType, GridMode>::GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb) :
+ Layout(wl, p, fw, lb, LayoutInfo::Grid),
+ m_grid(static_cast<Grid::Mode>(GridMode))
+{
+}
+
+template <class GridLikeLayout, int LayoutType, int GridMode>
+QWidget *GridLayout<GridLikeLayout, LayoutType, GridMode>::widgetAt(GridLikeLayout *layout, int row, int column) const
+{
+ int index = 0;
+ while (QLayoutItem *item = layout->itemAt(index)) {
+ if (item->widget()) {
+ int r, c, rowspan, colspan;
+ getGridItemPosition(layout, index, &r, &c, &rowspan, &colspan);
+ if (row == r && column == c)
+ return item->widget();
+ }
+ ++index;
+ }
+ return 0;
+}
+
+template <class GridLikeLayout, int LayoutType, int GridMode>
+void GridLayout<GridLikeLayout, LayoutType, GridMode>::doLayout()
+{
+ bool needMove, needReparent;
+ if (!prepareLayout(needMove, needReparent))
+ return;
+
+ GridLikeLayout *layout = static_cast<GridLikeLayout *>(createLayout(LayoutType));
+
+ if (m_grid.empty())
+ sort();
+
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+
+ const QWidgetList::const_iterator cend = widgets().constEnd();
+ for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) {
+ QWidget *w = *it;
+ int r = 0, c = 0, rs = 0, cs = 0;
+
+ if (m_grid.locateWidget(w, r, c, rs, cs)) {
+ if (needReparent)
+ reparentToLayoutBase(w);
+
+ Qt::Alignment alignment = Qt::Alignment(0);
+ if (const Spacer *spacer = qobject_cast<const Spacer*>(w))
+ alignment = spacer->alignment();
+
+ if (rs * cs == 1) {
+ addWidgetToGrid(layout, w, r, c, 1, 1, alignment);
+ } else {
+ addWidgetToGrid(layout, w, r, c, rs, cs, alignment);
+ }
+
+ w->show();
+ } else {
+ qDebug("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData());
+ }
+ }
+
+ QLayoutSupport::createEmptyCells(layout);
+
+ finishLayout(needMove, layout);
+}
+
+// Remove duplicate entries (Remove next, if equal to current)
+void removeIntVecDuplicates(QVector<int> &v)
+{
+ if (v.size() < 2)
+ return;
+
+ for (QVector<int>::iterator current = v.begin() ; (current != v.end()) && ((current+1) != v.end()) ; )
+ if ( (*current == *(current+1)) )
+ v.erase(current+1);
+ else
+ ++current;
+}
+
+// Ensure a non-zero size for a widget geometry (squeezed spacers)
+inline QRect expandGeometry(const QRect &rect)
+{
+ return rect.isEmpty() ? QRect(rect.topLeft(), rect.size().expandedTo(QSize(1, 1))) : rect;
+}
+
+template <class GridLikeLayout, int LayoutType, int GridMode>
+QWidgetList GridLayout<GridLikeLayout, LayoutType, GridMode>::buildGrid(const QWidgetList &widgetList)
+{
+ if (widgetList.empty())
+ return QWidgetList();
+
+ // Pixel to cell conversion:
+ // By keeping a list of start'n'stop values (x & y) for each widget,
+ // it is possible to create a very small grid of cells to represent
+ // the widget layout.
+ // -----------------------------------------------------------------
+
+ // We need a list of both start and stop values for x- & y-axis
+ const int widgetCount = widgetList.size();
+ QVector<int> x( widgetCount * 2 );
+ QVector<int> y( widgetCount * 2 );
+
+ // Using push_back would look nicer, but operator[] is much faster
+ int index = 0;
+ for (int i = 0; i < widgetCount; ++i) {
+ const QRect widgetPos = expandGeometry(widgetList.at(i)->geometry());
+ x[index] = widgetPos.left();
+ x[index+1] = widgetPos.right();
+ y[index] = widgetPos.top();
+ y[index+1] = widgetPos.bottom();
+ index += 2;
+ }
+
+ qSort(x);
+ qSort(y);
+
+ // Remove duplicate x entries (Remove next, if equal to current)
+ removeIntVecDuplicates(x);
+ removeIntVecDuplicates(y);
+
+ // Note that left == right and top == bottom for size 1 items; reserve
+ // enough space
+ m_grid.resize(y.size(), x.size());
+
+ const QWidgetList::const_iterator cend = widgetList.constEnd();
+ for (QWidgetList::const_iterator it = widgetList.constBegin(); it != cend; ++it) {
+ QWidget *w = *it;
+ // Mark the cells in the grid that contains a widget
+ const QRect widgetPos = expandGeometry(w->geometry());
+ QRect c(0, 0, 0, 0); // rect of columns/rows
+
+ // From left til right (not including)
+ const int leftIdx = x.indexOf(widgetPos.left());
+ Q_ASSERT(leftIdx != -1);
+ c.setLeft(leftIdx);
+ c.setRight(leftIdx);
+ for (int cw=leftIdx; cw<x.size(); cw++)
+ if (x[cw] < widgetPos.right())
+ c.setRight(cw);
+ else
+ break;
+ // From top til bottom (not including)
+ const int topIdx = y.indexOf(widgetPos.top());
+ Q_ASSERT(topIdx != -1);
+ c.setTop(topIdx);
+ c.setBottom(topIdx);
+ for (int ch=topIdx; ch<y.size(); ch++)
+ if (y[ch] < widgetPos.bottom())
+ c.setBottom(ch);
+ else
+ break;
+ m_grid.setCells(c, w); // Mark cellblock
+ }
+
+ m_grid.simplify();
+
+ QWidgetList ordered;
+ for (int i = 0; i < m_grid.numRows(); i++)
+ for (int j = 0; j < m_grid.numCols(); j++) {
+ QWidget *w = m_grid.cell(i, j);
+ if (w && !ordered.contains(w))
+ ordered.append(w);
+ }
+ return ordered;
+}
+} // anonymous
+
+Layout* Layout::createLayout(const QWidgetList &widgets, QWidget *parentWidget,
+ QDesignerFormWindowInterface *fw,
+ QWidget *layoutBase, LayoutInfo::Type layoutType)
+{
+ switch (layoutType) {
+ case LayoutInfo::Grid:
+ return new GridLayout<QGridLayout, LayoutInfo::Grid, Grid::GridLayout>(widgets, parentWidget, fw, layoutBase);
+ case LayoutInfo::HBox:
+ case LayoutInfo::VBox: {
+ const Qt::Orientation orientation = layoutType == LayoutInfo::HBox ? Qt::Horizontal : Qt::Vertical;
+ return new BoxLayout(widgets, parentWidget, fw, layoutBase, orientation);
+ }
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter: {
+ const Qt::Orientation orientation = layoutType == LayoutInfo::HSplitter ? Qt::Horizontal : Qt::Vertical;
+ return new SplitterLayout(widgets, parentWidget, fw, layoutBase, orientation);
+ }
+ case LayoutInfo::Form:
+ return new GridLayout<QFormLayout, LayoutInfo::Form, Grid::FormLayout>(widgets, parentWidget, fw, layoutBase);
+ default:
+ break;
+ }
+ Q_ASSERT(0);
+ return 0;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/layout_p.h b/tools/designer/src/lib/shared/layout_p.h
new file mode 100644
index 0000000..8396876
--- /dev/null
+++ b/tools/designer/src/lib/shared/layout_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 LAYOUT_H
+#define LAYOUT_H
+
+#include "shared_global_p.h"
+#include "layoutinfo_p.h"
+
+#include <QtCore/QPointer>
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QHash>
+
+#include <QtGui/QLayout>
+#include <QtGui/QGridLayout>
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+namespace qdesigner_internal {
+class QDESIGNER_SHARED_EXPORT Layout : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Layout)
+protected:
+ Layout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, LayoutInfo::Type layoutType);
+
+public:
+ static Layout* createLayout(const QWidgetList &widgets, QWidget *parentWidget,
+ QDesignerFormWindowInterface *fw,
+ QWidget *layoutBase, LayoutInfo::Type layoutType);
+
+ virtual ~Layout();
+
+ virtual void sort() = 0;
+ virtual void doLayout() = 0;
+
+ virtual void setup();
+ virtual void undoLayout();
+ virtual void breakLayout();
+
+ const QWidgetList &widgets() const { return m_widgets; }
+ QWidget *parentWidget() const { return m_parentWidget; }
+ QWidget *layoutBaseWidget() const { return m_layoutBase; }
+
+ /* Determines whether instances of QLayoutWidget are unmanaged/hidden
+ * after breaking a layout. Default is true. Can be turned off when
+ * morphing */
+ bool reparentLayoutWidget() const { return m_reparentLayoutWidget; }
+ void setReparentLayoutWidget(bool v) { m_reparentLayoutWidget = v; }
+
+protected:
+ virtual void finishLayout(bool needMove, QLayout *layout = 0);
+ virtual bool prepareLayout(bool &needMove, bool &needReparent);
+
+ void setWidgets(const QWidgetList &widgets) { m_widgets = widgets; }
+ QLayout *createLayout(int type);
+ void reparentToLayoutBase(QWidget *w);
+
+private slots:
+ void widgetDestroyed();
+
+private:
+ QWidgetList m_widgets;
+ QWidget *m_parentWidget;
+ typedef QHash<QWidget *, QRect> WidgetGeometryHash;
+ WidgetGeometryHash m_geometries;
+ QWidget *m_layoutBase;
+ QDesignerFormWindowInterface *m_formWindow;
+ const LayoutInfo::Type m_layoutType;
+ QPoint m_startPoint;
+ QRect m_oldGeometry;
+
+ bool m_reparentLayoutWidget;
+ const bool m_isBreak;
+};
+
+namespace Utils
+{
+
+inline int indexOfWidget(QLayout *layout, QWidget *widget)
+{
+ int index = 0;
+ while (QLayoutItem *item = layout->itemAt(index)) {
+ if (item->widget() == widget)
+ return index;
+
+ ++index;
+ }
+
+ return -1;
+}
+
+} // namespace Utils
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // LAYOUT_H
diff --git a/tools/designer/src/lib/shared/layoutinfo.cpp b/tools/designer/src/lib/shared/layoutinfo.cpp
new file mode 100644
index 0000000..01eb43a
--- /dev/null
+++ b/tools/designer/src/lib/shared/layoutinfo.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "layoutinfo_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QSplitter>
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+#include <QtCore/QRect>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+/*!
+ \overload
+*/
+LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QLayout *layout)
+{
+ Q_UNUSED(core)
+ if (!layout)
+ return NoLayout;
+ else if (qobject_cast<const QHBoxLayout*>(layout))
+ return HBox;
+ else if (qobject_cast<const QVBoxLayout*>(layout))
+ return VBox;
+ else if (qobject_cast<const QGridLayout*>(layout))
+ return Grid;
+ else if (qobject_cast<const QFormLayout*>(layout))
+ return Form;
+ return UnknownLayout;
+}
+
+static const QHash<QString, LayoutInfo::Type> &layoutNameTypeMap()
+{
+ static QHash<QString, LayoutInfo::Type> nameTypeMap;
+ if (nameTypeMap.empty()) {
+ nameTypeMap.insert(QLatin1String("QVBoxLayout"), LayoutInfo::VBox);
+ nameTypeMap.insert(QLatin1String("QHBoxLayout"), LayoutInfo::HBox);
+ nameTypeMap.insert(QLatin1String("QGridLayout"), LayoutInfo::Grid);
+ nameTypeMap.insert(QLatin1String("QFormLayout"), LayoutInfo::Form);
+ }
+ return nameTypeMap;
+}
+
+LayoutInfo::Type LayoutInfo::layoutType(const QString &typeName)
+{
+ return layoutNameTypeMap().value(typeName, NoLayout);
+}
+
+QString LayoutInfo::layoutName(Type t)
+{
+ return layoutNameTypeMap().key(t);
+}
+
+/*!
+ \overload
+*/
+LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QWidget *w)
+{
+ if (const QSplitter *splitter = qobject_cast<const QSplitter *>(w))
+ return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
+ return layoutType(core, w->layout());
+}
+
+LayoutInfo::Type LayoutInfo::managedLayoutType(const QDesignerFormEditorInterface *core,
+ const QWidget *w,
+ QLayout **ptrToLayout)
+{
+ if (ptrToLayout)
+ *ptrToLayout = 0;
+ if (const QSplitter *splitter = qobject_cast<const QSplitter *>(w))
+ return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
+ QLayout *layout = managedLayout(core, w);
+ if (!layout)
+ return NoLayout;
+ if (ptrToLayout)
+ *ptrToLayout = layout;
+ return layoutType(core, layout);
+}
+
+QWidget *LayoutInfo::layoutParent(const QDesignerFormEditorInterface *core, QLayout *layout)
+{
+ Q_UNUSED(core)
+
+ QObject *o = layout;
+ while (o) {
+ if (QWidget *widget = qobject_cast<QWidget*>(o))
+ return widget;
+
+ o = o->parent();
+ }
+ return 0;
+}
+
+void LayoutInfo::deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget)
+{
+ if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), widget))
+ widget = container->widget(container->currentIndex());
+
+ Q_ASSERT(widget != 0);
+
+ QLayout *layout = managedLayout(core, widget);
+
+ if (layout == 0 || core->metaDataBase()->item(layout) != 0) {
+ delete layout;
+ widget->updateGeometry();
+ return;
+ }
+
+ qDebug() << "trying to delete an unmanaged layout:" << "widget:" << widget << "layout:" << layout;
+}
+
+LayoutInfo::Type LayoutInfo::laidoutWidgetType(const QDesignerFormEditorInterface *core,
+ QWidget *widget,
+ bool *isManaged,
+ QLayout **ptrToLayout)
+{
+ if (isManaged)
+ *isManaged = false;
+ if (ptrToLayout)
+ *ptrToLayout = 0;
+
+ QWidget *parent = widget->parentWidget();
+ if (!parent)
+ return NoLayout;
+
+ // 1) Splitter
+ if (QSplitter *splitter = qobject_cast<QSplitter*>(parent)) {
+ if (isManaged)
+ *isManaged = core->metaDataBase()->item(splitter);
+ return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
+ }
+
+ // 2) Layout of parent
+ QLayout *parentLayout = parent->layout();
+ if (!parentLayout)
+ return NoLayout;
+
+ if (parentLayout->indexOf(widget) != -1) {
+ if (isManaged)
+ *isManaged = core->metaDataBase()->item(parentLayout);
+ if (ptrToLayout)
+ *ptrToLayout = parentLayout;
+ return layoutType(core, parentLayout);
+ }
+
+ // 3) Some child layout (see below comment about Q3GroupBox)
+ const QList<QLayout*> childLayouts = qFindChildren<QLayout*>(parentLayout);
+ if (childLayouts.empty())
+ return NoLayout;
+ const QList<QLayout*>::const_iterator lcend = childLayouts.constEnd();
+ for (QList<QLayout*>::const_iterator it = childLayouts.constBegin(); it != lcend; ++it) {
+ QLayout *layout = *it;
+ if (layout->indexOf(widget) != -1) {
+ if (isManaged)
+ *isManaged = core->metaDataBase()->item(layout);
+ if (ptrToLayout)
+ *ptrToLayout = layout;
+ return layoutType(core, layout);
+ }
+ }
+
+ return NoLayout;
+}
+
+QLayout *LayoutInfo::internalLayout(const QWidget *widget)
+{
+ QLayout *widgetLayout = widget->layout();
+ if (widgetLayout && widget->inherits("Q3GroupBox")) {
+ if (widgetLayout->count()) {
+ widgetLayout = widgetLayout->itemAt(0)->layout();
+ } else {
+ widgetLayout = 0;
+ }
+ }
+ return widgetLayout;
+}
+
+
+QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, const QWidget *widget)
+{
+ if (widget == 0)
+ return 0;
+
+ QLayout *layout = widget->layout();
+ if (!layout)
+ return 0;
+
+ return managedLayout(core, layout);
+}
+
+QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout)
+{
+ QDesignerMetaDataBaseInterface *metaDataBase = core->metaDataBase();
+
+ if (!metaDataBase)
+ return layout;
+ /* This code exists mainly for the Q3GroupBox class, for which
+ * widget->layout() returns an internal VBoxLayout. */
+ const QDesignerMetaDataBaseItemInterface *item = metaDataBase->item(layout);
+ if (item == 0) {
+ layout = qFindChild<QLayout*>(layout);
+ item = metaDataBase->item(layout);
+ }
+ if (!item)
+ return 0;
+ return layout;
+}
+
+// Is it a a dummy grid placeholder created by Designer?
+bool LayoutInfo::isEmptyItem(QLayoutItem *item)
+{
+ if (item == 0) {
+ qDebug() << "** WARNING Zero-item passed on to isEmptyItem(). This indicates a layout inconsistency.";
+ return true;
+ }
+ return item->spacerItem() != 0;
+}
+
+QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr, int *rowspanPtr, int *colspanPtr)
+{
+ int row;
+ QFormLayout::ItemRole role;
+ formLayout->getItemPosition(index, &row, &role);
+ const int columnspan = role == QFormLayout::SpanningRole ? 2 : 1;
+ const int column = (columnspan > 1 || role == QFormLayout::LabelRole) ? 0 : 1;
+ if (rowPtr)
+ *rowPtr = row;
+ if (columnPtr)
+ *columnPtr = column;
+ if (rowspanPtr)
+ *rowspanPtr = 1;
+ if (colspanPtr)
+ *colspanPtr = columnspan;
+}
+
+static inline QFormLayout::ItemRole formLayoutRole(int column, int colspan)
+{
+ if (colspan > 1)
+ return QFormLayout::SpanningRole;
+ return column == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
+}
+
+QDESIGNER_SHARED_EXPORT void formLayoutAddWidget(QFormLayout *formLayout, QWidget *w, const QRect &r, bool insert)
+{
+ // Consistent API galore...
+ if (insert) {
+ const bool spanning = r.width() > 1;
+ if (spanning) {
+ formLayout->insertRow(r.y(), w);
+ } else {
+ QWidget *label = 0, *field = 0;
+ if (r.x() == 0) {
+ label = w;
+ } else {
+ field = w;
+ }
+ formLayout->insertRow(r.y(), label, field);
+ }
+ } else {
+ formLayout->setWidget(r.y(), formLayoutRole(r.x(), r.width()), w);
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/layoutinfo_p.h b/tools/designer/src/lib/shared/layoutinfo_p.h
new file mode 100644
index 0000000..64f3f04
--- /dev/null
+++ b/tools/designer/src/lib/shared/layoutinfo_p.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$
+**
+****************************************************************************/
+
+//
+// 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 LAYOUTINFO_H
+#define LAYOUTINFO_H
+
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+class QLayout;
+class QLayoutItem;
+class QDesignerFormEditorInterface;
+class QFormLayout;
+class QRect;
+class QString;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT LayoutInfo
+{
+public:
+ enum Type
+ {
+ NoLayout,
+ HSplitter,
+ VSplitter,
+ HBox,
+ VBox,
+ Grid,
+ Form,
+ UnknownLayout // QDockWindow inside QMainWindow is inside QMainWindowLayout - it doesn't mean there is no layout
+ };
+
+ static void deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget);
+
+ // Examines the immediate layout of the widget (will fail for Q3Group Box).
+ static Type layoutType(const QDesignerFormEditorInterface *core, const QWidget *w);
+ // Examines the managed layout of the widget
+ static Type managedLayoutType(const QDesignerFormEditorInterface *core, const QWidget *w, QLayout **layout = 0);
+ static Type layoutType(const QDesignerFormEditorInterface *core, const QLayout *layout);
+ static Type layoutType(const QString &typeName);
+ static QString layoutName(Type t);
+
+ static QWidget *layoutParent(const QDesignerFormEditorInterface *core, QLayout *layout);
+
+ static Type laidoutWidgetType(const QDesignerFormEditorInterface *core, QWidget *widget, bool *isManaged = 0, QLayout **layout = 0);
+ static bool inline isWidgetLaidout(const QDesignerFormEditorInterface *core, QWidget *widget) { return laidoutWidgetType(core, widget) != NoLayout; }
+
+ static QLayout *managedLayout(const QDesignerFormEditorInterface *core, const QWidget *widget);
+ static QLayout *managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout);
+ static QLayout *internalLayout(const QWidget *widget);
+
+ // Is it a a dummy grid placeholder created by Designer?
+ static bool isEmptyItem(QLayoutItem *item);
+};
+
+QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr = 0, int *rowspanPtr = 0, int *colspanPtr = 0);
+QDESIGNER_SHARED_EXPORT void formLayoutAddWidget(QFormLayout *formLayout, QWidget *w, const QRect &r, bool insert);
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // LAYOUTINFO_H
diff --git a/tools/designer/src/lib/shared/metadatabase.cpp b/tools/designer/src/lib/shared/metadatabase.cpp
new file mode 100644
index 0000000..1403440
--- /dev/null
+++ b/tools/designer/src/lib/shared/metadatabase.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** 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 "metadatabase_p.h"
+#include "widgetdatabase_p.h"
+
+// sdk
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+// Qt
+#include <QtGui/QWidget>
+#include <QtCore/qalgorithms.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ const bool debugMetaDatabase = false;
+}
+
+namespace qdesigner_internal {
+
+MetaDataBaseItem::MetaDataBaseItem(QObject *object)
+ : m_object(object),
+ m_enabled(true)
+{
+}
+
+MetaDataBaseItem::~MetaDataBaseItem()
+{
+}
+
+QString MetaDataBaseItem::name() const
+{
+ Q_ASSERT(m_object);
+ return m_object->objectName();
+}
+
+void MetaDataBaseItem::setName(const QString &name)
+{
+ Q_ASSERT(m_object);
+ m_object->setObjectName(name);
+}
+
+QString MetaDataBaseItem::customClassName() const
+{
+ return m_customClassName;
+}
+void MetaDataBaseItem::setCustomClassName(const QString &customClassName)
+{
+ m_customClassName = customClassName;
+}
+
+
+MetaDataBaseItem::TabOrder MetaDataBaseItem::tabOrder() const
+{
+ return m_tabOrder;
+}
+
+void MetaDataBaseItem::setTabOrder(const TabOrder &tabOrder)
+{
+ m_tabOrder = tabOrder;
+}
+
+bool MetaDataBaseItem::enabled() const
+{
+ return m_enabled;
+}
+
+void MetaDataBaseItem::setEnabled(bool b)
+{
+ m_enabled = b;
+}
+
+QString MetaDataBaseItem::script() const
+{
+ return m_script;
+}
+
+void MetaDataBaseItem::setScript(const QString &script)
+{
+ m_script = script;
+}
+
+QStringList MetaDataBaseItem::fakeSlots() const
+{
+ return m_fakeSlots;
+}
+
+void MetaDataBaseItem::setFakeSlots(const QStringList &fs)
+{
+ m_fakeSlots = fs;
+}
+
+QStringList MetaDataBaseItem::fakeSignals() const
+{
+ return m_fakeSignals;
+}
+
+void MetaDataBaseItem::setFakeSignals(const QStringList &fs)
+{
+ m_fakeSignals = fs;
+}
+
+// -----------------------------------------------------
+MetaDataBase::MetaDataBase(QDesignerFormEditorInterface *core, QObject *parent)
+ : QDesignerMetaDataBaseInterface(parent),
+ m_core(core)
+{
+}
+
+MetaDataBase::~MetaDataBase()
+{
+ qDeleteAll(m_items);
+}
+
+MetaDataBaseItem *MetaDataBase::metaDataBaseItem(QObject *object) const
+{
+ MetaDataBaseItem *i = m_items.value(object);
+ if (i == 0 || !i->enabled())
+ return 0;
+ return i;
+}
+
+void MetaDataBase::add(QObject *object)
+{
+ MetaDataBaseItem *item = m_items.value(object);
+ if (item != 0) {
+ item->setEnabled(true);
+ if (debugMetaDatabase) {
+ qDebug() << "MetaDataBase::add: Existing item for " << object->metaObject()->className() << item->name();
+ }
+ return;
+ }
+
+ item = new MetaDataBaseItem(object);
+ m_items.insert(object, item);
+ if (debugMetaDatabase) {
+ qDebug() << "MetaDataBase::add: New item " << object->metaObject()->className() << item->name();
+ }
+ connect(object, SIGNAL(destroyed(QObject*)),
+ this, SLOT(slotDestroyed(QObject*)));
+
+ emit changed();
+}
+
+void MetaDataBase::remove(QObject *object)
+{
+ Q_ASSERT(object);
+
+ if (MetaDataBaseItem *item = m_items.value(object)) {
+ item->setEnabled(false);
+ emit changed();
+ }
+}
+
+QList<QObject*> MetaDataBase::objects() const
+{
+ QList<QObject*> result;
+
+ ItemMap::const_iterator it = m_items.begin();
+ for (; it != m_items.end(); ++it) {
+ if (it.value()->enabled())
+ result.append(it.key());
+ }
+
+ return result;
+}
+
+QDesignerFormEditorInterface *MetaDataBase::core() const
+{
+ return m_core;
+}
+
+void MetaDataBase::slotDestroyed(QObject *object)
+{
+ if (m_items.contains(object)) {
+ MetaDataBaseItem *item = m_items.value(object);
+ delete item;
+ m_items.remove(object);
+ }
+}
+
+// promotion convenience
+QDESIGNER_SHARED_EXPORT bool promoteWidget(QDesignerFormEditorInterface *core,QWidget *widget,const QString &customClassName)
+{
+
+ MetaDataBase *db = qobject_cast<MetaDataBase *>(core->metaDataBase());
+ if (!db)
+ return false;
+ MetaDataBaseItem *item = db->metaDataBaseItem(widget);
+ if (!item) {
+ db ->add(widget);
+ item = db->metaDataBaseItem(widget);
+ }
+ // Recursive promotion occurs if there is a plugin missing.
+ const QString oldCustomClassName = item->customClassName();
+ if (!oldCustomClassName.isEmpty()) {
+ qDebug() << "WARNING: Recursive promotion of " << oldCustomClassName << " to " << customClassName
+ << ". A plugin is missing.";
+ }
+ item->setCustomClassName(customClassName);
+ if (debugMetaDatabase) {
+ qDebug() << "Promoting " << widget->metaObject()->className() << " to " << customClassName;
+ }
+ return true;
+}
+
+QDESIGNER_SHARED_EXPORT void demoteWidget(QDesignerFormEditorInterface *core,QWidget *widget)
+{
+ MetaDataBase *db = qobject_cast<MetaDataBase *>(core->metaDataBase());
+ if (!db)
+ return;
+ MetaDataBaseItem *item = db->metaDataBaseItem(widget);
+ item->setCustomClassName(QString());
+ if (debugMetaDatabase) {
+ qDebug() << "Demoting " << widget;
+ }
+}
+
+QDESIGNER_SHARED_EXPORT bool isPromoted(QDesignerFormEditorInterface *core, QWidget* widget)
+{
+ const MetaDataBase *db = qobject_cast<const MetaDataBase *>(core->metaDataBase());
+ if (!db)
+ return false;
+ const MetaDataBaseItem *item = db->metaDataBaseItem(widget);
+ if (!item)
+ return false;
+ return !item->customClassName().isEmpty();
+}
+
+QDESIGNER_SHARED_EXPORT QString promotedCustomClassName(QDesignerFormEditorInterface *core, QWidget* widget)
+{
+ const MetaDataBase *db = qobject_cast<const MetaDataBase *>(core->metaDataBase());
+ if (!db)
+ return QString();
+ const MetaDataBaseItem *item = db->metaDataBaseItem(widget);
+ if (!item)
+ return QString();
+ return item->customClassName();
+}
+
+QDESIGNER_SHARED_EXPORT QString promotedExtends(QDesignerFormEditorInterface *core, QWidget* widget)
+{
+ const QString customClassName = promotedCustomClassName(core,widget);
+ if (customClassName.isEmpty())
+ return QString();
+ const int i = core->widgetDataBase()->indexOfClassName(customClassName);
+ if (i == -1)
+ return QString();
+ return core->widgetDataBase()->item(i)->extends();
+}
+
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/metadatabase_p.h b/tools/designer/src/lib/shared/metadatabase_p.h
new file mode 100644
index 0000000..874b540
--- /dev/null
+++ b/tools/designer/src/lib/shared/metadatabase_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 METADATABASE_H
+#define METADATABASE_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtGui/QCursor>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT MetaDataBaseItem: public QDesignerMetaDataBaseItemInterface
+{
+public:
+ explicit MetaDataBaseItem(QObject *object);
+ virtual ~MetaDataBaseItem();
+
+ virtual QString name() const;
+ virtual void setName(const QString &name);
+
+ typedef QList<QWidget*> TabOrder;
+ virtual TabOrder tabOrder() const;
+ virtual void setTabOrder(const TabOrder &tabOrder);
+
+ virtual bool enabled() const;
+ virtual void setEnabled(bool b);
+
+ QString customClassName() const;
+ void setCustomClassName(const QString &customClassName);
+
+ QString script() const;
+ void setScript(const QString &script);
+
+ QStringList fakeSlots() const;
+ void setFakeSlots(const QStringList &);
+
+ QStringList fakeSignals() const;
+ void setFakeSignals(const QStringList &);
+
+private:
+ QObject *m_object;
+ TabOrder m_tabOrder;
+ bool m_enabled;
+ QString m_customClassName;
+ QString m_script;
+ QStringList m_fakeSlots;
+ QStringList m_fakeSignals;
+};
+
+class QDESIGNER_SHARED_EXPORT MetaDataBase: public QDesignerMetaDataBaseInterface
+{
+ Q_OBJECT
+public:
+ explicit MetaDataBase(QDesignerFormEditorInterface *core, QObject *parent = 0);
+ virtual ~MetaDataBase();
+
+ virtual QDesignerFormEditorInterface *core() const;
+
+ virtual QDesignerMetaDataBaseItemInterface *item(QObject *object) const { return metaDataBaseItem(object); }
+ virtual MetaDataBaseItem *metaDataBaseItem(QObject *object) const;
+ virtual void add(QObject *object);
+ virtual void remove(QObject *object);
+
+ virtual QList<QObject*> objects() const;
+
+private slots:
+ void slotDestroyed(QObject *object);
+
+private:
+ QDesignerFormEditorInterface *m_core;
+ typedef QHash<QObject *, MetaDataBaseItem*> ItemMap;
+ ItemMap m_items;
+};
+
+ // promotion convenience
+ QDESIGNER_SHARED_EXPORT bool promoteWidget(QDesignerFormEditorInterface *core,QWidget *widget,const QString &customClassName);
+ QDESIGNER_SHARED_EXPORT void demoteWidget(QDesignerFormEditorInterface *core,QWidget *widget);
+ QDESIGNER_SHARED_EXPORT bool isPromoted(QDesignerFormEditorInterface *core, QWidget* w);
+ QDESIGNER_SHARED_EXPORT QString promotedCustomClassName(QDesignerFormEditorInterface *core, QWidget* w);
+ QDESIGNER_SHARED_EXPORT QString promotedExtends(QDesignerFormEditorInterface *core, QWidget* w);
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // METADATABASE_H
diff --git a/tools/designer/src/lib/shared/morphmenu.cpp b/tools/designer/src/lib/shared/morphmenu.cpp
new file mode 100644
index 0000000..0d41af0
--- /dev/null
+++ b/tools/designer/src/lib/shared/morphmenu.cpp
@@ -0,0 +1,635 @@
+/****************************************************************************
+**
+** 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 "morphmenu_p.h"
+#include "formwindowbase_p.h"
+#include "widgetfactory_p.h"
+#include "qdesigner_formwindowcommand_p.h"
+#include "qlayout_widget_p.h"
+#include "layoutinfo_p.h"
+#include "qdesigner_propertycommand_p.h"
+
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+
+#include <QtGui/QWidget>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtGui/QApplication>
+#include <QtGui/QLayout>
+#include <QtGui/QUndoStack>
+
+#include <QtGui/QFrame>
+#include <QtGui/QGroupBox>
+#include <QtGui/QTabWidget>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QToolBox>
+#include <QtGui/QAbstractItemView>
+#include <QtGui/QAbstractButton>
+#include <QtGui/QAbstractSpinBox>
+#include <QtGui/QTextEdit>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QLabel>
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QVariant>
+#include <QtCore/QSignalMapper>
+#include <QtCore/QDebug>
+
+Q_DECLARE_METATYPE(QWidgetList)
+
+QT_BEGIN_NAMESPACE
+
+// Helpers for the dynamic properties that store Z/Widget order
+static const char *widgetOrderPropertyC = "_q_widgetOrder";
+static const char *zOrderPropertyC = "_q_zOrder";
+
+/* Morphing in Designer:
+ * It is possible to morph:
+ * - Non-Containers into similar widgets by category
+ * - Simple page containers into similar widgets or page-based containers with
+ * a single page (in theory also into a QLayoutWidget, but this might
+ * not always be appropriate).
+ * - Page-based containers into page-based containers or simple containers if
+ * they have just one page
+ * [Page based containers meaning here having a container extension]
+ * Morphing types are restricted to the basic Qt types. Morphing custom
+ * widgets is considered risky since they might have unmanaged layouts
+ * or the like.
+ *
+ * Requirements:
+ * - The widget must be on a non-laid out parent or in a layout managed
+ * by Designer
+ * - Its child widgets must be non-laid out or in a layout managed
+ * by Designer
+ * Note that child widgets can be
+ * - On the widget itself in the case of simple containers
+ * - On several pages in the case of page-based containers
+ * This is what is called 'childContainers' in the code (the widget itself
+ * or the list of container extension pages).
+ *
+ * The Morphing process encompasses:
+ * - Create a target widget and apply properties as far as applicable
+ * If the target widget has a container extension, add a sufficient
+ * number of pages.
+ * - Transferring the child widgets over to the new childContainers.
+ * In the case of a managed layout on a childContainer, this is simply
+ * set on the target childContainer, which is a new Qt 4.5
+ * functionality.
+ * - Replace the widget itself in the parent layout
+ */
+
+namespace qdesigner_internal {
+
+enum MorphCategory {
+ MorphCategoryNone, MorphSimpleContainer, MorphPageContainer, MorphItemView,
+ MorphButton, MorphSpinBox, MorphTextEdit
+};
+
+// Determine category of a widget
+static MorphCategory category(const QWidget *w)
+{
+ // Simple containers: Exact match
+ const QMetaObject *mo = w->metaObject();
+ if (mo == &QWidget::staticMetaObject || mo == &QFrame::staticMetaObject || mo == &QGroupBox::staticMetaObject || mo == &QLayoutWidget::staticMetaObject)
+ return MorphSimpleContainer;
+ if (mo == &QTabWidget::staticMetaObject || mo == &QStackedWidget::staticMetaObject || mo == &QToolBox::staticMetaObject)
+ return MorphPageContainer;
+ if (qobject_cast<const QAbstractItemView*>(w))
+ return MorphItemView;
+ if (qobject_cast<const QAbstractButton *>(w))
+ return MorphButton;
+ if (qobject_cast<const QAbstractSpinBox *>(w))
+ return MorphSpinBox;
+ if (qobject_cast<const QPlainTextEdit *>(w) || qobject_cast<const QTextEdit*>(w))
+ return MorphTextEdit;
+
+ return MorphCategoryNone;
+}
+
+/* Return the similar classes of a category. This is currently restricted
+ * to the known Qt classes with no precautions to parse the Widget Database
+ * (which is too risky, custom classes might have container extensions
+ * or non-managed layouts, etc.). */
+
+static QStringList classesOfCategory(MorphCategory cat)
+{
+ typedef QMap<MorphCategory, QStringList> CandidateCache;
+ static CandidateCache candidateCache;
+ CandidateCache::iterator it = candidateCache.find(cat);
+ if (it == candidateCache.end()) {
+ it = candidateCache.insert(cat, QStringList());
+ QStringList &l = it.value();
+ switch (cat) {
+ case MorphCategoryNone:
+ break;
+ case MorphSimpleContainer:
+ // Do not generally allow to morph into a layout.
+ // This can be risky in case of container pages,etc.
+ l << QLatin1String("QWidget") << QLatin1String("QFrame") << QLatin1String("QGroupBox");
+ break;
+ case MorphPageContainer:
+ l << QLatin1String("QTabWidget") << QLatin1String("QStackedWidget") << QLatin1String("QToolBox");
+ break;
+ case MorphItemView:
+ l << QLatin1String("QListView") << QLatin1String("QListWidget")
+ << QLatin1String("QTreeView") << QLatin1String("QTreeWidget")
+ << QLatin1String("QTableView") << QLatin1String("QTableWidget")
+ << QLatin1String("QColumnView");
+ break;
+ case MorphButton:
+ l << QLatin1String("QCheckBox") << QLatin1String("QRadioButton")
+ << QLatin1String("QPushButton") << QLatin1String("QToolButton")
+ << QLatin1String("QCommandLinkButton");
+ break;
+ case MorphSpinBox:
+ l << QLatin1String("QDateTimeEdit") << QLatin1String("QDateEdit")
+ << QLatin1String("QTimeEdit")
+ << QLatin1String("QSpinBox") << QLatin1String("QDoubleSpinBox");
+ break;
+ case MorphTextEdit:
+ l << QLatin1String("QTextEdit") << QLatin1String("QPlainTextEdit");
+ break;
+ }
+ }
+ return it.value();
+}
+
+// Return the widgets containing the children to be transferred to. This is the
+// widget itself in most cases, except for QDesignerContainerExtension cases
+static QWidgetList childContainers(const QDesignerFormEditorInterface *core, QWidget *w)
+{
+ if (const QDesignerContainerExtension *ce = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), w)) {
+ QWidgetList children;
+ if (const int count = ce->count()) {
+ for (int i = 0; i < count; i++)
+ children.push_back(ce->widget(i));
+ }
+ return children;
+ }
+ QWidgetList self;
+ self.push_back(w);
+ return self;
+}
+
+// Suggest a suitable objectname for the widget to be morphed into
+// Replace the class name parts: 'xxFrame' -> 'xxGroupBox', 'frame' -> 'groupBox'
+static QString suggestObjectName(const QString &oldClassName, const QString &newClassName, const QString &oldName)
+{
+ QString oldClassPart = oldClassName;
+ QString newClassPart = newClassName;
+ if (oldClassPart.startsWith(QLatin1Char('Q')))
+ oldClassPart.remove(0, 1);
+ if (newClassPart.startsWith(QLatin1Char('Q')))
+ newClassPart.remove(0, 1);
+
+ QString newName = oldName;
+ newName.replace(oldClassPart, newClassPart);
+ oldClassPart[0] = oldClassPart.at(0).toLower();
+ newClassPart[0] = newClassPart.at(0).toLower();
+ newName.replace(oldClassPart, newClassPart);
+ return newName;
+}
+
+// Find the label whose buddy the widget is.
+QLabel *buddyLabelOf(QDesignerFormWindowInterface *fw, QWidget *w)
+{
+ typedef QList<QLabel*> LabelList;
+ const LabelList labelList = qFindChildren<QLabel*>(fw);
+ if (labelList.empty())
+ return 0;
+ const LabelList::const_iterator cend = labelList.constEnd();
+ for (LabelList::const_iterator it = labelList.constBegin(); it != cend; ++it )
+ if ( (*it)->buddy() == w)
+ return *it;
+ return 0;
+}
+
+// Replace widgets in a widget-list type dynamic property of the parent
+// used for Z-order, etc.
+static void replaceWidgetListDynamicProperty(QWidget *parentWidget,
+ QWidget *oldWidget, QWidget *newWidget,
+ const char *name)
+{
+ QWidgetList list = qVariantValue<QWidgetList>(parentWidget->property(name));
+ const int index = list.indexOf(oldWidget);
+ if (index != -1) {
+ list.replace(index, newWidget);
+ parentWidget->setProperty(name, qVariantFromValue(list));
+ }
+}
+
+/* Morph a widget into another class. Use the static addMorphMacro() to
+ * add a respective command sequence to the undo stack as it emits signals
+ * which cause other commands to be added. */
+class MorphWidgetCommand : public QDesignerFormWindowCommand
+{
+ Q_DISABLE_COPY(MorphWidgetCommand)
+public:
+
+ explicit MorphWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ ~MorphWidgetCommand();
+
+ // Convenience to add a morph command sequence macro
+ static bool addMorphMacro(QDesignerFormWindowInterface *formWindow, QWidget *w, const QString &newClass);
+
+ bool init(QWidget *widget, const QString &newClass);
+
+ QString newWidgetName() const { return m_afterWidget->objectName(); }
+
+ virtual void redo();
+ virtual void undo();
+
+ static QStringList candidateClasses(QDesignerFormWindowInterface *fw, QWidget *w);
+
+private:
+ static bool canMorph(QDesignerFormWindowInterface *fw, QWidget *w, int *childContainerCount = 0, MorphCategory *cat = 0);
+ void morph(QWidget *before, QWidget *after);
+
+ QWidget *m_beforeWidget;
+ QWidget *m_afterWidget;
+};
+
+bool MorphWidgetCommand::addMorphMacro(QDesignerFormWindowInterface *fw, QWidget *w, const QString &newClass)
+{
+ MorphWidgetCommand *morphCmd = new MorphWidgetCommand(fw);
+ if (!morphCmd->init(w, newClass)) {
+ qWarning("*** Unable to create a MorphWidgetCommand");
+ delete morphCmd;
+ return false;
+ }
+ QLabel *buddyLabel = buddyLabelOf(fw, w);
+ // Need a macro since it adds further commands
+ QUndoStack *us = fw->commandHistory();
+ us->beginMacro(morphCmd->text());
+ // Have the signal slot/buddy editors add their commands to delete widget
+ if (FormWindowBase *fwb = qobject_cast<FormWindowBase*>(fw))
+ fwb->emitWidgetRemoved(w);
+
+ const QString newWidgetName = morphCmd->newWidgetName();
+ us->push(morphCmd);
+
+ // restore buddy using the QByteArray name.
+ if (buddyLabel) {
+ SetPropertyCommand *buddyCmd = new SetPropertyCommand(fw);
+ buddyCmd->init(buddyLabel, QLatin1String("buddy"), QVariant(newWidgetName.toUtf8()));
+ us->push(buddyCmd);
+ }
+ us->endMacro();
+ return true;
+}
+
+MorphWidgetCommand::MorphWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_beforeWidget(0),
+ m_afterWidget(0)
+{
+}
+
+MorphWidgetCommand::~MorphWidgetCommand()
+{
+}
+
+bool MorphWidgetCommand::init(QWidget *widget, const QString &newClassName)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ QDesignerFormEditorInterface *core = fw->core();
+
+ if (!canMorph(fw, widget))
+ return false;
+
+ const QString oldClassName = WidgetFactory::classNameOf(core, widget);
+ const QString oldName = widget->objectName();
+ //: MorphWidgetCommand description
+ setText(QApplication::translate("Command", "Morph %1/'%2' into %3").arg(oldClassName, oldName, newClassName));
+
+ m_beforeWidget = widget;
+ m_afterWidget = core->widgetFactory()->createWidget(newClassName, fw);
+ if (!m_afterWidget)
+ return false;
+
+ // Set object name. Do not unique it (as to maintain it).
+ m_afterWidget->setObjectName(suggestObjectName(oldClassName, newClassName, oldName));
+
+ // If the target has a container extension, we add enough new pages to take
+ // up the children of the before widget
+ if (QDesignerContainerExtension* c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_afterWidget)) {
+ if (const int pageCount = childContainers(core, m_beforeWidget).size()) {
+ const QString qWidget = QLatin1String("QWidget");
+ const QString containerName = m_afterWidget->objectName();
+ for (int i = 0; i < pageCount; i++) {
+ QString name = containerName;
+ name += QLatin1String("Page");
+ name += QString::number(i + 1);
+ QWidget *page = core->widgetFactory()->createWidget(qWidget);
+ page->setObjectName(name);
+ fw->ensureUniqueObjectName(page);
+ c->addWidget(page);
+ core->metaDataBase()->add(page);
+ }
+ }
+ }
+
+ // Copy over applicable properties
+ const QDesignerPropertySheetExtension *beforeSheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), widget);
+ QDesignerPropertySheetExtension *afterSheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), m_afterWidget);
+ const QString objectNameProperty = QLatin1String("objectName");
+ const int count = beforeSheet->count();
+ for (int i = 0; i < count; i++)
+ if (beforeSheet->isVisible(i) && beforeSheet->isChanged(i)) {
+ const QString name = beforeSheet->propertyName(i);
+ if (name != objectNameProperty) {
+ const int afterIndex = afterSheet->indexOf(name);
+ if (afterIndex != -1 && afterSheet->isVisible(afterIndex) && afterSheet->propertyGroup(afterIndex) == beforeSheet->propertyGroup(i)) {
+ afterSheet->setProperty(i, beforeSheet->property(i));
+ afterSheet->setChanged(i, true);
+ } else {
+ // Some mismatch. The rest won't match, either
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+void MorphWidgetCommand::redo()
+{
+ morph(m_beforeWidget, m_afterWidget);
+}
+
+void MorphWidgetCommand::undo()
+{
+ morph(m_afterWidget, m_beforeWidget);
+}
+
+void MorphWidgetCommand::morph(QWidget *before, QWidget *after)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+
+ fw->unmanageWidget(before);
+
+ const QRect oldGeom = before->geometry();
+ QWidget *parent = before->parentWidget();
+ Q_ASSERT(parent);
+ /* Morphing consists of main 2 steps
+ * 1) Move over children (laid out, non-laid out)
+ * 2) Register self with new parent (laid out, non-laid out) */
+
+ // 1) Move children. Loop over child containers
+ QWidgetList beforeChildContainers = childContainers(fw->core(), before);
+ QWidgetList afterChildContainers = childContainers(fw->core(), after);
+ Q_ASSERT(beforeChildContainers.size() == afterChildContainers.size());
+ const int childContainerCount = beforeChildContainers.size();
+ for (int i = 0; i < childContainerCount; i++) {
+ QWidget *beforeChildContainer = beforeChildContainers.at(i);
+ QWidget *afterChildContainer = afterChildContainers.at(i);
+ if (QLayout *childLayout = beforeChildContainer->layout()) {
+ // Laid-out: Move the layout (since 4.5)
+ afterChildContainer->setLayout(childLayout);
+ } else {
+ // Non-Laid-out: Reparent, move over
+ const QObjectList c = beforeChildContainer->children();
+ const QObjectList::const_iterator cend = c.constEnd();
+ for (QObjectList::const_iterator it = c.constBegin(); it != cend; ++it) {
+ if ( (*it)->isWidgetType()) {
+ QWidget *w = static_cast<QWidget*>(*it);
+ if (fw->isManaged(w)) {
+ const QRect geom = w->geometry();
+ w->setParent(afterChildContainer);
+ w->setGeometry(geom);
+ }
+ }
+ }
+ }
+ afterChildContainer->setProperty(widgetOrderPropertyC, beforeChildContainer->property(widgetOrderPropertyC));
+ afterChildContainer->setProperty(zOrderPropertyC, beforeChildContainer->property(zOrderPropertyC));
+ }
+
+ // 2) Replace the actual widget in the parent layout
+ after->setGeometry(oldGeom);
+ if (QLayout *containingLayout = LayoutInfo::managedLayout(fw->core(), parent)) {
+ LayoutHelper *lh = LayoutHelper::createLayoutHelper(LayoutInfo::layoutType(fw->core(), containingLayout));
+ Q_ASSERT(lh);
+ lh->replaceWidget(containingLayout, before, after);
+ delete lh;
+ } else {
+ before->hide();
+ before->setParent(0);
+ after->setParent(parent);
+ after->setGeometry(oldGeom);
+ }
+
+ // Check various properties: Z order, form tab order
+ replaceWidgetListDynamicProperty(parent, before, after, widgetOrderPropertyC);
+ replaceWidgetListDynamicProperty(parent, before, after, zOrderPropertyC);
+
+ QDesignerMetaDataBaseItemInterface *formItem = fw->core()->metaDataBase()->item(fw);
+ QWidgetList tabOrder = formItem->tabOrder();
+ const int tabIndex = tabOrder.indexOf(before);
+ if (tabIndex != -1) {
+ tabOrder.replace(tabIndex, after);
+ formItem->setTabOrder(tabOrder);
+ }
+
+ after->show();
+ fw->manageWidget(after);
+
+ fw->clearSelection(false);
+ fw->selectWidget(after);
+}
+
+/* Check if morphing is possible. It must be a valid category and the parent/
+ * child relationships must be either non-laidout or directly on
+ * Designer-managed layouts. */
+bool MorphWidgetCommand::canMorph(QDesignerFormWindowInterface *fw, QWidget *w, int *ptrToChildContainerCount, MorphCategory *ptrToCat)
+{
+ if (ptrToChildContainerCount)
+ *ptrToChildContainerCount = 0;
+ const MorphCategory cat = category(w);
+ if (ptrToCat)
+ *ptrToCat = cat;
+ if (cat == MorphCategoryNone)
+ return false;
+
+ QDesignerFormEditorInterface *core = fw->core();
+ // Don't know how to fiddle class names in Jambi..
+ if (qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core))
+ return false;
+ if (!fw->isManaged(w) || w == fw->mainContainer())
+ return false;
+ // Check the parent relationship. We accept only managed parent widgets
+ // with a single, managed layout in which widget is a member.
+ QWidget *parent = w->parentWidget();
+ if (parent == 0)
+ return false;
+ if (QLayout *pl = LayoutInfo::managedLayout(core, parent))
+ if (pl->indexOf(w) < 0 || !core->metaDataBase()->item(pl))
+ return false;
+ // Check Widget database
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ const int wdbindex = wdb->indexOfObject(w);
+ if (wdbindex == -1)
+ return false;
+ const bool isContainer = wdb->item(wdbindex)->isContainer();
+ if (!isContainer)
+ return true;
+ // Check children. All child containers must be non-laid-out or have managed layouts
+ const QWidgetList pages = childContainers(core, w);
+ const int pageCount = pages.size();
+ if (ptrToChildContainerCount)
+ *ptrToChildContainerCount = pageCount;
+ if (pageCount) {
+ for (int i = 0; i < pageCount; i++)
+ if (QLayout *cl = pages.at(i)->layout())
+ if (!core->metaDataBase()->item(cl))
+ return false;
+ }
+ return true;
+}
+
+QStringList MorphWidgetCommand::candidateClasses(QDesignerFormWindowInterface *fw, QWidget *w)
+{
+ int childContainerCount;
+ MorphCategory cat;
+ if (!canMorph(fw, w, &childContainerCount, &cat))
+ return QStringList();
+
+ QStringList rc = classesOfCategory(cat);
+ switch (cat) {
+ // Frames, etc can always be morphed into one-page page containers
+ case MorphSimpleContainer:
+ rc += classesOfCategory(MorphPageContainer);
+ break;
+ // Multipage-Containers can be morphed into simple containers if they
+ // have 1 page.
+ case MorphPageContainer:
+ if (childContainerCount == 1)
+ rc += classesOfCategory(MorphSimpleContainer);
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+// MorphMenu
+MorphMenu::MorphMenu(QObject *parent) :
+ QObject(parent),
+ m_subMenuAction(0),
+ m_menu(0),
+ m_mapper(0),
+ m_widget(0),
+ m_formWindow(0)
+{
+}
+
+void MorphMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList& al)
+{
+ if (populateMenu(w, fw))
+ al.push_back(m_subMenuAction);
+}
+
+void MorphMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, QMenu& m)
+{
+ if (populateMenu(w, fw))
+ m.addAction(m_subMenuAction);
+}
+
+void MorphMenu::slotMorph(const QString &newClassName)
+{
+ MorphWidgetCommand::addMorphMacro(m_formWindow, m_widget, newClassName);
+}
+
+bool MorphMenu::populateMenu(QWidget *w, QDesignerFormWindowInterface *fw)
+{
+ m_widget = 0;
+ m_formWindow = 0;
+
+ // Clear menu
+ if (m_subMenuAction) {
+ m_subMenuAction->setVisible(false);
+ m_menu->clear();
+ }
+
+ // Checks: Must not be main container
+ if (w == fw->mainContainer())
+ return false;
+
+ const QStringList c = MorphWidgetCommand::candidateClasses(fw, w);
+ if (c.empty())
+ return false;
+
+ // Pull up
+ m_widget = w;
+ m_formWindow = fw;
+ const QString oldClassName = WidgetFactory::classNameOf(fw->core(), w);
+
+ if (!m_subMenuAction) {
+ m_subMenuAction = new QAction(tr("Morph into"), this);
+ m_menu = new QMenu;
+ m_subMenuAction->setMenu(m_menu);
+ m_mapper = new QSignalMapper(this);
+ connect(m_mapper , SIGNAL(mapped(QString)), this, SLOT(slotMorph(QString)));
+ }
+
+ // Add actions
+ const QStringList::const_iterator cend = c.constEnd();
+ for (QStringList::const_iterator it = c.constBegin(); it != cend; ++it) {
+ if (*it != oldClassName) {
+ QAction *a = m_menu->addAction(*it);
+ m_mapper->setMapping (a, *it);
+ connect(a, SIGNAL(triggered()), m_mapper, SLOT(map()));
+ }
+ }
+ m_subMenuAction->setVisible(true);
+ return true;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/morphmenu_p.h b/tools/designer/src/lib/shared/morphmenu_p.h
new file mode 100644
index 0000000..92389a0
--- /dev/null
+++ b/tools/designer/src/lib/shared/morphmenu_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 MORPH_COMMAND_H
+#define MORPH_COMMAND_H
+
+#include "shared_global_p.h"
+#include "qdesigner_formwindowcommand_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAction;
+class QSignalMapper;
+class QMenu;
+
+namespace qdesigner_internal {
+
+/* Conveniene morph menu that acts on a single widget. */
+class QDESIGNER_SHARED_EXPORT MorphMenu : public QObject {
+ Q_DISABLE_COPY(MorphMenu)
+ Q_OBJECT
+public:
+ typedef QList<QAction *> ActionList;
+
+ explicit MorphMenu(QObject *parent = 0);
+
+ void populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList& al);
+ void populate(QWidget *w, QDesignerFormWindowInterface *fw, QMenu& m);
+
+private slots:
+ void slotMorph(const QString &newClassName);
+
+private:
+ bool populateMenu(QWidget *w, QDesignerFormWindowInterface *fw);
+
+ QAction *m_subMenuAction;
+ QMenu *m_menu;
+ QSignalMapper *m_mapper;
+
+ QWidget *m_widget;
+ QDesignerFormWindowInterface *m_formWindow;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // MORPH_COMMAND_H
diff --git a/tools/designer/src/lib/shared/newactiondialog.cpp b/tools/designer/src/lib/shared/newactiondialog.cpp
new file mode 100644
index 0000000..53aec4b
--- /dev/null
+++ b/tools/designer/src/lib/shared/newactiondialog.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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 "newactiondialog_p.h"
+#include "ui_newactiondialog.h"
+#include "richtexteditor_p.h"
+#include "actioneditor_p.h"
+#include "formwindowbase_p.h"
+#include "qdesigner_utils_p.h"
+#include "iconloader_p.h"
+
+#include <QtDesigner/abstractformwindow.h>
+#include <QtDesigner/abstractformeditor.h>
+
+#include <QtGui/QPushButton>
+#include <QtCore/QRegExp>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+// -------------------- ActionData
+
+ActionData::ActionData() :
+ checkable(false)
+{
+}
+
+// Returns a combination of ChangeMask flags
+unsigned ActionData::compare(const ActionData &rhs) const
+{
+ unsigned rc = 0;
+ if (text != rhs.text)
+ rc |= TextChanged;
+ if (name != rhs.name)
+ rc |= NameChanged;
+ if (toolTip != rhs.toolTip)
+ rc |= ToolTipChanged ;
+ if (icon != rhs.icon)
+ rc |= IconChanged ;
+ if (checkable != rhs.checkable)
+ rc |= CheckableChanged;
+ if (keysequence != rhs.keysequence)
+ rc |= KeysequenceChanged ;
+ return rc;
+}
+
+// -------------------- NewActionDialog
+NewActionDialog::NewActionDialog(ActionEditor *parent) :
+ QDialog(parent, Qt::Sheet),
+ m_ui(new Ui::NewActionDialog),
+ m_actionEditor(parent)
+{
+ m_ui->setupUi(this);
+
+ m_ui->tooltipEditor->setTextPropertyValidationMode(ValidationRichText);
+ connect(m_ui->toolTipToolButton, SIGNAL(clicked()), this, SLOT(slotEditToolTip()));
+
+ m_ui->keysequenceResetToolButton->setIcon(createIconSet(QLatin1String("resetproperty.png")));
+ connect(m_ui->keysequenceResetToolButton, SIGNAL(clicked()), this, SLOT(slotResetKeySequence()));
+
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ m_ui->editActionText->setFocus();
+ m_auto_update_object_name = true;
+ updateButtons();
+
+ QDesignerFormWindowInterface *form = parent->formWindow();
+ m_ui->iconSelector->setFormEditor(form->core());
+ FormWindowBase *formBase = qobject_cast<FormWindowBase *>(form);
+
+ if (formBase) {
+ m_ui->iconSelector->setPixmapCache(formBase->pixmapCache());
+ m_ui->iconSelector->setIconCache(formBase->iconCache());
+ }
+}
+
+NewActionDialog::~NewActionDialog()
+{
+ delete m_ui;
+}
+
+QString NewActionDialog::actionText() const
+{
+ return m_ui->editActionText->text();
+}
+
+QString NewActionDialog::actionName() const
+{
+ return m_ui->editObjectName->text();
+}
+
+ActionData NewActionDialog::actionData() const
+{
+ ActionData rc;
+ rc.text = actionText();
+ rc.name = actionName();
+ rc.toolTip = m_ui->tooltipEditor->text();
+ rc.icon = m_ui->iconSelector->icon();
+ rc.checkable = m_ui->checkableCheckBox->checkState() == Qt::Checked;
+ rc.keysequence = m_ui->keySequenceEdit->keySequence();
+ return rc;
+}
+
+void NewActionDialog::setActionData(const ActionData &d)
+{
+ m_ui->editActionText->setText(d.text);
+ m_ui->editObjectName->setText(d.name);
+ m_ui->iconSelector->setIcon(d.icon);
+ m_ui->tooltipEditor->setText(d.toolTip);
+ m_ui->keySequenceEdit->setKeySequence(d.keysequence);
+ m_ui->checkableCheckBox->setCheckState(d.checkable ? Qt::Checked : Qt::Unchecked);
+
+ m_auto_update_object_name = false;
+ updateButtons();
+}
+
+void NewActionDialog::on_editActionText_textEdited(const QString &text)
+{
+ if (text.isEmpty())
+ m_auto_update_object_name = true;
+
+ if (m_auto_update_object_name)
+ m_ui->editObjectName->setText(ActionEditor::actionTextToName(text));
+
+ updateButtons();
+}
+
+void NewActionDialog::on_editObjectName_textEdited(const QString&)
+{
+ updateButtons();
+ m_auto_update_object_name = false;
+}
+
+void NewActionDialog::slotEditToolTip()
+{
+ const QString oldToolTip = m_ui->tooltipEditor->text();
+ RichTextEditorDialog richTextDialog(m_actionEditor->core(), this);
+ richTextDialog.setText(oldToolTip);
+ if (richTextDialog.showDialog() == QDialog::Rejected)
+ return;
+ const QString newToolTip = richTextDialog.text();
+ if (newToolTip != oldToolTip)
+ m_ui->tooltipEditor->setText(newToolTip);
+}
+
+void NewActionDialog::slotResetKeySequence()
+{
+ m_ui->keySequenceEdit->setKeySequence(QKeySequence());
+ m_ui->keySequenceEdit->setFocus(Qt::MouseFocusReason);
+}
+
+void NewActionDialog::updateButtons()
+{
+ QPushButton *okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok);
+ okButton->setEnabled(!actionText().isEmpty() && !actionName().isEmpty());
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/newactiondialog.ui b/tools/designer/src/lib/shared/newactiondialog.ui
new file mode 100644
index 0000000..77eda28
--- /dev/null
+++ b/tools/designer/src/lib/shared/newactiondialog.ui
@@ -0,0 +1,277 @@
+<?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>qdesigner_internal::NewActionDialog</class>
+ <widget class="QDialog" name="qdesigner_internal::NewActionDialog">
+ <property name="windowTitle">
+ <string>New Action...</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="textLabel">
+ <property name="text">
+ <string>&amp;Text:</string>
+ </property>
+ <property name="buddy">
+ <cstring>editActionText</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="editActionText">
+ <property name="minimumSize">
+ <size>
+ <width>255</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="objectNameLabel">
+ <property name="text">
+ <string>Object &amp;name:</string>
+ </property>
+ <property name="buddy">
+ <cstring>editObjectName</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="editObjectName"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="iconLabel">
+ <property name="text">
+ <string>&amp;Icon:</string>
+ </property>
+ <property name="buddy">
+ <cstring>iconSelector</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="qdesigner_internal::IconSelector" name="iconSelector" native="true"/>
+ </item>
+ <item>
+ <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>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="shortcutLabel">
+ <property name="text">
+ <string>Shortcut:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="checkableCheckBox">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="checkableLabel">
+ <property name="text">
+ <string>Checkable:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="toolTipLabel">
+ <property name="text">
+ <string>ToolTip:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="toolTipLayout">
+ <item>
+ <widget class="TextPropertyEditor" name="tooltipEditor" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="toolTipToolButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="5" column="1">
+ <layout class="QHBoxLayout" name="keysequenceLayout">
+ <item>
+ <widget class="QtKeySequenceEdit" name="keySequenceEdit" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="keysequenceResetToolButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>qdesigner_internal::IconSelector</class>
+ <extends>QWidget</extends>
+ <header>iconselector_p.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>QtKeySequenceEdit</class>
+ <extends>QWidget</extends>
+ <header>qtpropertybrowserutils_p.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>TextPropertyEditor</class>
+ <extends>QWidget</extends>
+ <header>textpropertyeditor_p.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>editActionText</tabstop>
+ <tabstop>editObjectName</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>qdesigner_internal::NewActionDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>165</x>
+ <y>162</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>291</x>
+ <y>94</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>qdesigner_internal::NewActionDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>259</x>
+ <y>162</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>293</x>
+ <y>128</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/designer/src/lib/shared/newactiondialog_p.h b/tools/designer/src/lib/shared/newactiondialog_p.h
new file mode 100644
index 0000000..c8bd34c
--- /dev/null
+++ b/tools/designer/src/lib/shared/newactiondialog_p.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 NEWACTIONDIALOG_P_H
+#define NEWACTIONDIALOG_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 "qdesigner_utils_p.h" // PropertySheetIconValue
+
+#include <QtGui/QDialog>
+#include <QtGui/QKeySequence>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+namespace Ui {
+ class NewActionDialog;
+}
+
+class ActionEditor;
+
+struct ActionData {
+
+ enum ChangeMask {
+ TextChanged = 0x1, NameChanged = 0x2, ToolTipChanged = 0x4,
+ IconChanged = 0x8, CheckableChanged = 0x10, KeysequenceChanged = 0x20
+ };
+
+ ActionData();
+ // Returns a combination of ChangeMask flags
+ unsigned compare(const ActionData &rhs) const;
+
+ QString text;
+ QString name;
+ QString toolTip;
+ PropertySheetIconValue icon;
+ bool checkable;
+ QKeySequence keysequence;
+};
+
+inline bool operator==(const ActionData &a1, const ActionData &a2) { return a1.compare(a2) == 0u; }
+inline bool operator!=(const ActionData &a1, const ActionData &a2) { return a1.compare(a2) != 0u; }
+
+class NewActionDialog: public QDialog
+{
+ Q_OBJECT
+public:
+ explicit NewActionDialog(ActionEditor *parent);
+ virtual ~NewActionDialog();
+
+ ActionData actionData() const;
+ void setActionData(const ActionData &d);
+
+ QString actionText() const;
+ QString actionName() const;
+
+private slots:
+ void on_editActionText_textEdited(const QString &text);
+ void on_editObjectName_textEdited(const QString &text);
+ void slotEditToolTip();
+ void slotResetKeySequence();
+
+private:
+ Ui::NewActionDialog *m_ui;
+ ActionEditor *m_actionEditor;
+ bool m_auto_update_object_name;
+
+ void updateButtons();
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // NEWACTIONDIALOG_P_H
diff --git a/tools/designer/src/lib/shared/newformwidget.cpp b/tools/designer/src/lib/shared/newformwidget.cpp
new file mode 100644
index 0000000..d79d77a
--- /dev/null
+++ b/tools/designer/src/lib/shared/newformwidget.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** 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 "newformwidget_p.h"
+#include "ui_newformwidget.h"
+#include "qdesigner_formbuilder_p.h"
+#include "sheet_delegate_p.h"
+#include "widgetdatabase_p.h"
+#include "shared_settings_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QByteArray>
+#include <QtCore/QBuffer>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+
+#include <QtGui/QHeaderView>
+#include <QtGui/QTreeWidgetItem>
+#include <QtGui/QPainter>
+#include <QtGui/QPushButton>
+
+QT_BEGIN_NAMESPACE
+
+enum { profileComboIndexOffset = 1 };
+enum { debugNewFormWidget = 0 };
+
+enum NewForm_CustomRole {
+ // File name (templates from resources, paths)
+ TemplateNameRole = Qt::UserRole + 100,
+ // Class name (widgets from Widget data base)
+ ClassNameRole = Qt::UserRole + 101
+};
+
+static const char *newFormObjectNameC = "Form";
+
+// Create a form name for an arbitrary class. If it is Qt, qtify it,
+// else return "Form".
+static QString formName(const QString &className)
+{
+ if (!className.startsWith(QLatin1Char('Q')))
+ return QLatin1String(newFormObjectNameC);
+ QString rc = className;
+ rc.remove(0, 1);
+ return rc;
+}
+
+namespace qdesigner_internal {
+
+struct TemplateSize {
+ const char *name;
+ int width;
+ int height;
+};
+
+static const struct TemplateSize templateSizes[] =
+{
+ { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "Default size"), 0, 0 },
+ { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "QVGA portrait (240x320)"), 240, 320 },
+ { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "QVGA landscape (320x240)"), 320, 240 },
+ { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "VGA portrait (480x640)"), 480, 640 },
+ { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "VGA landscape (640x480)"), 640, 480 }
+};
+
+/* -------------- NewForm dialog.
+ * Designer takes new form templates from:
+ * 1) Files located in directories specified in resources
+ * 2) Files located in directories specified as user templates
+ * 3) XML from container widgets deemed usable for form templates by the widget
+ * database
+ * 4) XML from custom container widgets deemed usable for form templates by the
+ * widget database
+ *
+ * The widget database provides helper functions to obtain lists of names
+ * and xml for 3,4.
+ *
+ * Fixed-size forms for embedded platforms are obtained as follows:
+ * 1) If the origin is a file:
+ * - Check if the file exists in the subdirectory "/<width>x<height>/" of
+ * the path (currently the case for the dialog box because the button box
+ * needs to be positioned)
+ * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine.
+ * 2) If the origin is XML:
+ * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine.
+ *
+ * The tree widget item roles indicate which type of entry it is
+ * (TemplateNameRole = file name 1,2, ClassNameRole = class name 3,4)
+ */
+
+NewFormWidget::NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parentWidget) :
+ QDesignerNewFormWidgetInterface(parentWidget),
+ m_core(core),
+ m_ui(new Ui::NewFormWidget),
+ m_currentItem(0),
+ m_acceptedItem(0)
+{
+ typedef QList<qdesigner_internal::DeviceProfile> DeviceProfileList;
+
+ m_ui->setupUi(this);
+ m_ui->treeWidget->setItemDelegate(new qdesigner_internal::SheetDelegate(m_ui->treeWidget, this));
+ m_ui->treeWidget->header()->hide();
+ m_ui->treeWidget->header()->setStretchLastSection(true);
+ m_ui->lblPreview->setBackgroundRole(QPalette::Base);
+ QDesignerSharedSettings settings(m_core);
+
+ QString uiExtension = QLatin1String("ui");
+ QString templatePath = QLatin1String(":/trolltech/designer/templates/forms");
+
+ QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core);
+ if (lang) {
+ templatePath = QLatin1String(":/templates/forms");
+ uiExtension = lang->uiExtension();
+ }
+
+ // Resource templates
+ const QString formTemplate = settings.formTemplate();
+ QTreeWidgetItem *selectedItem = 0;
+ loadFrom(templatePath, true, uiExtension, formTemplate, selectedItem);
+ // Additional template paths
+ const QStringList formTemplatePaths = settings.formTemplatePaths();
+ const QStringList::const_iterator ftcend = formTemplatePaths.constEnd();
+ for (QStringList::const_iterator it = formTemplatePaths.constBegin(); it != ftcend; ++it)
+ loadFrom(*it, false, uiExtension, formTemplate, selectedItem);
+
+ // Widgets/custom widgets
+ if (!lang) {
+ //: New Form Dialog Categories
+ loadFrom(tr("Widgets"), qdesigner_internal::WidgetDataBase::formWidgetClasses(core), formTemplate, selectedItem);
+ loadFrom(tr("Custom Widgets"), qdesigner_internal::WidgetDataBase::customFormWidgetClasses(core), formTemplate, selectedItem);
+ }
+
+ // Still no selection - default to first item
+ if (selectedItem == 0 && m_ui->treeWidget->topLevelItemCount() != 0) {
+ QTreeWidgetItem *firstTopLevel = m_ui->treeWidget->topLevelItem(0);
+ if (firstTopLevel->childCount() > 0)
+ selectedItem = firstTopLevel->child(0);
+ }
+
+ // Open parent, select and make visible
+ if (selectedItem) {
+ m_ui->treeWidget->setCurrentItem(selectedItem);
+ m_ui->treeWidget->setItemSelected(selectedItem, true);
+ m_ui->treeWidget->scrollToItem(selectedItem->parent());
+ }
+ // Fill profile combo
+ m_deviceProfiles = settings.deviceProfiles();
+ m_ui->profileComboBox->addItem(tr("None"));
+ connect(m_ui->profileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDeviceProfileIndexChanged(int)));
+ if (m_deviceProfiles.empty()) {
+ m_ui->profileComboBox->setEnabled(false);
+ } else {
+ const DeviceProfileList::const_iterator dcend = m_deviceProfiles.constEnd();
+ for (DeviceProfileList::const_iterator it = m_deviceProfiles.constBegin(); it != dcend; ++it)
+ m_ui->profileComboBox->addItem(it->name());
+ const int ci = settings.currentDeviceProfileIndex();
+ if (ci >= 0)
+ m_ui->profileComboBox->setCurrentIndex(ci + profileComboIndexOffset);
+ }
+ // Fill size combo
+ const int sizeCount = sizeof(templateSizes)/ sizeof(TemplateSize);
+ for (int i = 0; i < sizeCount; i++) {
+ const QSize size = QSize(templateSizes[i].width, templateSizes[i].height);
+ m_ui->sizeComboBox->addItem(tr(templateSizes[i].name), size);
+ }
+
+ setTemplateSize(settings.newFormSize());
+
+ if (debugNewFormWidget)
+ qDebug() << Q_FUNC_INFO << "Leaving";
+}
+
+NewFormWidget::~NewFormWidget()
+{
+ QDesignerSharedSettings settings (m_core);
+ settings.setNewFormSize(templateSize());
+ // Do not change previously stored item if dialog was rejected
+ if (m_acceptedItem)
+ settings.setFormTemplate(m_acceptedItem->text(0));
+ delete m_ui;
+}
+
+void NewFormWidget::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
+{
+ if (debugNewFormWidget)
+ qDebug() << Q_FUNC_INFO << current;
+ if (!current)
+ return;
+
+ if (!current->parent()) { // Top level item: Ensure expanded when browsing down
+ return;
+ }
+
+ m_currentItem = current;
+
+ emit currentTemplateChanged(showCurrentItemPixmap());
+}
+
+bool NewFormWidget::showCurrentItemPixmap()
+{
+ bool rc = false;
+ if (m_currentItem) {
+ const QPixmap pixmap = formPreviewPixmap(m_currentItem);
+ if (pixmap.isNull()) {
+ m_ui->lblPreview->setText(tr("Error loading form"));
+ } else {
+ m_ui->lblPreview->setPixmap(pixmap);
+ rc = true;
+ }
+ }
+ return rc;
+}
+
+void NewFormWidget::on_treeWidget_itemActivated(QTreeWidgetItem *item)
+{
+ if (debugNewFormWidget)
+ qDebug() << Q_FUNC_INFO << item;
+
+ if (item->data(0, TemplateNameRole).isValid() || item->data(0, ClassNameRole).isValid())
+ emit templateActivated();
+}
+
+QPixmap NewFormWidget::formPreviewPixmap(const QTreeWidgetItem *item)
+{
+ // Cache pixmaps per item/device profile
+ const ItemPixmapCacheKey cacheKey(item, profileComboIndex());
+ ItemPixmapCache::iterator it = m_itemPixmapCache.find(cacheKey);
+ if (it == m_itemPixmapCache.end()) {
+ // file or string?
+ const QVariant fileName = item->data(0, TemplateNameRole);
+ QPixmap rc;
+ if (fileName.type() == QVariant::String) {
+ rc = formPreviewPixmap(fileName.toString());
+ } else {
+ const QVariant classNameV = item->data(0, ClassNameRole);
+ Q_ASSERT(classNameV.type() == QVariant::String);
+ const QString className = classNameV.toString();
+ QByteArray data = qdesigner_internal::WidgetDataBase::formTemplate(m_core, className, formName(className)).toUtf8();
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ rc = formPreviewPixmap(buffer);
+ }
+ if (rc.isNull()) // Retry invalid ones
+ return rc;
+ it = m_itemPixmapCache.insert(cacheKey, rc);
+ }
+ return it.value();
+}
+
+QPixmap NewFormWidget::formPreviewPixmap(const QString &fileName) const
+{
+ QFile f(fileName);
+ if (f.open(QFile::ReadOnly)) {
+ QFileInfo fi(fileName);
+ const QPixmap rc = formPreviewPixmap(f, fi.absolutePath());
+ f.close();
+ return rc;
+ }
+ qWarning() << "The file " << fileName << " could not be opened: " << f.errorString();
+ return QPixmap();
+}
+
+QImage NewFormWidget::grabForm(QDesignerFormEditorInterface *core,
+ QIODevice &file,
+ const QString &workingDir,
+ const qdesigner_internal::DeviceProfile &dp)
+{
+ qdesigner_internal::QDesignerFormBuilder formBuilder(core,
+ qdesigner_internal::QDesignerFormBuilder::DisableScripts,
+ dp);
+ if (!workingDir.isEmpty())
+ formBuilder.setWorkingDirectory(workingDir);
+
+ QWidget *widget = formBuilder.load(&file, 0);
+ if (!widget)
+ return QImage();
+
+ const QPixmap pixmap = QPixmap::grabWidget(widget);
+ widget->deleteLater();
+ return pixmap.toImage();
+}
+
+QPixmap NewFormWidget::formPreviewPixmap(QIODevice &file, const QString &workingDir) const
+{
+ const int margin = 7;
+ const int shadow = 7;
+ const int previewSize = 256;
+
+ const QImage wimage = grabForm(m_core, file, workingDir, currentDeviceProfile());
+ if (wimage.isNull())
+ return QPixmap();
+ const QImage image = wimage.scaled(previewSize - margin * 2, previewSize - margin * 2,
+ Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
+
+ QImage dest(previewSize, previewSize, QImage::Format_ARGB32_Premultiplied);
+ dest.fill(0);
+
+ QPainter p(&dest);
+ p.drawImage(margin, margin, image);
+
+ p.setPen(QPen(palette().brush(QPalette::WindowText), 0));
+
+ p.drawRect(margin-1, margin-1, image.width() + 1, image.height() + 1);
+
+ const QColor dark(Qt::darkGray);
+ const QColor light(Qt::transparent);
+
+ // right shadow
+ {
+ const QRect rect(margin + image.width() + 1, margin + shadow, shadow, image.height() - shadow + 1);
+ QLinearGradient lg(rect.topLeft(), rect.topRight());
+ lg.setColorAt(0, dark);
+ lg.setColorAt(1, light);
+ p.fillRect(rect, lg);
+ }
+
+ // bottom shadow
+ {
+ const QRect rect(margin + shadow, margin + image.height() + 1, image.width() - shadow + 1, shadow);
+ QLinearGradient lg(rect.topLeft(), rect.bottomLeft());
+ lg.setColorAt(0, dark);
+ lg.setColorAt(1, light);
+ p.fillRect(rect, lg);
+ }
+
+ // bottom/right corner shadow
+ {
+ const QRect rect(margin + image.width() + 1, margin + image.height() + 1, shadow, shadow);
+ QRadialGradient g(rect.topLeft(), shadow);
+ g.setColorAt(0, dark);
+ g.setColorAt(1, light);
+ p.fillRect(rect, g);
+ }
+
+ // top/right corner
+ {
+ const QRect rect(margin + image.width() + 1, margin, shadow, shadow);
+ QRadialGradient g(rect.bottomLeft(), shadow);
+ g.setColorAt(0, dark);
+ g.setColorAt(1, light);
+ p.fillRect(rect, g);
+ }
+
+ // bottom/left corner
+ {
+ const QRect rect(margin, margin + image.height() + 1, shadow, shadow);
+ QRadialGradient g(rect.topRight(), shadow);
+ g.setColorAt(0, dark);
+ g.setColorAt(1, light);
+ p.fillRect(rect, g);
+ }
+
+ p.end();
+
+ return QPixmap::fromImage(dest);
+}
+
+void NewFormWidget::loadFrom(const QString &path, bool resourceFile, const QString &uiExtension,
+ const QString &selectedItem, QTreeWidgetItem *&selectedItemFound)
+{
+ const QDir dir(path);
+
+ if (!dir.exists())
+ return;
+
+ // Iterate through the directory and add the templates
+ const QFileInfoList list = dir.entryInfoList(QStringList(QLatin1String("*.") + uiExtension),
+ QDir::Files);
+
+ if (list.isEmpty())
+ return;
+
+ const QChar separator = resourceFile ? QChar(QLatin1Char('/'))
+ : QDir::separator();
+ QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget);
+ root->setFlags(root->flags() & ~Qt::ItemIsSelectable);
+ // Try to get something that is easy to read.
+ QString visiblePath = path;
+ int index = visiblePath.lastIndexOf(separator);
+ if (index != -1) {
+ // try to find a second slash, just to be a bit better.
+ const int index2 = visiblePath.lastIndexOf(separator, index - 1);
+ if (index2 != -1)
+ index = index2;
+ visiblePath = visiblePath.mid(index + 1);
+ visiblePath = QDir::toNativeSeparators(visiblePath);
+ }
+
+ const QChar underscore = QLatin1Char('_');
+ const QChar blank = QLatin1Char(' ');
+ root->setText(0, visiblePath.replace(underscore, blank));
+ root->setToolTip(0, path);
+
+ const QFileInfoList::const_iterator lcend = list.constEnd();
+ for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it) {
+ if (!it->isFile())
+ continue;
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(root);
+ const QString text = it->baseName().replace(underscore, blank);
+ if (selectedItemFound == 0 && text == selectedItem)
+ selectedItemFound = item;
+ item->setText(0, text);
+ item->setData(0, TemplateNameRole, it->absoluteFilePath());
+ }
+}
+
+void NewFormWidget::loadFrom(const QString &title, const QStringList &nameList,
+ const QString &selectedItem, QTreeWidgetItem *&selectedItemFound)
+{
+ if (nameList.empty())
+ return;
+ QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget);
+ root->setFlags(root->flags() & ~Qt::ItemIsSelectable);
+ root->setText(0, title);
+ const QStringList::const_iterator cend = nameList.constEnd();
+ for (QStringList::const_iterator it = nameList.constBegin(); it != cend; ++it) {
+ const QString text = *it;
+ QTreeWidgetItem *item = new QTreeWidgetItem(root);
+ item->setText(0, text);
+ if (selectedItemFound == 0 && text == selectedItem)
+ selectedItemFound = item;
+ item->setData(0, ClassNameRole, *it);
+ }
+}
+
+void NewFormWidget::on_treeWidget_itemPressed(QTreeWidgetItem *item)
+{
+ if (item && !item->parent())
+ m_ui->treeWidget->setItemExpanded(item, !m_ui->treeWidget->isItemExpanded(item));
+}
+
+QSize NewFormWidget::templateSize() const
+{
+ return m_ui->sizeComboBox->itemData(m_ui->sizeComboBox->currentIndex()).toSize();
+}
+
+void NewFormWidget::setTemplateSize(const QSize &s)
+{
+ const int index = s.isNull() ? 0 : m_ui->sizeComboBox->findData(s);
+ if (index != -1)
+ m_ui->sizeComboBox->setCurrentIndex(index);
+}
+
+static QString readAll(const QString &fileName, QString *errorMessage)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ *errorMessage = NewFormWidget::tr("Unable to open the form template file '%1': %2").arg(fileName, file.errorString());
+ return QString();
+ }
+ return QString::fromUtf8(file.readAll());
+}
+
+QString NewFormWidget::itemToTemplate(const QTreeWidgetItem *item, QString *errorMessage) const
+{
+ const QSize size = templateSize();
+ // file name or string contents?
+ const QVariant templateFileName = item->data(0, TemplateNameRole);
+ if (templateFileName.type() == QVariant::String) {
+ const QString fileName = templateFileName.toString();
+ // No fixed size: just open.
+ if (size.isNull())
+ return readAll(fileName, errorMessage);
+ // try to find a file matching the size, like "../640x480/xx.ui"
+ const QFileInfo fiBase(fileName);
+ QString sizeFileName;
+ QTextStream(&sizeFileName) << fiBase.path() << QDir::separator()
+ << size.width() << QLatin1Char('x') << size.height() << QDir::separator()
+ << fiBase.fileName();
+ if (QFileInfo(sizeFileName).isFile())
+ return readAll(sizeFileName, errorMessage);
+ // Nothing found, scale via DOM/temporary file
+ QString contents = readAll(fileName, errorMessage);
+ if (!contents.isEmpty())
+ contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(contents, size, false);
+ return contents;
+ }
+ // Content.
+ const QString className = item->data(0, ClassNameRole).toString();
+ QString contents = qdesigner_internal::WidgetDataBase::formTemplate(m_core, className, formName(className));
+ if (!size.isNull())
+ contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(contents, size, false);
+ return contents;
+}
+
+void NewFormWidget::slotDeviceProfileIndexChanged(int idx)
+{
+ // Store index for form windows to take effect and refresh pixmap
+ QDesignerSharedSettings settings(m_core);
+ settings.setCurrentDeviceProfileIndex(idx - profileComboIndexOffset);
+ showCurrentItemPixmap();
+}
+
+int NewFormWidget::profileComboIndex() const
+{
+ return m_ui->profileComboBox->currentIndex();
+}
+
+qdesigner_internal::DeviceProfile NewFormWidget::currentDeviceProfile() const
+{
+ const int ci = profileComboIndex();
+ if (ci > 0)
+ return m_deviceProfiles.at(ci - profileComboIndexOffset);
+ return qdesigner_internal::DeviceProfile();
+}
+
+bool NewFormWidget::hasCurrentTemplate() const
+{
+ return m_currentItem != 0;
+}
+
+QString NewFormWidget::currentTemplateI(QString *ptrToErrorMessage)
+{
+ if (m_currentItem == 0) {
+ *ptrToErrorMessage = tr("Internal error: No template selected.");
+ return QString();
+ }
+ const QString contents = itemToTemplate(m_currentItem, ptrToErrorMessage);
+ if (contents.isEmpty())
+ return contents;
+
+ m_acceptedItem = m_currentItem;
+ return contents;
+}
+
+QString NewFormWidget::currentTemplate(QString *ptrToErrorMessage)
+{
+ if (ptrToErrorMessage)
+ return currentTemplateI(ptrToErrorMessage);
+ // Do not loose the error
+ QString errorMessage;
+ const QString contents = currentTemplateI(&errorMessage);
+ if (!errorMessage.isEmpty())
+ qWarning("%s", errorMessage.toUtf8().constData());
+ return contents;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/newformwidget.ui b/tools/designer/src/lib/shared/newformwidget.ui
new file mode 100644
index 0000000..c062602
--- /dev/null
+++ b/tools/designer/src/lib/shared/newformwidget.ui
@@ -0,0 +1,192 @@
+<?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>qdesigner_internal::NewFormWidget</class>
+ <widget class="QWidget" name="qdesigner_internal::NewFormWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>480</width>
+ <height>194</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>128</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="columnCount">
+ <number>1</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>0</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="lblPreview">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="text">
+ <string>Choose a template for a preview</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>7</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="embeddedGroup">
+ <property name="title">
+ <string>Embedded Design</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QComboBox" name="profileComboBox"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="sizeComboBox"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Device:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Screen Size:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <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>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/newformwidget_p.h b/tools/designer/src/lib/shared/newformwidget_p.h
new file mode 100644
index 0000000..f94f952
--- /dev/null
+++ b/tools/designer/src/lib/shared/newformwidget_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef NEWFORMWIDGET_H
+#define NEWFORMWIDGET_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 "shared_global_p.h"
+#include "deviceprofile_p.h"
+
+#include <abstractnewformwidget_p.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QPixmap>
+
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+class QTreeWidgetItem;
+
+namespace qdesigner_internal {
+
+namespace Ui {
+ class NewFormWidget;
+}
+
+class QDesignerWorkbench;
+
+class QDESIGNER_SHARED_EXPORT NewFormWidget : public QDesignerNewFormWidgetInterface
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(NewFormWidget)
+
+public:
+ typedef QList<qdesigner_internal::DeviceProfile> DeviceProfileList;
+
+ explicit NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parentWidget);
+ virtual ~NewFormWidget();
+
+ virtual bool hasCurrentTemplate() const;
+ virtual QString currentTemplate(QString *errorMessage = 0);
+
+ // Convenience for implementing file dialogs with preview
+ static QImage grabForm(QDesignerFormEditorInterface *core,
+ QIODevice &file,
+ const QString &workingDir,
+ const qdesigner_internal::DeviceProfile &dp);
+
+private slots:
+ void on_treeWidget_itemActivated(QTreeWidgetItem *item);
+ void on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *);
+ void on_treeWidget_itemPressed(QTreeWidgetItem *item);
+ void slotDeviceProfileIndexChanged(int idx);
+
+private:
+ QPixmap formPreviewPixmap(const QString &fileName) const;
+ QPixmap formPreviewPixmap(QIODevice &file, const QString &workingDir = QString()) const;
+ QPixmap formPreviewPixmap(const QTreeWidgetItem *item);
+
+ void loadFrom(const QString &path, bool resourceFile, const QString &uiExtension,
+ const QString &selectedItem, QTreeWidgetItem *&selectedItemFound);
+ void loadFrom(const QString &title, const QStringList &nameList,
+ const QString &selectedItem, QTreeWidgetItem *&selectedItemFound);
+
+private:
+ QString itemToTemplate(const QTreeWidgetItem *item, QString *errorMessage) const;
+ QString currentTemplateI(QString *ptrToErrorMessage);
+
+ QSize templateSize() const;
+ void setTemplateSize(const QSize &s);
+ int profileComboIndex() const;
+ qdesigner_internal::DeviceProfile currentDeviceProfile() const;
+ bool showCurrentItemPixmap();
+
+ // Pixmap cache (item, profile combo index)
+ typedef QPair<const QTreeWidgetItem *, int> ItemPixmapCacheKey;
+ typedef QMap<ItemPixmapCacheKey, QPixmap> ItemPixmapCache;
+ ItemPixmapCache m_itemPixmapCache;
+
+ QDesignerFormEditorInterface *m_core;
+ Ui::NewFormWidget *m_ui;
+ QTreeWidgetItem *m_currentItem;
+ QTreeWidgetItem *m_acceptedItem;
+ DeviceProfileList m_deviceProfiles;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // NEWFORMWIDGET_H
diff --git a/tools/designer/src/lib/shared/orderdialog.cpp b/tools/designer/src/lib/shared/orderdialog.cpp
new file mode 100644
index 0000000..3f14ca6
--- /dev/null
+++ b/tools/designer/src/lib/shared/orderdialog.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** 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::OrderDialog
+*/
+
+#include "orderdialog_p.h"
+#include "iconloader_p.h"
+#include "ui_orderdialog.h"
+
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QModelIndex>
+#include <QtGui/QPushButton>
+
+QT_BEGIN_NAMESPACE
+
+// OrderDialog: Used to reorder the pages of QStackedWidget and QToolBox.
+// Provides up and down buttons as well as DnD via QAbstractItemView::InternalMove mode
+namespace qdesigner_internal {
+
+OrderDialog::OrderDialog(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::OrderDialog),
+ m_format(PageOrderFormat)
+{
+ m_ui->setupUi(this);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ m_ui->upButton->setIcon(createIconSet(QString::fromUtf8("up.png")));
+ m_ui->downButton->setIcon(createIconSet(QString::fromUtf8("down.png")));
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ connect(m_ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(slotReset()));
+ // Catch the remove operation of a DnD operation in QAbstractItemView::InternalMove mode to enable buttons
+ // Selection mode is 'contiguous' to enable DnD of groups
+ connect(m_ui->pageList->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotEnableButtonsAfterDnD()));
+
+ m_ui->upButton->setEnabled(false);
+ m_ui->downButton->setEnabled(false);
+}
+
+OrderDialog::~OrderDialog()
+{
+ delete m_ui;
+}
+
+void OrderDialog::setDescription(const QString &d)
+{
+ m_ui->groupBox->setTitle(d);
+}
+
+void OrderDialog::setPageList(const QWidgetList &pages)
+{
+ // The QWidget* are stored in a map indexed by the old index.
+ // The old index is set as user data on the item instead of the QWidget*
+ // because DnD is enabled which requires the user data to serializable
+ m_orderMap.clear();
+ const int count = pages.count();
+ for (int i=0; i < count; ++i)
+ m_orderMap.insert(i, pages.at(i));
+ buildList();
+}
+
+void OrderDialog::buildList()
+{
+ m_ui->pageList->clear();
+ const OrderMap::const_iterator cend = m_orderMap.constEnd();
+ for (OrderMap::const_iterator it = m_orderMap.constBegin(); it != cend; ++it) {
+ QListWidgetItem *item = new QListWidgetItem();
+ const int index = it.key();
+ switch (m_format) {
+ case PageOrderFormat:
+ item->setText(tr("Index %1 (%2)").arg(index).arg(it.value()->objectName()));
+ break;
+ case TabOrderFormat:
+ item->setText(tr("%1 %2").arg(index+1).arg(it.value()->objectName()));
+ break;
+ }
+ item->setData(Qt::UserRole, QVariant(index));
+ m_ui->pageList->addItem(item);
+ }
+
+ if (m_ui->pageList->count() > 0)
+ m_ui->pageList->setCurrentRow(0);
+}
+
+void OrderDialog::slotReset()
+{
+ buildList();
+}
+
+QWidgetList OrderDialog::pageList() const
+{
+ QWidgetList rc;
+ const int count = m_ui->pageList->count();
+ for (int i=0; i < count; ++i) {
+ const int oldIndex = m_ui->pageList->item(i)->data(Qt::UserRole).toInt();
+ rc.append(m_orderMap.value(oldIndex));
+ }
+ return rc;
+}
+
+void OrderDialog::on_upButton_clicked()
+{
+ const int row = m_ui->pageList->currentRow();
+ if (row <= 0)
+ return;
+
+ m_ui->pageList->insertItem(row - 1, m_ui->pageList->takeItem(row));
+ m_ui->pageList->setCurrentRow(row - 1);
+}
+
+void OrderDialog::on_downButton_clicked()
+{
+ const int row = m_ui->pageList->currentRow();
+ if (row == -1 || row == m_ui->pageList->count() - 1)
+ return;
+
+ m_ui->pageList->insertItem(row + 1, m_ui->pageList->takeItem(row));
+ m_ui->pageList->setCurrentRow(row + 1);
+}
+
+void OrderDialog::slotEnableButtonsAfterDnD()
+{
+ enableButtons(m_ui->pageList->currentRow());
+}
+
+void OrderDialog::on_pageList_currentRowChanged(int r)
+{
+ enableButtons(r);
+}
+
+void OrderDialog::enableButtons(int r)
+{
+ m_ui->upButton->setEnabled(r > 0);
+ m_ui->downButton->setEnabled(r >= 0 && r < m_ui->pageList->count() - 1);
+}
+
+QWidgetList OrderDialog::pagesOfContainer(const QDesignerFormEditorInterface *core, QWidget *container)
+{
+ QWidgetList rc;
+ if (QDesignerContainerExtension* ce = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), container)) {
+ const int count = ce->count();
+ for (int i = 0; i < count ;i ++)
+ rc.push_back(ce->widget(i));
+ }
+ return rc;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/orderdialog.ui b/tools/designer/src/lib/shared/orderdialog.ui
new file mode 100644
index 0000000..dcecb31
--- /dev/null
+++ b/tools/designer/src/lib/shared/orderdialog.ui
@@ -0,0 +1,198 @@
+<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::OrderDialog</class>
+ <widget class="QDialog" name="qdesigner_internal::OrderDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>467</width>
+ <height>310</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Change Page Order</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Page Order</string>
+ </property>
+ <layout class="QHBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>9</number>
+ </property>
+ <property name="topMargin" >
+ <number>9</number>
+ </property>
+ <property name="rightMargin" >
+ <number>9</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="pageList" >
+ <property name="minimumSize" >
+ <size>
+ <width>344</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="dragDropMode" >
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::ContiguousSelection</enum>
+ </property>
+ <property name="movement" >
+ <enum>QListView::Snap</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="upButton" >
+ <property name="toolTip" >
+ <string>Move page up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="downButton" >
+ <property name="toolTip" >
+ <string>Move page down</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>99</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </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::Reset</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>qdesigner_internal::OrderDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>50</x>
+ <y>163</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>6</x>
+ <y>151</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>qdesigner_internal::OrderDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>300</x>
+ <y>160</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>348</x>
+ <y>148</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/designer/src/lib/shared/orderdialog_p.h b/tools/designer/src/lib/shared/orderdialog_p.h
new file mode 100644
index 0000000..e8897e6
--- /dev/null
+++ b/tools/designer/src/lib/shared/orderdialog_p.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$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+
+#ifndef ORDERDIALOG_P_H
+#define ORDERDIALOG_P_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QDialog>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+namespace Ui {
+ class OrderDialog;
+}
+
+class QDESIGNER_SHARED_EXPORT OrderDialog: public QDialog
+{
+ Q_OBJECT
+public:
+ OrderDialog(QWidget *parent);
+ virtual ~OrderDialog();
+
+ static QWidgetList pagesOfContainer(const QDesignerFormEditorInterface *core, QWidget *container);
+
+ void setPageList(const QWidgetList &pages);
+ QWidgetList pageList() const;
+
+ void setDescription(const QString &d);
+
+ enum Format { // Display format
+ PageOrderFormat, // Container pages, ranging 0..[n-1]
+ TabOrderFormat // List of widgets, ranging 1..1
+ };
+
+ void setFormat(Format f) { m_format = f; }
+ Format format() const { return m_format; }
+
+private slots:
+ void on_upButton_clicked();
+ void on_downButton_clicked();
+ void on_pageList_currentRowChanged(int row);
+ void slotEnableButtonsAfterDnD();
+ void slotReset();
+
+private:
+ void buildList();
+ void enableButtons(int r);
+
+ typedef QMap<int, QWidget*> OrderMap;
+ OrderMap m_orderMap;
+ Ui::OrderDialog* m_ui;
+ Format m_format;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // ORDERDIALOG_P_H
diff --git a/tools/designer/src/lib/shared/plaintexteditor.cpp b/tools/designer/src/lib/shared/plaintexteditor.cpp
new file mode 100644
index 0000000..ce5cd5b
--- /dev/null
+++ b/tools/designer/src/lib/shared/plaintexteditor.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::PlainTextEditorDialog
+*/
+
+#include "plaintexteditor_p.h"
+#include "abstractsettings_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QPushButton>
+
+QT_BEGIN_NAMESPACE
+
+static const char *PlainTextDialogC = "PlainTextDialog";
+static const char *Geometry = "Geometry";
+
+
+namespace qdesigner_internal {
+
+PlainTextEditorDialog::PlainTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
+ QDialog(parent),
+ m_editor(new QPlainTextEdit),
+ m_core(core)
+{
+ setWindowTitle(tr("Edit text"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QVBoxLayout *vlayout = new QVBoxLayout(this);
+ vlayout->addWidget(m_editor);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
+ QPushButton *ok_button = buttonBox->button(QDialogButtonBox::Ok);
+ ok_button->setDefault(true);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ vlayout->addWidget(buttonBox);
+
+ QDesignerSettingsInterface *settings = core->settingsManager();
+ settings->beginGroup(QLatin1String(PlainTextDialogC));
+
+ if (settings->contains(QLatin1String(Geometry)))
+ restoreGeometry(settings->value(QLatin1String(Geometry)).toByteArray());
+
+ settings->endGroup();
+}
+
+PlainTextEditorDialog::~PlainTextEditorDialog()
+{
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->beginGroup(QLatin1String(PlainTextDialogC));
+
+ settings->setValue(QLatin1String(Geometry), saveGeometry());
+ settings->endGroup();
+}
+
+int PlainTextEditorDialog::showDialog()
+{
+ m_editor->setFocus();
+ return exec();
+}
+
+void PlainTextEditorDialog::setDefaultFont(const QFont &font)
+{
+ m_editor->setFont(font);
+}
+
+void PlainTextEditorDialog::setText(const QString &text)
+{
+ m_editor->setPlainText(text);
+}
+
+QString PlainTextEditorDialog::text() const
+{
+ return m_editor->toPlainText();
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/plaintexteditor_p.h b/tools/designer/src/lib/shared/plaintexteditor_p.h
new file mode 100644
index 0000000..d227db8
--- /dev/null
+++ b/tools/designer/src/lib/shared/plaintexteditor_p.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$
+**
+****************************************************************************/
+
+//
+// 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 PLAINTEXTEDITOR_H
+#define PLAINTEXTEDITOR_H
+
+#include <QtGui/QDialog>
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPlainTextEdit;
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT PlainTextEditorDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit PlainTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+ ~PlainTextEditorDialog();
+
+ int showDialog();
+
+ void setDefaultFont(const QFont &font);
+
+ void setText(const QString &text);
+ QString text() const;
+
+private:
+ QPlainTextEdit *m_editor;
+ QDesignerFormEditorInterface *m_core;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // RITCHTEXTEDITOR_H
diff --git a/tools/designer/src/lib/shared/plugindialog.cpp b/tools/designer/src/lib/shared/plugindialog.cpp
new file mode 100644
index 0000000..447f1e2
--- /dev/null
+++ b/tools/designer/src/lib/shared/plugindialog.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 "plugindialog_p.h"
+#include "pluginmanager_p.h"
+#include "qdesigner_integration_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerCustomWidgetCollectionInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtGui/QStyle>
+#include <QtGui/QHeaderView>
+#include <QtGui/QPushButton>
+#include <QtCore/QFileInfo>
+#include <QtCore/QPluginLoader>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+PluginDialog::PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent)
+ : QDialog(parent
+#ifdef Q_WS_MAC
+ , Qt::Tool
+#endif
+ ), m_core(core)
+{
+ ui.setupUi(this);
+
+ ui.message->hide();
+
+ const QStringList headerLabels(tr("Components"));
+
+ ui.treeWidget->setAlternatingRowColors(false);
+ ui.treeWidget->setSelectionMode(QAbstractItemView::NoSelection);
+ ui.treeWidget->setHeaderLabels(headerLabels);
+ ui.treeWidget->header()->hide();
+
+ interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
+ QIcon::Normal, QIcon::On);
+ interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
+ QIcon::Normal, QIcon::Off);
+ featureIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
+
+ setWindowTitle(tr("Plugin Information"));
+ populateTreeWidget();
+
+ if (qobject_cast<qdesigner_internal::QDesignerIntegration *>(m_core->integration())) {
+ QPushButton *updateButton = new QPushButton(tr("Refresh"));
+ const QString tooltip = tr("Scan for newly installed custom widget plugins.");
+ updateButton->setToolTip(tooltip);
+ updateButton->setWhatsThis(tooltip);
+ connect(updateButton, SIGNAL(clicked()), this, SLOT(updateCustomWidgetPlugins()));
+ ui.buttonBox->addButton(updateButton, QDialogButtonBox::ActionRole);
+ }
+}
+
+void PluginDialog::populateTreeWidget()
+{
+ ui.treeWidget->clear();
+ QDesignerPluginManager *pluginManager = m_core->pluginManager();
+ const QStringList fileNames = pluginManager->registeredPlugins();
+
+ if (!fileNames.isEmpty()) {
+ QTreeWidgetItem *topLevelItem = setTopLevelItem(QLatin1String("Loaded Plugins"));
+ QFont boldFont = topLevelItem->font(0);
+
+ foreach (QString fileName, fileNames) {
+ QPluginLoader loader(fileName);
+ const QFileInfo fileInfo(fileName);
+
+ QTreeWidgetItem *pluginItem = setPluginItem(topLevelItem, fileInfo.fileName(), boldFont);
+
+ if (QObject *plugin = loader.instance()) {
+ if (const QDesignerCustomWidgetCollectionInterface *c = qobject_cast<QDesignerCustomWidgetCollectionInterface*>(plugin)) {
+ foreach (const QDesignerCustomWidgetInterface *p, c->customWidgets())
+ setItem(pluginItem, p->name(), p->toolTip(), p->whatsThis(), p->icon());
+ } else {
+ if (const QDesignerCustomWidgetInterface *p = qobject_cast<QDesignerCustomWidgetInterface*>(plugin))
+ setItem(pluginItem, p->name(), p->toolTip(), p->whatsThis(), p->icon());
+ }
+ }
+ }
+ }
+
+ const QStringList notLoadedPlugins = pluginManager->failedPlugins();
+ if (!notLoadedPlugins.isEmpty()) {
+ QTreeWidgetItem *topLevelItem = setTopLevelItem(QLatin1String("Failed Plugins"));
+ const QFont boldFont = topLevelItem->font(0);
+ foreach (const QString plugin, notLoadedPlugins) {
+ const QString failureReason = pluginManager->failureReason(plugin);
+ QTreeWidgetItem *pluginItem = setPluginItem(topLevelItem, plugin, boldFont);
+ setItem(pluginItem, failureReason, failureReason, QString(), QIcon());
+ }
+ }
+
+ if (ui.treeWidget->topLevelItemCount() == 0) {
+ ui.label->setText(tr("Qt Designer couldn't find any plugins"));
+ ui.treeWidget->hide();
+ } else {
+ ui.label->setText(tr("Qt Designer found the following plugins"));
+ }
+}
+
+QIcon PluginDialog::pluginIcon(const QIcon &icon)
+{
+ if (icon.isNull())
+ return QIcon(QLatin1String(":/trolltech/formeditor/images/qtlogo.png"));
+
+ return icon;
+}
+
+QTreeWidgetItem* PluginDialog::setTopLevelItem(const QString &itemName)
+{
+ QTreeWidgetItem *topLevelItem = new QTreeWidgetItem(ui.treeWidget);
+ topLevelItem->setText(0, itemName);
+ ui.treeWidget->setItemExpanded(topLevelItem, true);
+ topLevelItem->setIcon(0, style()->standardPixmap(QStyle::SP_DirOpenIcon));
+
+ QFont boldFont = topLevelItem->font(0);
+ boldFont.setBold(true);
+ topLevelItem->setFont(0, boldFont);
+
+ return topLevelItem;
+}
+
+QTreeWidgetItem* PluginDialog::setPluginItem(QTreeWidgetItem *topLevelItem,
+ const QString &itemName, const QFont &font)
+{
+ QTreeWidgetItem *pluginItem = new QTreeWidgetItem(topLevelItem);
+ pluginItem->setFont(0, font);
+ pluginItem->setText(0, itemName);
+ ui.treeWidget->setItemExpanded(pluginItem, true);
+ pluginItem->setIcon(0, style()->standardPixmap(QStyle::SP_DirOpenIcon));
+
+ return pluginItem;
+}
+
+void PluginDialog::setItem(QTreeWidgetItem *pluginItem, const QString &name,
+ const QString &toolTip, const QString &whatsThis, const QIcon &icon)
+{
+ QTreeWidgetItem *item = new QTreeWidgetItem(pluginItem);
+ item->setText(0, name);
+ item->setToolTip(0, toolTip);
+ item->setWhatsThis(0, whatsThis);
+ item->setIcon(0, pluginIcon(icon));
+}
+
+void PluginDialog::updateCustomWidgetPlugins()
+{
+ if (qdesigner_internal::QDesignerIntegration *integration = qobject_cast<qdesigner_internal::QDesignerIntegration *>(m_core->integration())) {
+ const int before = m_core->widgetDataBase()->count();
+ integration->updateCustomWidgetPlugins();
+ const int after = m_core->widgetDataBase()->count();
+ if (after > before) {
+ ui.message->setText(tr("New custom widget plugins have been found."));
+ ui.message->show();
+ } else {
+ ui.message->setText(QString());
+ }
+ populateTreeWidget();
+ }
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/plugindialog.ui b/tools/designer/src/lib/shared/plugindialog.ui
new file mode 100644
index 0000000..b12a42d
--- /dev/null
+++ b/tools/designer/src/lib/shared/plugindialog.ui
@@ -0,0 +1,136 @@
+<?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>PluginDialog</class>
+ <widget class="QDialog" name="PluginDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>401</width>
+ <height>331</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Plugin Information</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>8</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <property name="textElideMode">
+ <enum>Qt::ElideNone</enum>
+ </property>
+ <column>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="message">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PluginDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>154</x>
+ <y>307</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>401</x>
+ <y>280</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/designer/src/lib/shared/plugindialog_p.h b/tools/designer/src/lib/shared/plugindialog_p.h
new file mode 100644
index 0000000..d50a804
--- /dev/null
+++ b/tools/designer/src/lib/shared/plugindialog_p.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 PLUGINDIALOG_H
+#define PLUGINDIALOG_H
+
+#include "ui_plugindialog.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+class PluginDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+
+private slots:
+ void updateCustomWidgetPlugins();
+
+private:
+ void populateTreeWidget();
+ QIcon pluginIcon(const QIcon &icon);
+ QTreeWidgetItem* setTopLevelItem(const QString &itemName);
+ QTreeWidgetItem* setPluginItem(QTreeWidgetItem *topLevelItem,
+ const QString &itemName, const QFont &font);
+ void setItem(QTreeWidgetItem *pluginItem, const QString &name,
+ const QString &toolTip, const QString &whatsThis, const QIcon &icon);
+
+ QDesignerFormEditorInterface *m_core;
+ Ui::PluginDialog ui;
+ QIcon interfaceIcon;
+ QIcon featureIcon;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/pluginmanager.cpp b/tools/designer/src/lib/shared/pluginmanager.cpp
new file mode 100644
index 0000000..9dc8c7b
--- /dev/null
+++ b/tools/designer/src/lib/shared/pluginmanager.cpp
@@ -0,0 +1,670 @@
+/****************************************************************************
+**
+** 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 "pluginmanager_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_qsettings_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerCustomWidgetInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerLanguageExtension>
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSet>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QLibrary>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/qdebug.h>
+#include <QtCore/QMap>
+#include <QtCore/QSettings>
+#include <QtCore/QCoreApplication>
+
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamAttribute>
+
+static const char *uiElementC = "ui";
+static const char *languageAttributeC = "language";
+static const char *widgetElementC = "widget";
+static const char *displayNameAttributeC = "displayname";
+static const char *classAttributeC = "class";
+static const char *customwidgetElementC = "customwidget";
+static const char *extendsElementC = "extends";
+static const char *addPageMethodC = "addpagemethod";
+static const char *jambiLanguageC = "jambi";
+
+enum { debugPluginManager = 0 };
+
+/* Custom widgets: Loading custom widgets is a 2-step process: PluginManager
+ * scans for its plugins in the constructor. At this point, it might not be safe
+ * to immediately initialize the custom widgets it finds, because the rest of
+ * Designer is not initialized yet.
+ * Later on, in ensureInitialized(), the plugin instances (including static ones)
+ * are iterated and the custom widget plugins are initialized and added to internal
+ * list of custom widgets and parsed data. Should there be a parse error or a language
+ * mismatch, it kicks out the respective custom widget. The m_initialized flag
+ * is used to indicate the state.
+ * Later, someone might call registerNewPlugins(), which agains clears the flag via
+ * registerPlugin() and triggers the process again.
+ * Also note that Jambi fakes a custom widget collection that changes its contents
+ * every time the project is switched. So, custom widget plugins can actually
+ * disappear, and the custom widget list must be cleared and refilled in
+ * ensureInitialized() after registerNewPlugins. */
+
+QT_BEGIN_NAMESPACE
+
+static QStringList unique(const QStringList &lst)
+{
+ const QSet<QString> s = QSet<QString>::fromList(lst);
+ return s.toList();
+}
+
+QStringList QDesignerPluginManager::defaultPluginPaths()
+{
+ QStringList result;
+
+ const QStringList path_list = QCoreApplication::libraryPaths();
+
+ const QString designer = QLatin1String("designer");
+ foreach (const QString &path, path_list) {
+ QString libPath = path;
+ libPath += QDir::separator();
+ libPath += designer;
+ result.append(libPath);
+ }
+
+ QString homeLibPath = QDir::homePath();
+ homeLibPath += QDir::separator();
+ homeLibPath += QLatin1String(".designer");
+ homeLibPath += QDir::separator();
+ homeLibPath += QLatin1String("plugins");
+
+ result.append(homeLibPath);
+ return result;
+}
+
+// Figure out the language designer is running. ToDo: Introduce some
+// Language name API to QDesignerLanguageExtension?
+
+static inline QString getDesignerLanguage(QDesignerFormEditorInterface *core)
+{
+ if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core)) {
+ if (lang->uiExtension() == QLatin1String("jui"))
+ return QLatin1String(jambiLanguageC);
+ return QLatin1String("unknown");
+ }
+ return QLatin1String("c++");
+}
+
+// ---------------- QDesignerCustomWidgetSharedData
+
+class QDesignerCustomWidgetSharedData : public QSharedData {
+public:
+ explicit QDesignerCustomWidgetSharedData(const QString &thePluginPath) : pluginPath(thePluginPath) {}
+ void clearXML();
+
+ QString pluginPath;
+
+ QString xmlClassName;
+ QString xmlDisplayName;
+ QString xmlLanguage;
+ QString xmlAddPageMethod;
+ QString xmlExtends;
+
+};
+
+void QDesignerCustomWidgetSharedData::clearXML()
+{
+ xmlClassName.clear();
+ xmlDisplayName.clear();
+ xmlLanguage.clear();
+ xmlAddPageMethod.clear();
+ xmlExtends.clear();
+}
+
+// ---------------- QDesignerCustomWidgetData
+
+QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QString &pluginPath) :
+ m_d(new QDesignerCustomWidgetSharedData(pluginPath))
+{
+}
+
+QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QDesignerCustomWidgetData &o) :
+ m_d(o.m_d)
+{
+}
+
+QDesignerCustomWidgetData& QDesignerCustomWidgetData::operator=(const QDesignerCustomWidgetData &o)
+{
+ m_d.operator=(o.m_d);
+ return *this;
+}
+
+QDesignerCustomWidgetData::~QDesignerCustomWidgetData()
+{
+}
+
+bool QDesignerCustomWidgetData::isNull() const
+{
+ return m_d->xmlClassName.isEmpty() || m_d->pluginPath.isEmpty();
+}
+
+QString QDesignerCustomWidgetData::xmlClassName() const
+{
+ return m_d->xmlClassName;
+}
+
+QString QDesignerCustomWidgetData::xmlLanguage() const
+{
+ return m_d->xmlLanguage;
+}
+
+QString QDesignerCustomWidgetData::xmlAddPageMethod() const
+{
+ return m_d->xmlAddPageMethod;
+}
+
+QString QDesignerCustomWidgetData::xmlExtends() const
+{
+ return m_d->xmlExtends;
+}
+
+QString QDesignerCustomWidgetData::xmlDisplayName() const
+{
+ return m_d->xmlDisplayName;
+}
+
+QString QDesignerCustomWidgetData::pluginPath() const
+{
+ return m_d->pluginPath;
+}
+
+// Wind a QXmlStreamReader until it finds an element. Returns index or one of FindResult
+enum FindResult { FindError = -2, ElementNotFound = -1 };
+
+static int findElement(const QStringList &desiredElts, QXmlStreamReader &sr)
+{
+ while (true) {
+ switch(sr.readNext()) {
+ case QXmlStreamReader::EndDocument:
+ return ElementNotFound;
+ case QXmlStreamReader::Invalid:
+ return FindError;
+ case QXmlStreamReader::StartElement: {
+ const int index = desiredElts.indexOf(sr.name().toString().toLower());
+ if (index >= 0)
+ return index;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return FindError;
+}
+
+static inline QString msgXmlError(const QString &name, const QString &errorMessage)
+{
+ return QDesignerPluginManager::tr("An XML error was encountered when parsing the XML of the custom widget %1: %2").arg(name, errorMessage);
+}
+
+QDesignerCustomWidgetData::ParseResult
+ QDesignerCustomWidgetData::parseXml(const QString &xml, const QString &name, QString *errorMessage)
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << name;
+
+ QDesignerCustomWidgetSharedData &data = *m_d;
+ data.clearXML();
+
+ QXmlStreamReader sr(xml);
+
+ bool foundUI = false;
+ bool foundWidget = false;
+ ParseResult rc = ParseOk;
+ // Parse for the (optional) <ui> or the first <widget> element
+ QStringList elements;
+ elements.push_back(QLatin1String(uiElementC));
+ elements.push_back(QLatin1String(widgetElementC));
+ for (int i = 0; i < 2 && !foundWidget; i++) {
+ switch (findElement(elements, sr)) {
+ case FindError:
+ *errorMessage = msgXmlError(name, sr.errorString());
+ return ParseError;
+ case ElementNotFound:
+ *errorMessage = QDesignerPluginManager::tr("The XML of the custom widget %1 does not contain any of the elements <widget> or <ui>.").arg(name);
+ return ParseError;
+ case 0: { // <ui>
+ const QXmlStreamAttributes attributes = sr.attributes();
+ data.xmlLanguage = attributes.value(QLatin1String(languageAttributeC)).toString();
+ data.xmlDisplayName = attributes.value(QLatin1String(displayNameAttributeC)).toString();
+ foundUI = true;
+ }
+ break;
+ case 1: // <widget>: Do some sanity checks
+ data.xmlClassName = sr.attributes().value(QLatin1String(classAttributeC)).toString();
+ if (data.xmlClassName.isEmpty()) {
+ *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 is missing.").arg(name);
+ rc = ParseWarning;
+ } else {
+ if (data.xmlClassName != name) {
+ *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 does not match the class name %2.").arg(data.xmlClassName, name);
+ rc = ParseWarning;
+ }
+ }
+ foundWidget = true;
+ break;
+ }
+ }
+ // Parse out the <customwidget> element which might be present if <ui> was there
+ if (!foundUI)
+ return rc;
+ elements.clear();
+ elements.push_back(QLatin1String(customwidgetElementC));
+ switch (findElement(elements, sr)) {
+ case FindError:
+ *errorMessage = msgXmlError(name, sr.errorString());
+ return ParseError;
+ case ElementNotFound:
+ return rc;
+ default:
+ break;
+ }
+ // Find <extends>, <addPageMethod>
+ elements.clear();
+ elements.push_back(QLatin1String(extendsElementC));
+ elements.push_back(QLatin1String(addPageMethodC));
+ while (true) {
+ switch (findElement(elements, sr)) {
+ case FindError:
+ *errorMessage = msgXmlError(name, sr.errorString());
+ return ParseError;
+ case ElementNotFound:
+ return rc;
+ case 0: // <extends>
+ data.xmlExtends = sr.readElementText();
+ if (sr.tokenType() != QXmlStreamReader::EndElement) {
+ *errorMessage = msgXmlError(name, sr.errorString());
+ return ParseError;
+ }
+ break;
+ case 1: // <addPageMethod>
+ data.xmlAddPageMethod = sr.readElementText();
+ if (sr.tokenType() != QXmlStreamReader::EndElement) {
+ *errorMessage = msgXmlError(name, sr.errorString());
+ return ParseError;
+ }
+ break;
+ }
+ }
+ return rc;
+}
+
+// ---------------- QDesignerPluginManagerPrivate
+
+class QDesignerPluginManagerPrivate {
+ public:
+ QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core);
+
+ void clearCustomWidgets();
+ bool addCustomWidget(QDesignerCustomWidgetInterface *c,
+ const QString &pluginPath,
+ const QString &designerLanguage);
+ void addCustomWidgets(const QObject *o,
+ const QString &pluginPath,
+ const QString &designerLanguage);
+
+ QDesignerFormEditorInterface *m_core;
+ QStringList m_pluginPaths;
+ QStringList m_registeredPlugins;
+ // TODO: QPluginLoader also caches invalid plugins -> This seems to be dead code
+ QStringList m_disabledPlugins;
+
+ typedef QMap<QString, QString> FailedPluginMap;
+ FailedPluginMap m_failedPlugins;
+
+ // Synced lists of custom widgets and their data. Note that the list
+ // must be ordered for collections to appear in order.
+ QList<QDesignerCustomWidgetInterface *> m_customWidgets;
+ QList<QDesignerCustomWidgetData> m_customWidgetData;
+
+ QStringList defaultPluginPaths() const;
+
+ bool m_initialized;
+};
+
+QDesignerPluginManagerPrivate::QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core) :
+ m_core(core),
+ m_initialized(false)
+{
+}
+
+void QDesignerPluginManagerPrivate::clearCustomWidgets()
+{
+ m_customWidgets.clear();
+ m_customWidgetData.clear();
+}
+
+// Add a custom widget to the list if it parses correctly
+// and is of the right language
+bool QDesignerPluginManagerPrivate::addCustomWidget(QDesignerCustomWidgetInterface *c,
+ const QString &pluginPath,
+ const QString &designerLanguage)
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << c->name();
+
+ if (!c->isInitialized())
+ c->initialize(m_core);
+ // Parse the XML even if the plugin is initialized as Jambi might play tricks here
+ QDesignerCustomWidgetData data(pluginPath);
+ const QString domXml = c->domXml();
+ if (!domXml.isEmpty()) { // Legacy: Empty XML means: Do not show up in widget box.
+ QString errorMessage;
+ const QDesignerCustomWidgetData::ParseResult pr = data.parseXml(domXml, c->name(), &errorMessage);
+ switch (pr) {
+ case QDesignerCustomWidgetData::ParseOk:
+ break;
+ case QDesignerCustomWidgetData::ParseWarning:
+ qdesigner_internal::designerWarning(errorMessage);
+ break;
+ case QDesignerCustomWidgetData::ParseError:
+ qdesigner_internal::designerWarning(errorMessage);
+ return false;
+ }
+ // Does the language match?
+ const QString pluginLanguage = data.xmlLanguage();
+ if (!pluginLanguage.isEmpty() && pluginLanguage.compare(designerLanguage, Qt::CaseInsensitive))
+ return false;
+ }
+ m_customWidgets.push_back(c);
+ m_customWidgetData.push_back(data);
+ return true;
+}
+
+// Check the plugin interface for either a custom widget or a collection and
+// add all contained custom widgets.
+void QDesignerPluginManagerPrivate::addCustomWidgets(const QObject *o,
+ const QString &pluginPath,
+ const QString &designerLanguage)
+{
+ if (QDesignerCustomWidgetInterface *c = qobject_cast<QDesignerCustomWidgetInterface*>(o)) {
+ addCustomWidget(c, pluginPath, designerLanguage);
+ return;
+ }
+ if (const QDesignerCustomWidgetCollectionInterface *coll = qobject_cast<QDesignerCustomWidgetCollectionInterface*>(o)) {
+ foreach(QDesignerCustomWidgetInterface *c, coll->customWidgets())
+ addCustomWidget(c, pluginPath, designerLanguage);
+ }
+}
+
+
+// ---------------- QDesignerPluginManager
+// As of 4.4, the header will be distributed with the Eclipse plugin.
+
+QDesignerPluginManager::QDesignerPluginManager(QDesignerFormEditorInterface *core) :
+ QObject(core),
+ m_d(new QDesignerPluginManagerPrivate(core))
+{
+ m_d->m_pluginPaths = defaultPluginPaths();
+ const QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName());
+ m_d->m_disabledPlugins = unique(settings.value(QLatin1String("PluginManager/DisabledPlugins")).toStringList());
+
+ // Register plugins
+ updateRegisteredPlugins();
+
+ if (debugPluginManager)
+ qDebug() << "QDesignerPluginManager::disabled: " << m_d->m_disabledPlugins << " static " << m_d->m_customWidgets.size();
+}
+
+QDesignerPluginManager::~QDesignerPluginManager()
+{
+ syncSettings();
+ delete m_d;
+}
+
+QDesignerFormEditorInterface *QDesignerPluginManager::core() const
+{
+ return m_d->m_core;
+}
+
+QStringList QDesignerPluginManager::findPlugins(const QString &path)
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << path;
+ const QDir dir(path);
+ if (!dir.exists())
+ return QStringList();
+
+ const QFileInfoList infoList = dir.entryInfoList(QDir::Files);
+ if (infoList.empty())
+ return QStringList();
+
+ // Load symbolic links but make sure all file names are unique as not
+ // to fall for something like 'libplugin.so.1 -> libplugin.so'
+ QStringList result;
+ const QFileInfoList::const_iterator icend = infoList.constEnd();
+ for (QFileInfoList::const_iterator it = infoList.constBegin(); it != icend; ++it) {
+ QString fileName;
+ if (it->isSymLink()) {
+ const QFileInfo linkTarget = QFileInfo(it->symLinkTarget());
+ if (linkTarget.exists() && linkTarget.isFile())
+ fileName = linkTarget.absoluteFilePath();
+ } else {
+ fileName = it->absoluteFilePath();
+ }
+ if (!fileName.isEmpty() && QLibrary::isLibrary(fileName) && !result.contains(fileName))
+ result += fileName;
+ }
+ return result;
+}
+
+void QDesignerPluginManager::setDisabledPlugins(const QStringList &disabled_plugins)
+{
+ m_d->m_disabledPlugins = disabled_plugins;
+ updateRegisteredPlugins();
+}
+
+void QDesignerPluginManager::setPluginPaths(const QStringList &plugin_paths)
+{
+ m_d->m_pluginPaths = plugin_paths;
+ updateRegisteredPlugins();
+}
+
+QStringList QDesignerPluginManager::disabledPlugins() const
+{
+ return m_d->m_disabledPlugins;
+}
+
+QStringList QDesignerPluginManager::failedPlugins() const
+{
+ return m_d->m_failedPlugins.keys();
+}
+
+QString QDesignerPluginManager::failureReason(const QString &pluginName) const
+{
+ return m_d->m_failedPlugins.value(pluginName);
+}
+
+QStringList QDesignerPluginManager::registeredPlugins() const
+{
+ return m_d->m_registeredPlugins;
+}
+
+QStringList QDesignerPluginManager::pluginPaths() const
+{
+ return m_d->m_pluginPaths;
+}
+
+QObject *QDesignerPluginManager::instance(const QString &plugin) const
+{
+ if (m_d->m_disabledPlugins.contains(plugin))
+ return 0;
+
+ QPluginLoader loader(plugin);
+ return loader.instance();
+}
+
+void QDesignerPluginManager::updateRegisteredPlugins()
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO;
+ m_d->m_registeredPlugins.clear();
+ foreach (const QString &path, m_d->m_pluginPaths)
+ registerPath(path);
+}
+
+bool QDesignerPluginManager::registerNewPlugins()
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO;
+
+ const int before = m_d->m_registeredPlugins.size();
+ foreach (const QString &path, m_d->m_pluginPaths)
+ registerPath(path);
+ const bool newPluginsFound = m_d->m_registeredPlugins.size() > before;
+ // We force a re-initialize as Jambi collection might return
+ // different widget lists when switching projects.
+ m_d->m_initialized = false;
+ ensureInitialized();
+
+ return newPluginsFound;
+}
+
+void QDesignerPluginManager::registerPath(const QString &path)
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << path;
+ QStringList candidates = findPlugins(path);
+
+ foreach (const QString &plugin, candidates)
+ registerPlugin(plugin);
+}
+
+void QDesignerPluginManager::registerPlugin(const QString &plugin)
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << plugin;
+ if (m_d->m_disabledPlugins.contains(plugin))
+ return;
+ if (m_d->m_registeredPlugins.contains(plugin))
+ return;
+
+ QPluginLoader loader(plugin);
+ if (loader.isLoaded() || loader.load()) {
+ m_d->m_registeredPlugins += plugin;
+ QDesignerPluginManagerPrivate::FailedPluginMap::iterator fit = m_d->m_failedPlugins.find(plugin);
+ if (fit != m_d->m_failedPlugins.end())
+ m_d->m_failedPlugins.erase(fit);
+ return;
+ }
+
+ const QString errorMessage = loader.errorString();
+ m_d->m_failedPlugins.insert(plugin, errorMessage);
+}
+
+
+
+bool QDesignerPluginManager::syncSettings()
+{
+ QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName());
+ settings.beginGroup(QLatin1String("PluginManager"));
+ settings.setValue(QLatin1String("DisabledPlugins"), m_d->m_disabledPlugins);
+ settings.endGroup();
+ return settings.status() == QSettings::NoError;
+}
+
+void QDesignerPluginManager::ensureInitialized()
+{
+ if (debugPluginManager)
+ qDebug() << Q_FUNC_INFO << m_d->m_initialized << m_d->m_customWidgets.size();
+
+ if (m_d->m_initialized)
+ return;
+
+ const QString designerLanguage = getDesignerLanguage(m_d->m_core);
+
+ m_d->clearCustomWidgets();
+ // Add the static custom widgets
+ const QObjectList staticPluginObjects = QPluginLoader::staticInstances();
+ if (!staticPluginObjects.empty()) {
+ const QString staticPluginPath = QCoreApplication::applicationFilePath();
+ foreach(QObject *o, staticPluginObjects)
+ m_d->addCustomWidgets(o, staticPluginPath, designerLanguage);
+ }
+ foreach (const QString &plugin, m_d->m_registeredPlugins)
+ if (QObject *o = instance(plugin))
+ m_d->addCustomWidgets(o, plugin, designerLanguage);
+
+ m_d->m_initialized = true;
+}
+
+QDesignerPluginManager::CustomWidgetList QDesignerPluginManager::registeredCustomWidgets() const
+{
+ const_cast<QDesignerPluginManager*>(this)->ensureInitialized();
+ return m_d->m_customWidgets;
+}
+
+QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(QDesignerCustomWidgetInterface *w) const
+{
+ const int index = m_d->m_customWidgets.indexOf(w);
+ if (index == -1)
+ return QDesignerCustomWidgetData();
+ return m_d->m_customWidgetData.at(index);
+}
+
+QObjectList QDesignerPluginManager::instances() const
+{
+ QStringList plugins = registeredPlugins();
+
+ QObjectList lst;
+ foreach (const QString &plugin, plugins) {
+ if (QObject *o = instance(plugin))
+ lst.append(o);
+ }
+
+ return lst;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/pluginmanager_p.h b/tools/designer/src/lib/shared/pluginmanager_p.h
new file mode 100644
index 0000000..e374f42
--- /dev/null
+++ b/tools/designer/src/lib/shared/pluginmanager_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 PLUGINMANAGER_H
+#define PLUGINMANAGER_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QMap>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerCustomWidgetInterface;
+class QDesignerPluginManagerPrivate;
+
+class QDesignerCustomWidgetSharedData;
+
+/* Information contained in the Dom XML of a custom widget. */
+class QDESIGNER_SHARED_EXPORT QDesignerCustomWidgetData {
+public:
+ explicit QDesignerCustomWidgetData(const QString &pluginPath = QString());
+
+ enum ParseResult { ParseOk, ParseWarning, ParseError };
+ ParseResult parseXml(const QString &xml, const QString &name, QString *errorMessage);
+
+ QDesignerCustomWidgetData(const QDesignerCustomWidgetData&);
+ QDesignerCustomWidgetData& operator=(const QDesignerCustomWidgetData&);
+ ~QDesignerCustomWidgetData();
+
+ bool isNull() const;
+
+ QString pluginPath() const;
+
+ // Data as parsed from the widget's domXML().
+ QString xmlClassName() const;
+ // Optional. The language the plugin is supposed to be used with.
+ QString xmlLanguage() const;
+ // Optional. method used to add pages to a container with a container extension
+ QString xmlAddPageMethod() const;
+ // Optional. Base class
+ QString xmlExtends() const;
+ // Optional. The name to be used in the widget box.
+ QString xmlDisplayName() const;
+
+private:
+ QSharedDataPointer<QDesignerCustomWidgetSharedData> m_d;
+};
+
+class QDESIGNER_SHARED_EXPORT QDesignerPluginManager: public QObject
+{
+ Q_OBJECT
+public:
+ typedef QList<QDesignerCustomWidgetInterface*> CustomWidgetList;
+
+ explicit QDesignerPluginManager(QDesignerFormEditorInterface *core);
+ virtual ~QDesignerPluginManager();
+
+ QDesignerFormEditorInterface *core() const;
+
+ QObject *instance(const QString &plugin) const;
+
+ QStringList registeredPlugins() const;
+
+ QStringList findPlugins(const QString &path);
+
+ QStringList pluginPaths() const;
+ void setPluginPaths(const QStringList &plugin_paths);
+
+ QStringList disabledPlugins() const;
+ void setDisabledPlugins(const QStringList &disabled_plugins);
+
+ QStringList failedPlugins() const;
+ QString failureReason(const QString &pluginName) const;
+
+ QObjectList instances() const;
+
+ CustomWidgetList registeredCustomWidgets() const;
+ QDesignerCustomWidgetData customWidgetData(QDesignerCustomWidgetInterface *w) const;
+
+ bool registerNewPlugins();
+
+public slots:
+ bool syncSettings();
+ void ensureInitialized();
+
+private:
+ void updateRegisteredPlugins();
+ void registerPath(const QString &path);
+ void registerPlugin(const QString &plugin);
+
+private:
+ static QStringList defaultPluginPaths();
+
+ QDesignerPluginManagerPrivate *m_d;
+};
+
+QT_END_NAMESPACE
+
+#endif // PLUGINMANAGER_H
diff --git a/tools/designer/src/lib/shared/previewconfigurationwidget.cpp b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp
new file mode 100644
index 0000000..2cf362f
--- /dev/null
+++ b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/* It is possible to link the skins as resources into Designer by specifying:
+ * QVFB_ROOT=$$QT_SOURCE_TREE/tools/qvfb
+ * RESOURCES += $$QVFB_ROOT/ClamshellPhone.qrc $$QVFB_ROOT/PDAPhone.qrc ...
+ * in lib/shared/shared.pri. However, this exceeds a limit of Visual Studio 6. */
+
+#include "previewconfigurationwidget_p.h"
+#include "ui_previewconfigurationwidget.h"
+#include "previewmanager_p.h"
+#include "abstractsettings_p.h"
+#include "shared_settings_p.h"
+
+#include <iconloader_p.h>
+#include <stylesheeteditor_p.h>
+
+#include <deviceskin.h>
+
+#include <QtGui/QFileDialog>
+#include <QtGui/QStyleFactory>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
+#include <QtCore/QPair>
+#include <QtCore/QList>
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSharedData>
+
+// #define DEFAULT_SKINS_FROM_RESOURCE
+#ifdef DEFAULT_SKINS_FROM_RESOURCE
+QT_BEGIN_NAMESPACE
+static const char *skinResourcePathC = ":/skins/";
+QT_END_NAMESPACE
+#else
+# include <QtCore/QLibraryInfo>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static const char *skinExtensionC = "skin";
+
+namespace {
+ // Pair of skin name, path
+ typedef QPair<QString, QString> SkinNamePath;
+ typedef QList<SkinNamePath> Skins;
+ enum { SkinComboNoneIndex = 0 };
+}
+
+// find default skins (resources)
+static const Skins &defaultSkins() {
+ static Skins rc;
+ if (rc.empty()) {
+#ifdef DEFAULT_SKINS_FROM_RESOURCE
+ const QString skinPath = QLatin1String(skinResourcePathC);
+#else
+ QString skinPath = QLibraryInfo::location(QLibraryInfo::PrefixPath);
+ skinPath += QDir::separator();
+ skinPath += QLatin1String("tools");
+ skinPath += QDir::separator();
+ skinPath += QLatin1String("qvfb");
+#endif
+ QString pattern = QLatin1String("*.");
+ pattern += QLatin1String(skinExtensionC);
+ const QDir dir(skinPath, pattern);
+ const QFileInfoList list = dir.entryInfoList();
+ if (list.empty())
+ return rc;
+ const QFileInfoList::const_iterator lcend = list.constEnd();
+ for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it)
+ rc.push_back(SkinNamePath(it->baseName(), it->filePath()));
+ }
+ return rc;
+}
+
+namespace qdesigner_internal {
+
+// ------------- PreviewConfigurationWidgetPrivate
+class PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate {
+public:
+ PreviewConfigurationWidgetPrivate(QDesignerFormEditorInterface *core, QGroupBox *g);
+
+ void slotEditAppStyleSheet();
+ void slotDeleteSkinEntry();
+ void slotSkinChanged(int index);
+
+ void retrieveSettings();
+ void storeSettings() const;
+
+ QAbstractButton *appStyleSheetChangeButton() const { return m_ui.m_appStyleSheetChangeButton; }
+ QAbstractButton *skinRemoveButton() const { return m_ui.m_skinRemoveButton; }
+ QComboBox *skinCombo() const { return m_ui.m_skinCombo; }
+
+ QDesignerFormEditorInterface *m_core;
+
+private:
+ PreviewConfiguration previewConfiguration() const;
+ void setPreviewConfiguration(const PreviewConfiguration &pc);
+
+ QStringList userSkins() const;
+ void addUserSkins(const QStringList &files);
+ bool canRemoveSkin(int index) const;
+ int browseSkin();
+
+ const QString m_defaultStyle;
+ QGroupBox *m_parent;
+ Ui::PreviewConfigurationWidget m_ui;
+
+ int m_firstUserSkinIndex;
+ int m_browseSkinIndex;
+ int m_lastSkinIndex; // required in case browse fails
+};
+
+PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::PreviewConfigurationWidgetPrivate(
+ QDesignerFormEditorInterface *core, QGroupBox *g) :
+ m_core(core),
+ m_defaultStyle(PreviewConfigurationWidget::tr("Default")),
+ m_parent(g),
+ m_firstUserSkinIndex(0),
+ m_browseSkinIndex(0),
+ m_lastSkinIndex(0)
+{
+ m_ui.setupUi(g);
+ // styles
+ m_ui.m_styleCombo->setEditable(false);
+ QStringList styleItems(m_defaultStyle);
+ styleItems += QStyleFactory::keys();
+ m_ui.m_styleCombo->addItems(styleItems);
+
+ // sheet
+ m_ui.m_appStyleSheetLineEdit->setTextPropertyValidationMode(qdesigner_internal::ValidationStyleSheet);
+ m_ui.m_appStyleSheetClearButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("resetproperty.png")));
+ QObject::connect(m_ui.m_appStyleSheetClearButton, SIGNAL(clicked()), m_ui.m_appStyleSheetLineEdit, SLOT(clear()));
+
+ m_ui.m_skinRemoveButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("editdelete.png")));
+ // skins: find default skins (resources)
+ m_ui.m_skinRemoveButton->setEnabled(false);
+ Skins skins = defaultSkins();
+ skins.push_front(SkinNamePath(PreviewConfigurationWidget::tr("None"), QString()));
+
+ const Skins::const_iterator scend = skins.constEnd();
+ for (Skins::const_iterator it = skins.constBegin(); it != scend; ++it)
+ m_ui.m_skinCombo->addItem (it->first, QVariant(it->second));
+ m_browseSkinIndex = m_firstUserSkinIndex = skins.size();
+ m_ui.m_skinCombo->addItem(PreviewConfigurationWidget::tr("Browse..."), QString());
+
+ m_ui.m_skinCombo->setMaxVisibleItems (qMax(15, 2 * m_browseSkinIndex));
+ m_ui.m_skinCombo->setEditable(false);
+
+ retrieveSettings();
+}
+
+bool PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::canRemoveSkin(int index) const
+{
+ return index >= m_firstUserSkinIndex && index != m_browseSkinIndex;
+}
+
+QStringList PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::userSkins() const
+{
+ QStringList rc;
+ for (int i = m_firstUserSkinIndex; i < m_browseSkinIndex; i++)
+ rc.push_back(m_ui.m_skinCombo->itemData(i).toString());
+ return rc;
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::addUserSkins(const QStringList &files)
+{
+ if (files.empty())
+ return;
+ const QStringList ::const_iterator fcend = files.constEnd();
+ for (QStringList::const_iterator it = files.constBegin(); it != fcend; ++it) {
+ const QFileInfo fi(*it);
+ if (fi.isDir() && fi.isReadable()) {
+ m_ui.m_skinCombo->insertItem(m_browseSkinIndex++, fi.baseName(), QVariant(*it));
+ } else {
+ qWarning() << "Unable to access the skin directory '" << *it << "'.";
+ }
+ }
+}
+
+PreviewConfiguration PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::previewConfiguration() const
+{
+ PreviewConfiguration rc;
+ QString style = m_ui.m_styleCombo->currentText();
+ if (style == m_defaultStyle)
+ style.clear();
+ const QString applicationStyleSheet = m_ui.m_appStyleSheetLineEdit->text();
+ // Figure out skin. 0 is None by definition..
+ const int skinIndex = m_ui.m_skinCombo->currentIndex();
+ QString deviceSkin;
+ if (skinIndex != SkinComboNoneIndex && skinIndex != m_browseSkinIndex)
+ deviceSkin = m_ui.m_skinCombo->itemData(skinIndex).toString();
+
+ return PreviewConfiguration(style, applicationStyleSheet, deviceSkin);
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::setPreviewConfiguration(const PreviewConfiguration &pc)
+{
+ int styleIndex = m_ui.m_styleCombo->findText(pc.style());
+ if (styleIndex == -1)
+ styleIndex = m_ui.m_styleCombo->findText(m_defaultStyle);
+ m_ui.m_styleCombo->setCurrentIndex(styleIndex);
+ m_ui.m_appStyleSheetLineEdit->setText(pc.applicationStyleSheet());
+ // find skin by file name. 0 is "none"
+ const QString deviceSkin = pc.deviceSkin();
+ int skinIndex = deviceSkin.isEmpty() ? 0 : m_ui.m_skinCombo->findData(QVariant(deviceSkin));
+ if (skinIndex == -1) {
+ qWarning() << "Unable to find skin '" << deviceSkin << "'.";
+ skinIndex = 0;
+ }
+ m_ui.m_skinCombo->setCurrentIndex(skinIndex);
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotEditAppStyleSheet()
+{
+ StyleSheetEditorDialog dlg(m_core, m_parent, StyleSheetEditorDialog::ModeGlobal);
+ dlg.setText(m_ui.m_appStyleSheetLineEdit->text());
+ if (dlg.exec() == QDialog::Accepted)
+ m_ui.m_appStyleSheetLineEdit->setText(dlg.text());
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotDeleteSkinEntry()
+{
+ const int index = m_ui.m_skinCombo->currentIndex();
+ if (canRemoveSkin(index)) {
+ m_ui.m_skinCombo->setCurrentIndex(SkinComboNoneIndex);
+ m_ui.m_skinCombo->removeItem(index);
+ m_browseSkinIndex--;
+ }
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotSkinChanged(int index)
+{
+ if (index == m_browseSkinIndex) {
+ m_ui.m_skinCombo->setCurrentIndex(browseSkin());
+ } else {
+ m_lastSkinIndex = index;
+ m_ui.m_skinRemoveButton->setEnabled(canRemoveSkin(index));
+ m_ui.m_skinCombo->setToolTip(index != SkinComboNoneIndex ? m_ui.m_skinCombo->itemData(index).toString() : QString());
+ }
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::retrieveSettings()
+{
+ QDesignerSharedSettings settings(m_core);
+ m_parent->setChecked(settings.isCustomPreviewConfigurationEnabled());
+ setPreviewConfiguration(settings.customPreviewConfiguration());
+ addUserSkins(settings.userDeviceSkins());
+}
+
+void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::storeSettings() const
+{
+ QDesignerSharedSettings settings(m_core);
+ settings.setCustomPreviewConfigurationEnabled(m_parent->isChecked());
+ settings.setCustomPreviewConfiguration(previewConfiguration());
+ settings.setUserDeviceSkins(userSkins());
+}
+
+int PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::browseSkin()
+{
+ QFileDialog dlg(m_parent);
+ dlg.setFileMode(QFileDialog::DirectoryOnly);
+ const QString title = tr("Load Custom Device Skin");
+ dlg.setWindowTitle(title);
+ dlg.setFilter(tr("All QVFB Skins (*.%1)").arg(QLatin1String(skinExtensionC)));
+
+ int rc = m_lastSkinIndex;
+ do {
+ if (!dlg.exec())
+ break;
+
+ const QStringList directories = dlg.selectedFiles();
+ if (directories.size() != 1)
+ break;
+
+ // check: 1) name already there
+ const QString directory = directories.front();
+ const QString name = QFileInfo(directory).baseName();
+ const int existingIndex = m_ui.m_skinCombo->findText(name);
+ if (existingIndex != -1 && existingIndex != SkinComboNoneIndex && existingIndex != m_browseSkinIndex) {
+ const QString msgTitle = tr("%1 - Duplicate Skin").arg(title);
+ const QString msg = tr("The skin '%1' already exists.").arg(name);
+ QMessageBox::information(m_parent, msgTitle, msg);
+ break;
+ }
+ // check: 2) can read
+ DeviceSkinParameters parameters;
+ QString readError;
+ if (parameters.read(directory, DeviceSkinParameters::ReadSizeOnly, &readError)) {
+ const QString name = QFileInfo(directory).baseName();
+ m_ui.m_skinCombo->insertItem(m_browseSkinIndex, name, QVariant(directory));
+ rc = m_browseSkinIndex++;
+
+ break;
+ } else {
+ const QString msgTitle = tr("%1 - Error").arg(title);
+ const QString msg = tr("%1 is not a valid skin directory:\n%2").arg(directory).arg(readError);
+ QMessageBox::warning (m_parent, msgTitle, msg);
+ }
+ } while (true);
+ return rc;
+}
+
+// ------------- PreviewConfigurationWidget
+PreviewConfigurationWidget::PreviewConfigurationWidget(QDesignerFormEditorInterface *core,
+ QWidget *parent) :
+ QGroupBox(parent),
+ m_impl(new PreviewConfigurationWidgetPrivate(core, this))
+{
+ connect(m_impl->appStyleSheetChangeButton(), SIGNAL(clicked()), this, SLOT(slotEditAppStyleSheet()));
+ connect(m_impl->skinRemoveButton(), SIGNAL(clicked()), this, SLOT(slotDeleteSkinEntry()));
+ connect(m_impl->skinCombo(), SIGNAL(currentIndexChanged(int)), this, SLOT(slotSkinChanged(int)));
+
+ m_impl->retrieveSettings();
+}
+
+PreviewConfigurationWidget::~PreviewConfigurationWidget()
+{
+ delete m_impl;
+}
+
+void PreviewConfigurationWidget::saveState()
+{
+ m_impl->storeSettings();
+}
+
+void PreviewConfigurationWidget::slotEditAppStyleSheet()
+{
+ m_impl->slotEditAppStyleSheet();
+}
+
+void PreviewConfigurationWidget::slotDeleteSkinEntry()
+{
+ m_impl->slotDeleteSkinEntry();
+}
+
+void PreviewConfigurationWidget::slotSkinChanged(int index)
+{
+ m_impl->slotSkinChanged(index);
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/previewconfigurationwidget.ui b/tools/designer/src/lib/shared/previewconfigurationwidget.ui
new file mode 100644
index 0000000..2f18766
--- /dev/null
+++ b/tools/designer/src/lib/shared/previewconfigurationwidget.ui
@@ -0,0 +1,91 @@
+<ui version="4.0" >
+ <class>PreviewConfigurationWidget</class>
+ <widget class="QGroupBox" name="PreviewConfigurationWidget" >
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <property name="title" >
+ <string>Print/Preview Configuration</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <layout class="QFormLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="m_styleLabel" >
+ <property name="text" >
+ <string>Style</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="m_styleCombo" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="m_appStyleSheetLabel" >
+ <property name="text" >
+ <string>Style sheet</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="qdesigner_internal::TextPropertyEditor" name="m_appStyleSheetLineEdit" >
+ <property name="minimumSize" >
+ <size>
+ <width>149</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_appStyleSheetChangeButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_appStyleSheetClearButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="m_skinLabel" >
+ <property name="text" >
+ <string>Device skin</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QComboBox" name="m_skinCombo" />
+ </item>
+ <item>
+ <widget class="QToolButton" name="m_skinRemoveButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>qdesigner_internal::TextPropertyEditor</class>
+ <extends>QLineEdit</extends>
+ <header location="global" >textpropertyeditor_p.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/previewconfigurationwidget_p.h b/tools/designer/src/lib/shared/previewconfigurationwidget_p.h
new file mode 100644
index 0000000..897ec4e
--- /dev/null
+++ b/tools/designer/src/lib/shared/previewconfigurationwidget_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 PREVIEWCONFIGURATIONWIDGET_H
+#define PREVIEWCONFIGURATIONWIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QGroupBox>
+#include <QtCore/QSharedDataPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerSettingsInterface;
+
+namespace qdesigner_internal {
+
+// ----------- PreviewConfigurationWidget: Widget to edit the preview configuration.
+
+class QDESIGNER_SHARED_EXPORT PreviewConfigurationWidget : public QGroupBox
+{
+ Q_OBJECT
+public:
+ explicit PreviewConfigurationWidget(QDesignerFormEditorInterface *core,
+ QWidget *parent = 0);
+ virtual ~PreviewConfigurationWidget();
+ void saveState();
+
+private slots:
+ void slotEditAppStyleSheet();
+ void slotDeleteSkinEntry();
+ void slotSkinChanged(int);
+
+private:
+ class PreviewConfigurationWidgetPrivate;
+ PreviewConfigurationWidgetPrivate *m_impl;
+
+ PreviewConfigurationWidget(const PreviewConfigurationWidget &other);
+ PreviewConfigurationWidget &operator =(const PreviewConfigurationWidget &other);
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // PREVIEWCONFIGURATIONWIDGET_H
diff --git a/tools/designer/src/lib/shared/previewmanager.cpp b/tools/designer/src/lib/shared/previewmanager.cpp
new file mode 100644
index 0000000..8ed1772
--- /dev/null
+++ b/tools/designer/src/lib/shared/previewmanager.cpp
@@ -0,0 +1,815 @@
+/****************************************************************************
+**
+** 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 "abstractsettings_p.h"
+#include "previewmanager_p.h"
+#include "qdesigner_formbuilder_p.h"
+#include "shared_settings_p.h"
+#include "shared_settings_p.h"
+#include "zoomwidget_p.h"
+#include "formwindowbase_p.h"
+#include "widgetfactory_p.h"
+
+#include <deviceskin.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+
+#include <QtGui/QWidget>
+#include <QtGui/qevent.h>
+#include <QtGui/QDesktopWidget>
+#include <QtGui/QMainWindow>
+#include <QtGui/QDockWidget>
+#include <QtGui/QApplication>
+#include <QtGui/QPixmap>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#include <QtGui/QCursor>
+
+#include <QtCore/QMap>
+#include <QtCore/QDebug>
+#include <QtCore/QSharedData>
+
+QT_BEGIN_NAMESPACE
+
+static inline int compare(const qdesigner_internal::PreviewConfiguration &pc1, const qdesigner_internal::PreviewConfiguration &pc2)
+{
+ int rc = pc1.style().compare(pc2.style());
+ if (rc)
+ return rc;
+ rc = pc1.applicationStyleSheet().compare(pc2.applicationStyleSheet());
+ if (rc)
+ return rc;
+ return pc1.deviceSkin().compare(pc2.deviceSkin());
+}
+
+namespace {
+ // ------ PreviewData (data associated with a preview window)
+ struct PreviewData {
+ PreviewData(const QPointer<QWidget> &widget, const QDesignerFormWindowInterface *formWindow, const qdesigner_internal::PreviewConfiguration &pc);
+ QPointer<QWidget> m_widget;
+ const QDesignerFormWindowInterface *m_formWindow;
+ qdesigner_internal::PreviewConfiguration m_configuration;
+ };
+
+ PreviewData::PreviewData(const QPointer<QWidget>& widget,
+ const QDesignerFormWindowInterface *formWindow,
+ const qdesigner_internal::PreviewConfiguration &pc) :
+ m_widget(widget),
+ m_formWindow(formWindow),
+ m_configuration(pc)
+ {
+ }
+}
+
+namespace qdesigner_internal {
+
+/* In designer, we have the situation that laid-out maincontainers have
+ * a geometry set (which might differ from their sizeHint()). The QGraphicsItem
+ * should return that in its size hint, else such cases won't work */
+
+class DesignerZoomProxyWidget : public ZoomProxyWidget {
+ Q_DISABLE_COPY(DesignerZoomProxyWidget)
+public:
+ DesignerZoomProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+protected:
+ virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const;
+};
+
+DesignerZoomProxyWidget::DesignerZoomProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) :
+ ZoomProxyWidget(parent, wFlags)
+{
+}
+
+QSizeF DesignerZoomProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
+{
+ if (const QWidget *w = widget())
+ return QSizeF(w->size());
+ return ZoomProxyWidget::sizeHint(which, constraint);
+}
+
+// DesignerZoomWidget which returns DesignerZoomProxyWidget in its factory function
+class DesignerZoomWidget : public ZoomWidget {
+ Q_DISABLE_COPY(DesignerZoomWidget)
+public:
+ DesignerZoomWidget(QWidget *parent = 0);
+private:
+ virtual QGraphicsProxyWidget *createProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0) const;
+};
+
+DesignerZoomWidget::DesignerZoomWidget(QWidget *parent) :
+ ZoomWidget(parent)
+{
+}
+
+QGraphicsProxyWidget *DesignerZoomWidget::createProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) const
+{
+ return new DesignerZoomProxyWidget(parent, wFlags);
+}
+
+// --------- Widget Preview skin: Forward the key events to the window
+class PreviewDeviceSkin : public DeviceSkin
+{
+ Q_OBJECT
+public:
+ explicit PreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent);
+ virtual void setPreview(QWidget *w);
+ QSize screenSize() const { return m_screenSize; }
+
+private slots:
+ void slotSkinKeyPressEvent(int code, const QString& text, bool autorep);
+ void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep);
+ void slotPopupMenu();
+
+protected:
+ virtual void populateContextMenu(QMenu *m);
+
+private:
+ const QSize m_screenSize;
+};
+
+PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent) :
+ DeviceSkin(parameters, parent),
+ m_screenSize(parameters.screenSize())
+{
+ connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)),
+ this, SLOT(slotSkinKeyPressEvent(int,QString,bool)));
+ connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)),
+ this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool)));
+ connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu()));
+}
+
+void PreviewDeviceSkin::setPreview(QWidget *formWidget)
+{
+ formWidget->setFixedSize(m_screenSize);
+ formWidget->setParent(this, Qt::SubWindow);
+ formWidget->setAutoFillBackground(true);
+ setView(formWidget);
+}
+
+void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep)
+{
+ if (QWidget *focusWidget = QApplication::focusWidget()) {
+ QKeyEvent e(QEvent::KeyPress,code,0,text,autorep);
+ QApplication::sendEvent(focusWidget, &e);
+ }
+
+}
+
+void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep)
+{
+ if (QWidget *focusWidget = QApplication::focusWidget()) {
+ QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep);
+ QApplication::sendEvent(focusWidget, &e);
+ }
+}
+
+void PreviewDeviceSkin::slotPopupMenu()
+{
+ QMenu menu(this);
+ populateContextMenu(&menu);
+ menu.exec(QCursor::pos());
+}
+
+void PreviewDeviceSkin::populateContextMenu(QMenu *menu)
+{
+ connect(menu->addAction(tr("&Close")), SIGNAL(triggered()), parentWidget(), SLOT(close()));
+}
+
+// ------------ PreviewConfigurationPrivate
+class PreviewConfigurationData : public QSharedData {
+public:
+ PreviewConfigurationData() {}
+ explicit PreviewConfigurationData(const QString &style, const QString &applicationStyleSheet, const QString &deviceSkin);
+
+ QString m_style;
+ // Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()).
+ QString m_applicationStyleSheet;
+ QString m_deviceSkin;
+};
+
+PreviewConfigurationData::PreviewConfigurationData(const QString &style, const QString &applicationStyleSheet, const QString &deviceSkin) :
+ m_style(style),
+ m_applicationStyleSheet(applicationStyleSheet),
+ m_deviceSkin(deviceSkin)
+{
+}
+
+/* ZoomablePreviewDeviceSkin: A Zoomable Widget Preview skin. Embeds preview
+ * into a ZoomWidget and this in turn into the DeviceSkin view and keeps
+ * Device skin zoom + ZoomWidget zoom in sync. */
+
+class ZoomablePreviewDeviceSkin : public PreviewDeviceSkin
+{
+ Q_OBJECT
+public:
+ explicit ZoomablePreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent);
+ virtual void setPreview(QWidget *w);
+
+ int zoomPercent() const; // Device Skins have a double 'zoom' property
+
+public slots:
+ void setZoomPercent(int);
+
+signals:
+ void zoomPercentChanged(int);
+
+protected:
+ virtual void populateContextMenu(QMenu *m);
+
+private:
+ ZoomMenu *m_zoomMenu;
+ ZoomWidget *m_zoomWidget;
+};
+
+ZoomablePreviewDeviceSkin::ZoomablePreviewDeviceSkin(const DeviceSkinParameters &parameters, QWidget *parent) :
+ PreviewDeviceSkin(parameters, parent),
+ m_zoomMenu(new ZoomMenu(this)),
+ m_zoomWidget(new DesignerZoomWidget)
+{
+ connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SLOT(setZoomPercent(int)));
+ connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SIGNAL(zoomPercentChanged(int)));
+ m_zoomWidget->setZoomContextMenuEnabled(false);
+ m_zoomWidget->setWidgetZoomContextMenuEnabled(false);
+ m_zoomWidget->resize(screenSize());
+ m_zoomWidget->setParent(this, Qt::SubWindow);
+ m_zoomWidget->setAutoFillBackground(true);
+ setView(m_zoomWidget);
+}
+
+void ZoomablePreviewDeviceSkin::setPreview(QWidget *formWidget)
+{
+ formWidget->setFixedSize(screenSize());
+ m_zoomWidget->setWidget(formWidget);
+}
+
+int ZoomablePreviewDeviceSkin::zoomPercent() const
+{
+ return m_zoomWidget->zoom();
+}
+
+void ZoomablePreviewDeviceSkin::setZoomPercent(int z)
+{
+ if (z == zoomPercent())
+ return;
+
+ // If not triggered by the menu itself: Update it
+ if (m_zoomMenu->zoom() != z)
+ m_zoomMenu->setZoom(z);
+
+ const QCursor oldCursor = cursor();
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ // DeviceSkin has double, not qreal.
+ const double hundred = 100.0;
+ setZoom(static_cast<double>(z) / hundred);
+ m_zoomWidget->setZoom(z);
+ QApplication::restoreOverrideCursor();
+}
+
+void ZoomablePreviewDeviceSkin::populateContextMenu(QMenu *menu)
+{
+ m_zoomMenu->addActions(menu);
+ menu->addSeparator();
+ PreviewDeviceSkin::populateContextMenu(menu);
+ menu->addSeparator();
+}
+
+// ------------- PreviewConfiguration
+
+static const char *styleKey = "Style";
+static const char *appStyleSheetKey = "AppStyleSheet";
+static const char *skinKey = "Skin";
+
+PreviewConfiguration::PreviewConfiguration() :
+ m_d(new PreviewConfigurationData)
+{
+}
+
+PreviewConfiguration::PreviewConfiguration(const QString &sty, const QString &applicationSheet, const QString &skin) :
+ m_d(new PreviewConfigurationData(sty, applicationSheet, skin))
+{
+}
+
+PreviewConfiguration::PreviewConfiguration(const PreviewConfiguration &o) :
+ m_d(o.m_d)
+{
+}
+
+PreviewConfiguration &PreviewConfiguration::operator=(const PreviewConfiguration &o)
+{
+ m_d.operator=(o.m_d);
+ return *this;
+}
+
+PreviewConfiguration::~PreviewConfiguration()
+{
+}
+
+void PreviewConfiguration::clear()
+{
+ PreviewConfigurationData &d = *m_d;
+ d.m_style.clear();
+ d.m_applicationStyleSheet.clear();
+ d.m_deviceSkin.clear();
+}
+
+QString PreviewConfiguration::style() const
+{
+ return m_d->m_style;
+}
+
+void PreviewConfiguration::setStyle(const QString &s)
+{
+ m_d->m_style = s;
+}
+
+// Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()).
+QString PreviewConfiguration::applicationStyleSheet() const
+{
+ return m_d->m_applicationStyleSheet;
+}
+
+void PreviewConfiguration::setApplicationStyleSheet(const QString &as)
+{
+ m_d->m_applicationStyleSheet = as;
+}
+
+QString PreviewConfiguration::deviceSkin() const
+{
+ return m_d->m_deviceSkin;
+}
+
+void PreviewConfiguration::setDeviceSkin(const QString &s)
+{
+ m_d->m_deviceSkin = s;
+}
+
+void PreviewConfiguration::toSettings(const QString &prefix, QDesignerSettingsInterface *settings) const
+{
+ const PreviewConfigurationData &d = *m_d;
+ settings->beginGroup(prefix);
+ settings->setValue(QLatin1String(styleKey), d.m_style);
+ settings->setValue(QLatin1String(appStyleSheetKey), d.m_applicationStyleSheet);
+ settings->setValue(QLatin1String(skinKey), d.m_deviceSkin);
+ settings->endGroup();
+}
+
+void PreviewConfiguration::fromSettings(const QString &prefix, const QDesignerSettingsInterface *settings)
+{
+ clear();
+ QString key = prefix;
+ key += QLatin1Char('/');
+ const int prefixSize = key.size();
+
+ PreviewConfigurationData &d = *m_d;
+
+ const QVariant emptyString = QVariant(QString());
+
+ key += QLatin1String(styleKey);
+ d.m_style = settings->value(key, emptyString).toString();
+
+ key.replace(prefixSize, key.size() - prefixSize, QLatin1String(appStyleSheetKey));
+ d.m_applicationStyleSheet = settings->value(key, emptyString).toString();
+
+ key.replace(prefixSize, key.size() - prefixSize, QLatin1String(skinKey));
+ d.m_deviceSkin = settings->value(key, emptyString).toString();
+}
+
+
+QDESIGNER_SHARED_EXPORT bool operator<(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2)
+{
+ return compare(pc1, pc2) < 0;
+}
+
+QDESIGNER_SHARED_EXPORT bool operator==(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2)
+{
+ return compare(pc1, pc2) == 0;
+}
+
+QDESIGNER_SHARED_EXPORT bool operator!=(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2)
+{
+ return compare(pc1, pc2) != 0;
+}
+
+// ------------- PreviewManagerPrivate
+class PreviewManagerPrivate {
+public:
+ PreviewManagerPrivate(PreviewManager::PreviewMode mode);
+
+ const PreviewManager::PreviewMode m_mode;
+
+ QPointer<QWidget> m_activePreview;
+
+ typedef QList<PreviewData> PreviewDataList;
+
+ PreviewDataList m_previews;
+
+ typedef QMap<QString, DeviceSkinParameters> DeviceSkinConfigCache;
+ DeviceSkinConfigCache m_deviceSkinConfigCache;
+
+ QDesignerFormEditorInterface *m_core;
+ bool m_updateBlocked;
+};
+
+PreviewManagerPrivate::PreviewManagerPrivate(PreviewManager::PreviewMode mode) :
+ m_mode(mode),
+ m_core(0),
+ m_updateBlocked(false)
+{
+}
+
+// ------------- PreviewManager
+
+PreviewManager::PreviewManager(PreviewMode mode, QObject *parent) :
+ QObject(parent),
+ d(new PreviewManagerPrivate(mode))
+{
+}
+
+PreviewManager:: ~PreviewManager()
+{
+ delete d;
+}
+
+
+Qt::WindowFlags PreviewManager::previewWindowFlags(const QWidget *widget) const
+{
+#ifdef Q_WS_WIN
+ Qt::WindowFlags windowFlags = (widget->windowType() == Qt::Window) ? Qt::Window | Qt::WindowMaximizeButtonHint : Qt::WindowFlags(Qt::Dialog);
+#else
+ Q_UNUSED(widget)
+ // Only Dialogs have close buttons on Mac.
+ // On Linux, we don't want an additional task bar item and we don't want a minimize button;
+ // we want the preview to be on top.
+ Qt::WindowFlags windowFlags = Qt::Dialog;
+#endif
+ return windowFlags;
+}
+
+QWidget *PreviewManager::createDeviceSkinContainer(const QDesignerFormWindowInterface *fw) const
+{
+ return new QDialog(fw->window());
+}
+
+// Some widgets might require fake containers
+
+static QWidget *fakeContainer(QWidget *w)
+{
+ // Prevent a dock widget from trying to dock to Designer's main window
+ // (which can be found in the parent hierarchy in MDI mode) by
+ // providing a fake mainwindow
+ if (QDockWidget *dock = qobject_cast<QDockWidget *>(w)) {
+ // Reparent: Clear modality, propagate title and resize outer container
+ const QSize size = w->size();
+ w->setWindowModality(Qt::NonModal);
+ dock->setFeatures(dock->features() & ~(QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetClosable));
+ dock->setAllowedAreas(Qt::LeftDockWidgetArea);
+ QMainWindow *mw = new QMainWindow;
+ int leftMargin, topMargin, rightMargin, bottomMargin;
+ mw->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
+ mw->addDockWidget(Qt::LeftDockWidgetArea, dock);
+ mw->resize(size + QSize(leftMargin + rightMargin, topMargin + bottomMargin));
+ return mw;
+ }
+ return w;
+}
+
+static PreviewConfiguration configurationFromSettings(QDesignerFormEditorInterface *core, const QString &style)
+{
+ qdesigner_internal::PreviewConfiguration pc;
+ const QDesignerSharedSettings settings(core);
+ if (settings.isCustomPreviewConfigurationEnabled())
+ pc = settings.customPreviewConfiguration();
+ if (!style.isEmpty())
+ pc.setStyle(style);
+ return pc;
+}
+
+QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex, QString *errorMessage)
+{
+ return showPreview(fw, configurationFromSettings(fw->core(), style), deviceProfileIndex, errorMessage);
+}
+
+QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage)
+{
+ return showPreview(fw, style, -1, errorMessage);
+}
+
+QWidget *PreviewManager::createPreview(const QDesignerFormWindowInterface *fw,
+ const PreviewConfiguration &pc,
+ int deviceProfileIndex,
+ QString *errorMessage,
+ int initialZoom)
+{
+ if (!d->m_core)
+ d->m_core = fw->core();
+
+ const bool zoomable = initialZoom > 0;
+ // Figure out which profile to apply
+ DeviceProfile deviceProfile;
+ if (deviceProfileIndex >= 0) {
+ deviceProfile = QDesignerSharedSettings(fw->core()).deviceProfileAt(deviceProfileIndex);
+ } else {
+ if (const FormWindowBase *fwb = qobject_cast<const FormWindowBase *>(fw))
+ deviceProfile = fwb->deviceProfile();
+ }
+ // Create
+ QWidget *formWidget = QDesignerFormBuilder::createPreview(fw, pc.style(), pc.applicationStyleSheet(), deviceProfile, errorMessage);
+ if (!formWidget)
+ return 0;
+
+ const QString title = tr("%1 - [Preview]").arg(formWidget->windowTitle());
+ formWidget = fakeContainer(formWidget);
+
+ // Clear any modality settings, child widget modalities must not be higher than parent's
+ formWidget->setWindowModality(Qt::NonModal);
+ // No skin
+ const QString deviceSkin = pc.deviceSkin();
+ if (deviceSkin.isEmpty()) {
+ if (zoomable) { // Embed into ZoomWidget
+ ZoomWidget *zw = new DesignerZoomWidget;
+ connect(zw->zoomMenu(), SIGNAL(zoomChanged(int)), this, SLOT(slotZoomChanged(int)));
+ zw->setWindowTitle(title);
+ zw->setWidget(formWidget);
+ // Keep any widgets' context menus working, do not use global menu
+ zw->setWidgetZoomContextMenuEnabled(true);
+ zw->setParent(fw->window(), previewWindowFlags(formWidget));
+ // Make preview close when Widget closes (Dialog/accept, etc)
+ formWidget->setAttribute(Qt::WA_DeleteOnClose, true);
+ connect(formWidget, SIGNAL(destroyed()), zw, SLOT(close()));
+ zw->setZoom(initialZoom);
+ zw->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true));
+ return zw;
+ }
+ formWidget->setParent(fw->window(), previewWindowFlags(formWidget));
+ formWidget->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true));
+ return formWidget;
+ }
+ // Embed into skin. find config in cache
+ PreviewManagerPrivate::DeviceSkinConfigCache::iterator it = d->m_deviceSkinConfigCache.find(deviceSkin);
+ if (it == d->m_deviceSkinConfigCache.end()) {
+ DeviceSkinParameters parameters;
+ if (!parameters.read(deviceSkin, DeviceSkinParameters::ReadAll, errorMessage)) {
+ formWidget->deleteLater();
+ return 0;
+ }
+ it = d->m_deviceSkinConfigCache.insert(deviceSkin, parameters);
+ }
+
+ QWidget *skinContainer = createDeviceSkinContainer(fw);
+ PreviewDeviceSkin *skin = 0;
+ if (zoomable) {
+ ZoomablePreviewDeviceSkin *zds = new ZoomablePreviewDeviceSkin(it.value(), skinContainer);
+ zds->setZoomPercent(initialZoom);
+ connect(zds, SIGNAL(zoomPercentChanged(int)), this, SLOT(slotZoomChanged(int)));
+ skin = zds;
+ } else {
+ skin = new PreviewDeviceSkin(it.value(), skinContainer);
+ }
+ skin->setPreview(formWidget);
+ // Make preview close when Widget closes (Dialog/accept, etc)
+ formWidget->setAttribute(Qt::WA_DeleteOnClose, true);
+ connect(formWidget, SIGNAL(destroyed()), skinContainer, SLOT(close()));
+ skinContainer->setWindowTitle(title);
+ skinContainer->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true));
+ return skinContainer;
+}
+
+QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw,
+ const PreviewConfiguration &pc,
+ int deviceProfileIndex,
+ QString *errorMessage)
+{
+ enum { Spacing = 10 };
+ if (QWidget *existingPreviewWidget = raise(fw, pc))
+ return existingPreviewWidget;
+
+ const QDesignerSharedSettings settings(fw->core());
+ const int initialZoom = settings.zoomEnabled() ? settings.zoom() : -1;
+
+ QWidget *widget = createPreview(fw, pc, deviceProfileIndex, errorMessage, initialZoom);
+ if (!widget)
+ return 0;
+ // Install filter for Escape key
+ widget->setAttribute(Qt::WA_DeleteOnClose, true);
+ widget->installEventFilter(this);
+
+ switch (d->m_mode) {
+ case ApplicationModalPreview:
+ // Cannot do this on the Mac as the dialog would have no close button
+ widget->setWindowModality(Qt::ApplicationModal);
+ break;
+ case SingleFormNonModalPreview:
+ case MultipleFormNonModalPreview:
+ widget->setWindowModality(Qt::NonModal);
+ connect(fw, SIGNAL(changed()), widget, SLOT(close()));
+ connect(fw, SIGNAL(destroyed()), widget, SLOT(close()));
+ if (d->m_mode == SingleFormNonModalPreview)
+ connect(fw->core()->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), widget, SLOT(close()));
+ break;
+ }
+ // Semi-smart algorithm to position previews:
+ // If its the first one, position relative to form.
+ // 2nd, attempt to tile right (for comparing styles) or cascade
+ const QSize size = widget->size();
+ const bool firstPreview = d->m_previews.empty();
+ if (firstPreview) {
+ widget->move(fw->mapToGlobal(QPoint(Spacing, Spacing)));
+ } else {
+ if (QWidget *lastPreview = d->m_previews.back().m_widget) {
+ QDesktopWidget *desktop = qApp->desktop();
+ const QRect lastPreviewGeometry = lastPreview->frameGeometry();
+ const QRect availGeometry = desktop->availableGeometry(desktop->screenNumber(lastPreview));
+ const QPoint newPos = lastPreviewGeometry.topRight() + QPoint(Spacing, 0);
+ if (newPos.x() + size.width() < availGeometry.right())
+ widget->move(newPos);
+ else
+ widget->move(lastPreviewGeometry.topLeft() + QPoint(Spacing, Spacing));
+ }
+
+ }
+ d->m_previews.push_back(PreviewData(widget, fw, pc));
+ widget->show();
+ if (firstPreview)
+ emit firstPreviewOpened();
+ return widget;
+}
+
+QWidget *PreviewManager::raise(const QDesignerFormWindowInterface *fw, const PreviewConfiguration &pc)
+{
+ typedef PreviewManagerPrivate::PreviewDataList PreviewDataList;
+ if (d->m_previews.empty())
+ return false;
+
+ // find matching window
+ const PreviewDataList::const_iterator cend = d->m_previews.constEnd();
+ for (PreviewDataList::const_iterator it = d->m_previews.constBegin(); it != cend ;++it) {
+ QWidget * w = it->m_widget;
+ if (w && it->m_formWindow == fw && it->m_configuration == pc) {
+ w->raise();
+ w->activateWindow();
+ return w;
+ }
+ }
+ return 0;
+}
+
+void PreviewManager::closeAllPreviews()
+{
+ typedef PreviewManagerPrivate::PreviewDataList PreviewDataList;
+ if (!d->m_previews.empty()) {
+ d->m_updateBlocked = true;
+ d->m_activePreview = 0;
+ const PreviewDataList::iterator cend = d->m_previews.end();
+ for (PreviewDataList::iterator it = d->m_previews.begin(); it != cend ;++it) {
+ if (it->m_widget)
+ it->m_widget->close();
+ }
+ d->m_previews.clear();
+ d->m_updateBlocked = false;
+ emit lastPreviewClosed();
+ }
+}
+
+void PreviewManager::updatePreviewClosed(QWidget *w)
+{
+ typedef PreviewManagerPrivate::PreviewDataList PreviewDataList;
+ if (d->m_updateBlocked)
+ return;
+ // Purge out all 0 or widgets to be deleted
+ for (PreviewDataList::iterator it = d->m_previews.begin(); it != d->m_previews.end() ; ) {
+ QWidget *iw = it->m_widget; // Might be 0 when catching QEvent::Destroyed
+ if (iw == 0 || iw == w) {
+ it = d->m_previews.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ if (d->m_previews.empty())
+ emit lastPreviewClosed();
+}
+
+bool PreviewManager::eventFilter(QObject *watched, QEvent *event)
+{
+ // Courtesy of designer
+ do {
+ if (!watched->isWidgetType())
+ break;
+ QWidget *previewWindow = qobject_cast<QWidget *>(watched);
+ if (!previewWindow || !previewWindow->isWindow())
+ break;
+
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ case QEvent::ShortcutOverride: {
+ const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
+ const int key = keyEvent->key();
+ if ((key == Qt::Key_Escape
+#ifdef Q_WS_MAC
+ || (keyEvent->modifiers() == Qt::ControlModifier && key == Qt::Key_Period)
+#endif
+ )) {
+ previewWindow->close();
+ return true;
+ }
+ }
+ break;
+ case QEvent::WindowActivate:
+ d->m_activePreview = previewWindow;
+ break;
+ case QEvent::Destroy: // We don't get QEvent::Close if someone accepts a QDialog.
+ updatePreviewClosed(previewWindow);
+ break;
+ case QEvent::Close:
+ updatePreviewClosed(previewWindow);
+ previewWindow->removeEventFilter (this);
+ break;
+ default:
+ break;
+ }
+ } while(false);
+ return QObject::eventFilter(watched, event);
+}
+
+int PreviewManager::previewCount() const
+{
+ return d->m_previews.size();
+}
+
+QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex, QString *errorMessage)
+{
+ return createPreviewPixmap(fw, configurationFromSettings(fw->core(), style), deviceProfileIndex, errorMessage);
+}
+
+QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage)
+{
+ return createPreviewPixmap(fw, style, -1, errorMessage);
+}
+
+QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw,
+ const PreviewConfiguration &pc,
+ int deviceProfileIndex,
+ QString *errorMessage)
+{
+ QWidget *widget = createPreview(fw, pc, deviceProfileIndex, errorMessage);
+ if (!widget)
+ return QPixmap();
+ const QPixmap rc = QPixmap::grabWidget(widget);
+ widget->deleteLater();
+ return rc;
+}
+
+void PreviewManager::slotZoomChanged(int z)
+{
+ if (d->m_core) { // Save the last zoom chosen by the user.
+ QDesignerSharedSettings settings(d->m_core);
+ settings.setZoom(z);
+ }
+}
+}
+
+QT_END_NAMESPACE
+
+#include "previewmanager.moc"
diff --git a/tools/designer/src/lib/shared/previewmanager_p.h b/tools/designer/src/lib/shared/previewmanager_p.h
new file mode 100644
index 0000000..1060f3c
--- /dev/null
+++ b/tools/designer/src/lib/shared/previewmanager_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** 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 PREVIEWMANAGER_H
+#define PREVIEWMANAGER_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QSharedDataPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QWidget;
+class QPixmap;
+class QAction;
+class QActionGroup;
+class QMenu;
+class QWidget;
+class QDesignerSettingsInterface;
+
+namespace qdesigner_internal {
+
+// ----------- PreviewConfiguration
+
+class PreviewConfigurationData;
+
+class QDESIGNER_SHARED_EXPORT PreviewConfiguration {
+public:
+ PreviewConfiguration();
+ explicit PreviewConfiguration(const QString &style,
+ const QString &applicationStyleSheet = QString(),
+ const QString &deviceSkin = QString());
+
+ PreviewConfiguration(const PreviewConfiguration&);
+ PreviewConfiguration& operator=(const PreviewConfiguration&);
+ ~PreviewConfiguration();
+
+ QString style() const;
+ void setStyle(const QString &);
+
+ // Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()).
+ QString applicationStyleSheet() const;
+ void setApplicationStyleSheet(const QString &);
+
+ QString deviceSkin() const;
+ void setDeviceSkin(const QString &);
+
+ void clear();
+ void toSettings(const QString &prefix, QDesignerSettingsInterface *settings) const;
+ void fromSettings(const QString &prefix, const QDesignerSettingsInterface *settings);
+
+private:
+ QSharedDataPointer<PreviewConfigurationData> m_d;
+};
+
+QDESIGNER_SHARED_EXPORT bool operator<(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2);
+QDESIGNER_SHARED_EXPORT bool operator==(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2);
+QDESIGNER_SHARED_EXPORT bool operator!=(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2);
+
+// ----------- Preview window manager.
+// Maintains a list of preview widgets with their associated form windows and configuration.
+
+class PreviewManagerPrivate;
+
+class QDESIGNER_SHARED_EXPORT PreviewManager : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum PreviewMode {
+ // Modal preview. Do not use on Macs as dialogs would have no close button
+ ApplicationModalPreview,
+ // Non modal previewing of one form in different configurations (closes if form window changes)
+ SingleFormNonModalPreview,
+ // Non modal previewing of several forms in different configurations
+ MultipleFormNonModalPreview };
+
+ explicit PreviewManager(PreviewMode mode, QObject *parent);
+ virtual ~PreviewManager();
+
+ // Show preview. Raise existing preview window if there is one with a matching
+ // configuration, else create a new preview.
+ QWidget *showPreview(const QDesignerFormWindowInterface *, const PreviewConfiguration &pc, int deviceProfileIndex /*=-1*/, QString *errorMessage);
+ // Convenience that creates a preview using a configuration taken from the settings.
+ QWidget *showPreview(const QDesignerFormWindowInterface *, const QString &style, int deviceProfileIndex /*=-1*/, QString *errorMessage);
+ QWidget *showPreview(const QDesignerFormWindowInterface *, const QString &style, QString *errorMessage);
+
+ int previewCount() const;
+
+ // Create a pixmap for printing.
+ QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const PreviewConfiguration &pc, int deviceProfileIndex /*=-1*/, QString *errorMessage);
+ // Convenience that creates a pixmap using a configuration taken from the settings.
+ QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex /*=-1*/, QString *errorMessage);
+ QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage);
+
+ virtual bool eventFilter(QObject *watched, QEvent *event);
+
+public slots:
+ void closeAllPreviews();
+
+signals:
+ void firstPreviewOpened();
+ void lastPreviewClosed();
+
+private slots:
+ void slotZoomChanged(int);
+
+private:
+
+ virtual Qt::WindowFlags previewWindowFlags(const QWidget *widget) const;
+ virtual QWidget *createDeviceSkinContainer(const QDesignerFormWindowInterface *) const;
+
+ QWidget *raise(const QDesignerFormWindowInterface *, const PreviewConfiguration &pc);
+ QWidget *createPreview(const QDesignerFormWindowInterface *,
+ const PreviewConfiguration &pc,
+ int deviceProfileIndex /* = -1 */,
+ QString *errorMessage,
+ /*Disabled by default, <0 */
+ int initialZoom = -1);
+
+ void updatePreviewClosed(QWidget *w);
+
+ PreviewManagerPrivate *d;
+
+ PreviewManager(const PreviewManager &other);
+ PreviewManager &operator =(const PreviewManager &other);
+};
+}
+
+QT_END_NAMESPACE
+
+#endif // PREVIEWMANAGER_H
diff --git a/tools/designer/src/lib/shared/promotionmodel.cpp b/tools/designer/src/lib/shared/promotionmodel.cpp
new file mode 100644
index 0000000..77d0bbb
--- /dev/null
+++ b/tools/designer/src/lib/shared/promotionmodel.cpp
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** 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::PromotionModel
+*/
+
+#include "promotionmodel_p.h"
+#include "widgetdatabase_p.h"
+
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+#include <QtDesigner/QDesignerPromotionInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtGui/QStandardItem>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ typedef QList<QStandardItem *> StandardItemList;
+
+ // Model columns.
+ enum { ClassNameColumn, IncludeFileColumn, IncludeTypeColumn, ReferencedColumn, NumColumns };
+
+ // Create a model row.
+ StandardItemList modelRow() {
+ StandardItemList rc;
+ for (int i = 0; i < NumColumns; i++) {
+ rc.push_back(new QStandardItem());
+ }
+ return rc;
+ }
+
+ // Create a model row for a base class (read-only, cannot be selected).
+ StandardItemList baseModelRow(const QDesignerWidgetDataBaseItemInterface *dbItem) {
+ StandardItemList rc = modelRow();
+
+ rc[ClassNameColumn]->setText(dbItem->name());
+ for (int i = 0; i < NumColumns; i++) {
+ rc[i]->setFlags(Qt::ItemIsEnabled);
+ }
+ return rc;
+ }
+
+ // Create an editable model row for a promoted class.
+ StandardItemList promotedModelRow(const QDesignerWidgetDataBaseInterface *widgetDataBase,
+ QDesignerWidgetDataBaseItemInterface *dbItem,
+ bool referenced = false) {
+
+ const int index = widgetDataBase->indexOf(dbItem);
+
+ // Associate user data: database index and enabled flag
+ QVariantList userDataList;
+ userDataList.push_back(QVariant(index));
+ userDataList.push_back(QVariant(referenced));
+ const QVariant userData(userDataList);
+
+ StandardItemList rc = modelRow();
+ // name
+ rc[ClassNameColumn]->setText(dbItem->name());
+ rc[ClassNameColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
+ rc[ClassNameColumn]->setData(userData);
+ // header
+ const qdesigner_internal::IncludeSpecification spec = qdesigner_internal::includeSpecification(dbItem->includeFile());
+ rc[IncludeFileColumn]->setText(spec.first);
+ rc[IncludeFileColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
+ rc[IncludeFileColumn]->setData(userData);
+ // global include
+ rc[IncludeTypeColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable);
+ rc[IncludeTypeColumn]->setData(userData);
+ rc[IncludeTypeColumn]->setCheckState(spec.second == qdesigner_internal::IncludeGlobal ? Qt::Checked : Qt::Unchecked);
+ // referenced
+ rc[ReferencedColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+ rc[ClassNameColumn]->setData(userData);
+ if (!referenced) {
+ //: Usage of promoted widgets
+ static const QString notUsed = QCoreApplication::translate("PromotionModel", "Not used");
+ rc[ReferencedColumn]->setText(notUsed);
+ }
+ return rc;
+ }
+}
+
+namespace qdesigner_internal {
+
+ PromotionModel::PromotionModel(QDesignerFormEditorInterface *core) :
+ m_core(core)
+ {
+ connect(this, SIGNAL(itemChanged(QStandardItem *)), this, SLOT(slotItemChanged(QStandardItem *)));
+ }
+
+ void PromotionModel::initializeHeaders() {
+ setColumnCount(NumColumns);
+ QStringList horizontalLabels(tr("Name"));
+ horizontalLabels += tr("Header file");
+ horizontalLabels += tr("Global include");
+ horizontalLabels += tr("Usage");
+ setHorizontalHeaderLabels (horizontalLabels);
+ }
+
+ void PromotionModel::updateFromWidgetDatabase() {
+ typedef QDesignerPromotionInterface::PromotedClasses PromotedClasses;
+
+ clear();
+ initializeHeaders();
+
+ // retrieve list of pairs from DB and convert into a tree structure.
+ // Set the item index as user data on the item.
+ const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses();
+
+ if (promotedClasses.empty())
+ return;
+
+ const QSet<QString> usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames();
+
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+ QDesignerWidgetDataBaseItemInterface *baseClass = 0;
+ QStandardItem *baseItem = 0;
+
+ const PromotedClasses::const_iterator bcend = promotedClasses.constEnd();
+ for (PromotedClasses::const_iterator it = promotedClasses.constBegin(); it != bcend; ++it) {
+ // Start a new base class?
+ if (baseClass != it->baseItem) {
+ baseClass = it->baseItem;
+ const StandardItemList baseRow = baseModelRow(it->baseItem);
+ baseItem = baseRow.front();
+ appendRow(baseRow);
+ }
+ Q_ASSERT(baseItem);
+ // Append derived
+ baseItem->appendRow(promotedModelRow(widgetDataBase, it->promotedItem, usedPromotedClasses.contains(it->promotedItem->name())));
+ }
+ }
+
+ void PromotionModel::slotItemChanged(QStandardItem * changedItem) {
+ // Retrieve DB item
+ bool referenced;
+ QDesignerWidgetDataBaseItemInterface *dbItem = databaseItem(changedItem, &referenced);
+ Q_ASSERT(dbItem);
+ // Change header or type
+ switch (changedItem->column()) {
+ case ClassNameColumn:
+ emit classNameChanged(dbItem, changedItem->text());
+ break;
+ case IncludeTypeColumn:
+ case IncludeFileColumn: {
+ // Get both file and type items via parent.
+ const QStandardItem *baseClassItem = changedItem->parent();
+ const QStandardItem *fileItem = baseClassItem->child(changedItem->row(), IncludeFileColumn);
+ const QStandardItem *typeItem = baseClassItem->child(changedItem->row(), IncludeTypeColumn);
+ emit includeFileChanged(dbItem, buildIncludeFile(fileItem->text(), typeItem->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal));
+ }
+ break;
+ }
+ }
+
+ QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItemAt(const QModelIndex &index, bool *referenced) const {
+ if (const QStandardItem *item = itemFromIndex (index))
+ return databaseItem(item, referenced);
+
+ *referenced = false;
+ return 0;
+ }
+
+ QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItem(const QStandardItem * item, bool *referenced) const {
+ // Decode user data associated with item.
+ const QVariant data = item->data();
+ if (data.type() != QVariant::List) {
+ *referenced = false;
+ return 0;
+ }
+
+ const QVariantList dataList = data.toList();
+ const int index = dataList[0].toInt();
+ *referenced = dataList[1].toBool();
+ return m_core->widgetDataBase()->item(index);
+ }
+
+ QModelIndex PromotionModel::indexOfClass(const QString &className) const {
+ const StandardItemList matches = findItems (className, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive);
+ return matches.empty() ? QModelIndex() : indexFromItem (matches.front());
+ }
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/promotionmodel_p.h b/tools/designer/src/lib/shared/promotionmodel_p.h
new file mode 100644
index 0000000..d5843fc
--- /dev/null
+++ b/tools/designer/src/lib/shared/promotionmodel_p.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$
+**
+****************************************************************************/
+
+//
+// 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 PROMOTIONMODEL_H
+#define PROMOTIONMODEL_H
+
+#include <QtGui/QStandardItemModel>
+#include <QtCore/QSet>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerWidgetDataBaseItemInterface;
+
+namespace qdesigner_internal {
+
+ // Item model representing the promoted widgets.
+ class PromotionModel : public QStandardItemModel {
+ Q_OBJECT
+
+ public:
+ explicit PromotionModel(QDesignerFormEditorInterface *core);
+
+ void updateFromWidgetDatabase();
+
+ // Return item at model index or 0.
+ QDesignerWidgetDataBaseItemInterface *databaseItemAt(const QModelIndex &, bool *referenced) const;
+
+ QModelIndex indexOfClass(const QString &className) const;
+
+ signals:
+ void includeFileChanged(QDesignerWidgetDataBaseItemInterface *, const QString &includeFile);
+ void classNameChanged(QDesignerWidgetDataBaseItemInterface *, const QString &newName);
+
+ private slots:
+ void slotItemChanged(QStandardItem * item);
+
+ private:
+ void initializeHeaders();
+ // Retrieve data base item of item or return 0.
+ QDesignerWidgetDataBaseItemInterface *databaseItem(const QStandardItem * item, bool *referenced) const;
+
+ QDesignerFormEditorInterface *m_core;
+ };
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // PROMOTIONMODEL_H
diff --git a/tools/designer/src/lib/shared/promotiontaskmenu.cpp b/tools/designer/src/lib/shared/promotiontaskmenu.cpp
new file mode 100644
index 0000000..e458aab
--- /dev/null
+++ b/tools/designer/src/lib/shared/promotiontaskmenu.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** 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 "promotiontaskmenu_p.h"
+#include "qdesigner_promotiondialog_p.h"
+#include "widgetfactory_p.h"
+#include "metadatabase_p.h"
+#include "widgetdatabase_p.h"
+#include "qdesigner_command_p.h"
+#include "signalslotdialog_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "abstractintrospection_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QAction>
+#include <QtGui/QWidget>
+#include <QtGui/QMenu>
+#include <QtCore/QSignalMapper>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static QAction *separatorAction(QObject *parent)
+{
+ QAction *rc = new QAction(parent);
+ rc->setSeparator(true);
+ return rc;
+}
+
+static inline QDesignerLanguageExtension *languageExtension(QDesignerFormEditorInterface *core)
+{
+ return qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core);
+}
+
+namespace qdesigner_internal {
+
+PromotionTaskMenu::PromotionTaskMenu(QWidget *widget,Mode mode, QObject *parent) :
+ QObject(parent),
+ m_mode(mode),
+ m_widget(widget),
+ m_promotionMapper(0),
+ m_globalEditAction(new QAction(tr("Promoted widgets..."), this)),
+ m_EditPromoteToAction(new QAction(tr("Promote to ..."), this)),
+ m_EditSignalsSlotsAction(new QAction(tr("Change signals/slots..."), this)),
+ m_promoteLabel(tr("Promote to")),
+ m_demoteLabel(tr("Demote to %1"))
+{
+ connect(m_globalEditAction, SIGNAL(triggered()), this, SLOT(slotEditPromotedWidgets()));
+ connect(m_EditPromoteToAction, SIGNAL(triggered()), this, SLOT(slotEditPromoteTo()));
+ connect(m_EditSignalsSlotsAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots()));
+}
+
+PromotionTaskMenu::Mode PromotionTaskMenu::mode() const
+{
+ return m_mode;
+}
+
+void PromotionTaskMenu::setMode(Mode m)
+{
+ m_mode = m;
+}
+
+void PromotionTaskMenu::setWidget(QWidget *widget)
+{
+ m_widget = widget;
+}
+
+void PromotionTaskMenu::setPromoteLabel(const QString &promoteLabel)
+{
+ m_promoteLabel = promoteLabel;
+}
+
+void PromotionTaskMenu::setEditPromoteToLabel(const QString &promoteEditLabel)
+{
+ m_EditPromoteToAction->setText(promoteEditLabel);
+}
+
+void PromotionTaskMenu::setDemoteLabel(const QString &demoteLabel)
+{
+ m_demoteLabel = demoteLabel;
+}
+
+PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDesignerFormWindowInterface *formWindow)
+{
+ // clear out old
+ if (!m_promotionActions.empty()) {
+ qDeleteAll(m_promotionActions);
+ m_promotionActions.clear();
+ }
+ // No promotion of main container
+ if (formWindow->mainContainer() == m_widget)
+ return NotApplicable;
+
+ // Check for a homogenous selection
+ const PromotionSelectionList promotionSelection = promotionSelectionList(formWindow);
+
+ if (promotionSelection.empty())
+ return NoHomogenousSelection;
+
+ QDesignerFormEditorInterface *core = formWindow->core();
+ // if it is promoted: demote only.
+ if (isPromoted(formWindow->core(), m_widget)) {
+ const QString label = m_demoteLabel.arg( promotedExtends(core , m_widget));
+ QAction *demoteAction = new QAction(label, this);
+ connect(demoteAction, SIGNAL(triggered()), this, SLOT(slotDemoteFromCustomWidget()));
+ m_promotionActions.push_back(demoteAction);
+ return CanDemote;
+ }
+ // figure out candidates
+ const QString baseClassName = WidgetFactory::classNameOf(core, m_widget);
+ const WidgetDataBaseItemList candidates = promotionCandidates(core->widgetDataBase(), baseClassName );
+ if (candidates.empty()) {
+ // Is this thing promotable at all?
+ return QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(baseClassName) ? CanPromote : NotApplicable;
+ }
+ // Set up a signal mapper to associate class names
+ if (!m_promotionMapper) {
+ m_promotionMapper = new QSignalMapper(this);
+ connect(m_promotionMapper, SIGNAL(mapped(QString)), this, SLOT(slotPromoteToCustomWidget(QString)));
+ }
+
+ QMenu *candidatesMenu = new QMenu();
+ // Create a sub menu
+ const WidgetDataBaseItemList::const_iterator cend = candidates.constEnd();
+ // Set up actions and map class names
+ for (WidgetDataBaseItemList::const_iterator it = candidates.constBegin(); it != cend; ++it) {
+ const QString customClassName = (*it)->name();
+ QAction *action = new QAction((*it)->name(), this);
+ connect(action, SIGNAL(triggered()), m_promotionMapper, SLOT(map()));
+ m_promotionMapper->setMapping(action, customClassName);
+ candidatesMenu->addAction(action);
+ }
+ // Sub menu action
+ QAction *subMenuAction = new QAction(m_promoteLabel, this);
+ subMenuAction->setMenu(candidatesMenu);
+ m_promotionActions.push_back(subMenuAction);
+ return CanPromote;
+}
+
+void PromotionTaskMenu::addActions(unsigned separatorFlags, ActionList &actionList)
+{
+ addActions(formWindow(), separatorFlags, actionList);
+}
+
+void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags,
+ ActionList &actionList)
+{
+ Q_ASSERT(m_widget);
+ const int previousSize = actionList.size();
+ const PromotionState promotionState = createPromotionActions(fw);
+
+ // Promotion candidates/demote
+ actionList += m_promotionActions;
+
+ // Edit action depending on context
+ switch (promotionState) {
+ case CanPromote:
+ actionList += m_EditPromoteToAction;
+ break;
+ case CanDemote:
+ if (!(flags & SuppressGlobalEdit))
+ actionList += m_globalEditAction;
+ if (!languageExtension(fw->core())) {
+ actionList += separatorAction(this);
+ actionList += m_EditSignalsSlotsAction;
+ }
+ break;
+ default:
+ if (!(flags & SuppressGlobalEdit))
+ actionList += m_globalEditAction;
+ break;
+ }
+ // Add separators if required
+ if (actionList.size() > previousSize) {
+ if (flags & LeadingSeparator)
+ actionList.insert(previousSize, separatorAction(this));
+ if (flags & TrailingSeparator)
+ actionList += separatorAction(this);
+ }
+}
+
+void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags, QMenu *menu)
+{
+ ActionList actionList;
+ addActions(fw, flags, actionList);
+ menu->addActions(actionList);
+}
+
+void PromotionTaskMenu::addActions(unsigned flags, QMenu *menu)
+{
+ addActions(formWindow(), flags, menu);
+}
+
+void PromotionTaskMenu::promoteTo(QDesignerFormWindowInterface *fw, const QString &customClassName)
+{
+ Q_ASSERT(m_widget);
+ PromoteToCustomWidgetCommand *cmd = new PromoteToCustomWidgetCommand(fw);
+ cmd->init(promotionSelectionList(fw), customClassName);
+ fw->commandHistory()->push(cmd);
+}
+
+
+void PromotionTaskMenu::slotPromoteToCustomWidget(const QString &customClassName)
+{
+ promoteTo(formWindow(), customClassName);
+}
+
+void PromotionTaskMenu::slotDemoteFromCustomWidget()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ const PromotionSelectionList promotedWidgets = promotionSelectionList(fw);
+ Q_ASSERT(!promotedWidgets.empty() && isPromoted(fw->core(), promotedWidgets.front()));
+
+ // ### use the undo stack
+ DemoteFromCustomWidgetCommand *cmd = new DemoteFromCustomWidgetCommand(fw);
+ cmd->init(promotedWidgets);
+ fw->commandHistory()->push(cmd);
+}
+
+void PromotionTaskMenu::slotEditPromoteTo()
+{
+ Q_ASSERT(m_widget);
+ // Check whether invoked over a promotable widget
+ QDesignerFormWindowInterface *fw = formWindow();
+ QDesignerFormEditorInterface *core = fw->core();
+ const QString base_class_name = WidgetFactory::classNameOf(core, m_widget);
+ Q_ASSERT(QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(base_class_name));
+ // Show over promotable widget
+ QString promoteToClassName;
+ QDialog *promotionEditor = 0;
+ if (QDesignerLanguageExtension *lang = languageExtension(core))
+ promotionEditor = lang->createPromotionDialog(core, base_class_name, &promoteToClassName, fw);
+ if (!promotionEditor)
+ promotionEditor = new QDesignerPromotionDialog(core, fw, base_class_name, &promoteToClassName);
+ if (promotionEditor->exec() == QDialog::Accepted && !promoteToClassName.isEmpty()) {
+ promoteTo(fw, promoteToClassName);
+ }
+ delete promotionEditor;
+}
+
+void PromotionTaskMenu::slotEditPromotedWidgets()
+{
+ // Global context, show over non-promotable widget
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+ editPromotedWidgets(fw->core(), fw);
+}
+
+PromotionTaskMenu::PromotionSelectionList PromotionTaskMenu::promotionSelectionList(QDesignerFormWindowInterface *formWindow) const
+{
+ // In multi selection mode, check for a homogenous selection (same class, same promotion state)
+ // and return the list if this is the case. Also make sure m_widget
+ // is the last widget in the list so that it is re-selected as the last
+ // widget by the promotion commands.
+
+ PromotionSelectionList rc;
+
+ if (m_mode != ModeSingleWidget) {
+ QDesignerFormEditorInterface *core = formWindow->core();
+ const QDesignerIntrospectionInterface *intro = core->introspection();
+ const QString className = intro->metaObject(m_widget)->className();
+ const bool promoted = isPromoted(formWindow->core(), m_widget);
+ // Just in case someone plugged an old-style Object Inspector
+ if (QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(core->objectInspector())) {
+ Selection s;
+ designerObjectInspector->getSelection(s);
+ // Find objects of similar state
+ const QWidgetList &source = m_mode == ModeManagedMultiSelection ? s.managed : s.unmanaged;
+ const QWidgetList::const_iterator cend = source.constEnd();
+ for (QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it) {
+ QWidget *w = *it;
+ if (w != m_widget) {
+ // Selection state mismatch
+ if (intro->metaObject(w)->className() != className || isPromoted(core, w) != promoted)
+ return PromotionSelectionList();
+ rc.push_back(w);
+ }
+ }
+ }
+ }
+
+ rc.push_back(m_widget);
+ return rc;
+}
+
+QDesignerFormWindowInterface *PromotionTaskMenu::formWindow() const
+{
+ // Use the QObject overload of QDesignerFormWindowInterface::findFormWindow since that works
+ // for QDesignerMenus also.
+ QObject *o = m_widget;
+ QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(o);
+ Q_ASSERT(result != 0);
+ return result;
+}
+
+void PromotionTaskMenu::editPromotedWidgets(QDesignerFormEditorInterface *core, QWidget* parent) {
+ QDesignerLanguageExtension *lang = languageExtension(core);
+ // Show over non-promotable widget
+ QDialog *promotionEditor = 0;
+ if (lang)
+ lang->createPromotionDialog(core, parent);
+ if (!promotionEditor)
+ promotionEditor = new QDesignerPromotionDialog(core, parent);
+ promotionEditor->exec();
+ delete promotionEditor;
+}
+
+void PromotionTaskMenu::slotEditSignalsSlots()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+ SignalSlotDialog::editPromotedClass(fw->core(), m_widget, fw);
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/promotiontaskmenu_p.h b/tools/designer/src/lib/shared/promotiontaskmenu_p.h
new file mode 100644
index 0000000..223ce48
--- /dev/null
+++ b/tools/designer/src/lib/shared/promotiontaskmenu_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 PROMOTIONTASKMENU_H
+#define PROMOTIONTASKMENU_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerFormEditorInterface;
+
+class QAction;
+class QMenu;
+class QWidget;
+class QSignalMapper;
+
+namespace qdesigner_internal {
+
+// A helper class for creating promotion context menus and handling promotion actions.
+
+class QDESIGNER_SHARED_EXPORT PromotionTaskMenu: public QObject
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ ModeSingleWidget,
+ ModeManagedMultiSelection,
+ ModeUnmanagedMultiSelection
+ };
+
+ explicit PromotionTaskMenu(QWidget *widget,Mode mode = ModeManagedMultiSelection, QObject *parent = 0);
+
+ Mode mode() const;
+ void setMode(Mode m);
+
+ void setWidget(QWidget *widget);
+
+ // Set menu labels
+ void setPromoteLabel(const QString &promoteLabel);
+ void setEditPromoteToLabel(const QString &promoteEditLabel);
+ // Defaults to "Demote to %1".arg(class).
+ void setDemoteLabel(const QString &demoteLabel);
+
+ typedef QList<QAction*> ActionList;
+
+ enum AddFlags { LeadingSeparator = 1, TrailingSeparator = 2, SuppressGlobalEdit = 4};
+
+ // Adds a list of promotion actions according to the current promotion state of the widget.
+ void addActions(QDesignerFormWindowInterface *fw, unsigned flags, ActionList &actionList);
+ // Convenience that finds the form window.
+ void addActions(unsigned flags, ActionList &actionList);
+
+ void addActions(QDesignerFormWindowInterface *fw, unsigned flags, QMenu *menu);
+ void addActions(unsigned flags, QMenu *menu);
+
+ // Pop up the editor in a global context.
+ static void editPromotedWidgets(QDesignerFormEditorInterface *core, QWidget* parent);
+
+private slots:
+ void slotPromoteToCustomWidget(const QString &customClassName);
+ void slotDemoteFromCustomWidget();
+ void slotEditPromotedWidgets();
+ void slotEditPromoteTo();
+ void slotEditSignalsSlots();
+
+private:
+ void promoteTo(QDesignerFormWindowInterface *fw, const QString &customClassName);
+
+ enum PromotionState { NotApplicable, NoHomogenousSelection, CanPromote, CanDemote };
+ PromotionState createPromotionActions(QDesignerFormWindowInterface *formWindow);
+ QDesignerFormWindowInterface *formWindow() const;
+
+ typedef QList<QPointer<QWidget> > PromotionSelectionList;
+ PromotionSelectionList promotionSelectionList(QDesignerFormWindowInterface *formWindow) const;
+
+ Mode m_mode;
+
+ QPointer<QWidget> m_widget;
+
+ QSignalMapper *m_promotionMapper;
+ // Per-Widget actions
+ QList<QAction *> m_promotionActions;
+
+ QAction *m_globalEditAction;
+ QAction *m_EditPromoteToAction;
+ QAction *m_EditSignalsSlotsAction;
+
+ QString m_promoteLabel;
+ QString m_demoteLabel;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // PROMOTIONTASKMENU_H
diff --git a/tools/designer/src/lib/shared/propertylineedit.cpp b/tools/designer/src/lib/shared/propertylineedit.cpp
new file mode 100644
index 0000000..a3b1efa
--- /dev/null
+++ b/tools/designer/src/lib/shared/propertylineedit.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 "propertylineedit_p.h"
+
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMenu>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+ PropertyLineEdit::PropertyLineEdit(QWidget *parent) :
+ QLineEdit(parent), m_wantNewLine(false)
+ {
+ }
+
+ bool PropertyLineEdit::event(QEvent *e)
+ {
+ // handle 'Select all' here as it is not done in the QLineEdit
+ if (e->type() == QEvent::ShortcutOverride && !isReadOnly()) {
+ QKeyEvent* ke = static_cast<QKeyEvent*> (e);
+ if (ke->modifiers() & Qt::ControlModifier) {
+ if(ke->key() == Qt::Key_A) {
+ ke->accept();
+ return true;
+ }
+ }
+ }
+ return QLineEdit::event(e);
+ }
+
+ void PropertyLineEdit::insertNewLine() {
+ insertText(QLatin1String("\\n"));
+ }
+
+ void PropertyLineEdit::insertText(const QString &text) {
+ // position cursor after new text and grab focus
+ const int oldCursorPosition = cursorPosition ();
+ insert(text);
+ setCursorPosition (oldCursorPosition + text.length());
+ setFocus(Qt::OtherFocusReason);
+ }
+
+ void PropertyLineEdit::contextMenuEvent(QContextMenuEvent *event) {
+ QMenu *menu = createStandardContextMenu ();
+
+ if (m_wantNewLine) {
+ menu->addSeparator();
+ QAction* nlAction = menu->addAction(tr("Insert line break"));
+ connect(nlAction, SIGNAL(triggered()), this, SLOT(insertNewLine()));
+ }
+
+ menu->exec(event->globalPos());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/propertylineedit_p.h b/tools/designer/src/lib/shared/propertylineedit_p.h
new file mode 100644
index 0000000..42f0b3c
--- /dev/null
+++ b/tools/designer/src/lib/shared/propertylineedit_p.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$
+**
+****************************************************************************/
+
+//
+// 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 PROPERTYLINEEDIT_H
+#define PROPERTYLINEEDIT_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QLineEdit>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+ // A line edit with a special context menu allowing for adding (escaped) new lines
+ class PropertyLineEdit : public QLineEdit {
+ Q_OBJECT
+ public:
+ explicit PropertyLineEdit(QWidget *parent);
+ void setWantNewLine(bool nl) { m_wantNewLine = nl; }
+ bool wantNewLine() const { return m_wantNewLine; }
+
+ bool event(QEvent *e);
+ protected:
+ void contextMenuEvent (QContextMenuEvent *event );
+ private slots:
+ void insertNewLine();
+ private:
+ void insertText(const QString &);
+ bool m_wantNewLine;
+ };
+}
+
+QT_END_NAMESPACE
+
+#endif // PROPERTYLINEEDIT_H
diff --git a/tools/designer/src/lib/shared/qdesigner_command.cpp b/tools/designer/src/lib/shared/qdesigner_command.cpp
new file mode 100644
index 0000000..81d5917
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_command.cpp
@@ -0,0 +1,2968 @@
+/****************************************************************************
+**
+** 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_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "qdesigner_utils_p.h"
+#include "layout_p.h"
+#include "qlayout_widget_p.h"
+#include "qdesigner_widget_p.h"
+#include "qdesigner_menu_p.h"
+#include "shared_enums_p.h"
+#include "metadatabase_p.h"
+#include "formwindowbase_p.h"
+#include <abstractformbuilder.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerActionEditorInterface>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerLayoutDecorationExtension>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QDesignerObjectInspectorInterface>
+#include <QtDesigner/QDesignerIntegrationInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtCore/qdebug.h>
+#include <QtCore/QTextStream>
+#include <QtCore/QQueue>
+
+#include <QtGui/QMenuBar>
+#include <QtGui/QStatusBar>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolBox>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QTabWidget>
+#include <QtGui/QTableWidget>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QListWidget>
+#include <QtGui/QComboBox>
+#include <QtGui/QSplitter>
+#include <QtGui/QDockWidget>
+#include <QtGui/QMainWindow>
+#include <QtGui/QWizardPage>
+#include <QtGui/QApplication>
+#include <QtGui/QFormLayout>
+
+Q_DECLARE_METATYPE(QWidgetList)
+
+QT_BEGIN_NAMESPACE
+
+static inline void setPropertySheetWindowTitle(const QDesignerFormEditorInterface *core, QObject *o, const QString &t)
+{
+ if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), o)) {
+ const int idx = sheet->indexOf(QLatin1String("windowTitle"));
+ if (idx != -1) {
+ sheet->setProperty(idx, t);
+ sheet->setChanged(idx, true);
+ }
+ }
+}
+
+namespace qdesigner_internal {
+
+// Helpers for the dynamic properties that store Z/Widget order
+static const char *widgetOrderPropertyC = "_q_widgetOrder";
+static const char *zOrderPropertyC = "_q_zOrder";
+
+static void addToWidgetListDynamicProperty(QWidget *parentWidget, QWidget *widget, const char *name, int index = -1)
+{
+ QWidgetList list = qVariantValue<QWidgetList>(parentWidget->property(name));
+ list.removeAll(widget);
+ if (index >= 0 && index < list.size()) {
+ list.insert(index, widget);
+ } else {
+ list.append(widget);
+ }
+ parentWidget->setProperty(name, qVariantFromValue(list));
+}
+
+static int removeFromWidgetListDynamicProperty(QWidget *parentWidget, QWidget *widget, const char *name)
+{
+ QWidgetList list = qVariantValue<QWidgetList>(parentWidget->property(name));
+ const int firstIndex = list.indexOf(widget);
+ if (firstIndex != -1) {
+ list.removeAll(widget);
+ parentWidget->setProperty(name, qVariantFromValue(list));
+ }
+ return firstIndex;
+}
+
+// ---- InsertWidgetCommand ----
+InsertWidgetCommand::InsertWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_insertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode),
+ m_layoutHelper(0),
+ m_widgetWasManaged(false)
+{
+}
+
+InsertWidgetCommand::~InsertWidgetCommand()
+{
+ delete m_layoutHelper;
+}
+
+void InsertWidgetCommand::init(QWidget *widget, bool already_in_form, int layoutRow, int layoutColumn)
+{
+ m_widget = widget;
+
+ setText(QApplication::translate("Command", "Insert '%1'").arg(widget->objectName()));
+
+ QWidget *parentWidget = m_widget->parentWidget();
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
+
+ m_insertMode = deco ? deco->currentInsertMode() : QDesignerLayoutDecorationExtension::InsertWidgetMode;
+ if (layoutRow >= 0 && layoutColumn >= 0) {
+ m_cell.first = layoutRow;
+ m_cell.second = layoutColumn;
+ } else {
+ m_cell = deco ? deco->currentCell() : qMakePair(0, 0);
+ }
+ m_widgetWasManaged = already_in_form;
+}
+
+static void recursiveUpdate(QWidget *w)
+{
+ w->update();
+
+ const QObjectList &l = w->children();
+ const QObjectList::const_iterator cend = l.end();
+ for ( QObjectList::const_iterator it = l.begin(); it != cend; ++it) {
+ if (QWidget *w = qobject_cast<QWidget*>(*it))
+ recursiveUpdate(w);
+ }
+}
+
+void InsertWidgetCommand::redo()
+{
+ QWidget *parentWidget = m_widget->parentWidget();
+ Q_ASSERT(parentWidget);
+
+ addToWidgetListDynamicProperty(parentWidget, m_widget, widgetOrderPropertyC);
+ addToWidgetListDynamicProperty(parentWidget, m_widget, zOrderPropertyC);
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
+
+ if (deco != 0) {
+ const LayoutInfo::Type type = LayoutInfo::layoutType(core, LayoutInfo::managedLayout(core, parentWidget));
+ m_layoutHelper = LayoutHelper::createLayoutHelper(type);
+ m_layoutHelper->pushState(core, parentWidget);
+ if (type == LayoutInfo::Grid) {
+ switch (m_insertMode) {
+ case QDesignerLayoutDecorationExtension::InsertRowMode: {
+ deco->insertRow(m_cell.first);
+ } break;
+
+ case QDesignerLayoutDecorationExtension::InsertColumnMode: {
+ deco->insertColumn(m_cell.second);
+ } break;
+
+ default: break;
+ } // end switch
+ }
+ deco->insertWidget(m_widget, m_cell);
+ }
+
+ if (!m_widgetWasManaged)
+ formWindow()->manageWidget(m_widget);
+ m_widget->show();
+ formWindow()->emitSelectionChanged();
+
+ if (parentWidget && parentWidget->layout()) {
+ recursiveUpdate(parentWidget);
+ parentWidget->layout()->invalidate();
+ }
+
+ refreshBuddyLabels();
+}
+
+void InsertWidgetCommand::undo()
+{
+ QWidget *parentWidget = m_widget->parentWidget();
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
+
+ if (deco) {
+ deco->removeWidget(m_widget);
+ m_layoutHelper->popState(core, parentWidget);
+ }
+
+ if (!m_widgetWasManaged) {
+ formWindow()->unmanageWidget(m_widget);
+ m_widget->hide();
+ }
+
+ removeFromWidgetListDynamicProperty(parentWidget, m_widget, widgetOrderPropertyC);
+ removeFromWidgetListDynamicProperty(parentWidget, m_widget, zOrderPropertyC);
+
+ formWindow()->emitSelectionChanged();
+
+ refreshBuddyLabels();
+}
+
+void InsertWidgetCommand::refreshBuddyLabels()
+{
+ typedef QList<QLabel*> LabelList;
+
+ const LabelList label_list = qFindChildren<QLabel*>(formWindow());
+ if (label_list.empty())
+ return;
+
+ const QString buddyProperty = QLatin1String("buddy");
+ const QByteArray objectNameU8 = m_widget->objectName().toUtf8();
+ // Re-set the buddy (The sheet locates the object by name and sets it)
+ const LabelList::const_iterator cend = label_list.constEnd();
+ for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) {
+ if (QDesignerPropertySheetExtension* sheet = propertySheet(*it)) {
+ const int idx = sheet->indexOf(buddyProperty);
+ if (idx != -1) {
+ const QVariant value = sheet->property(idx);
+ if (value.toByteArray() == objectNameU8)
+ sheet->setProperty(idx, value);
+ }
+ }
+ }
+}
+
+// ---- ChangeZOrderCommand ----
+ChangeZOrderCommand::ChangeZOrderCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow)
+{
+}
+
+void ChangeZOrderCommand::init(QWidget *widget)
+{
+ Q_ASSERT(widget);
+
+ m_widget = widget;
+
+ setText(QApplication::translate("Command", "Change Z-order of '%1'").arg(widget->objectName()));
+
+ m_oldParentZOrder = qVariantValue<QWidgetList>(widget->parentWidget()->property("_q_zOrder"));
+ const int index = m_oldParentZOrder.indexOf(m_widget);
+ if (index != -1 && index + 1 < m_oldParentZOrder.count())
+ m_oldPreceding = m_oldParentZOrder.at(index + 1);
+}
+
+void ChangeZOrderCommand::redo()
+{
+ m_widget->parentWidget()->setProperty("_q_zOrder", qVariantFromValue(reorderWidget(m_oldParentZOrder, m_widget)));
+
+ reorder(m_widget);
+}
+
+void ChangeZOrderCommand::undo()
+{
+ m_widget->parentWidget()->setProperty("_q_zOrder", qVariantFromValue(m_oldParentZOrder));
+
+ if (m_oldPreceding)
+ m_widget->stackUnder(m_oldPreceding);
+ else
+ m_widget->raise();
+}
+
+// ---- RaiseWidgetCommand ----
+RaiseWidgetCommand::RaiseWidgetCommand(QDesignerFormWindowInterface *formWindow)
+ : ChangeZOrderCommand(formWindow)
+{
+}
+
+void RaiseWidgetCommand::init(QWidget *widget)
+{
+ ChangeZOrderCommand::init(widget);
+ setText(QApplication::translate("Command", "Raise '%1'").arg(widget->objectName()));
+}
+
+QWidgetList RaiseWidgetCommand::reorderWidget(const QWidgetList &list, QWidget *widget) const
+{
+ QWidgetList l = list;
+ l.removeAll(widget);
+ l.append(widget);
+ return l;
+}
+
+void RaiseWidgetCommand::reorder(QWidget *widget) const
+{
+ widget->raise();
+}
+
+// ---- LowerWidgetCommand ----
+LowerWidgetCommand::LowerWidgetCommand(QDesignerFormWindowInterface *formWindow)
+ : ChangeZOrderCommand(formWindow)
+{
+}
+
+QWidgetList LowerWidgetCommand::reorderWidget(const QWidgetList &list, QWidget *widget) const
+{
+ QWidgetList l = list;
+ l.removeAll(widget);
+ l.prepend(widget);
+ return l;
+}
+
+void LowerWidgetCommand::init(QWidget *widget)
+{
+ ChangeZOrderCommand::init(widget);
+ setText(QApplication::translate("Command", "Lower '%1'").arg(widget->objectName()));
+}
+
+void LowerWidgetCommand::reorder(QWidget *widget) const
+{
+ widget->lower();
+}
+
+// ---- ManageWidgetCommandHelper
+ManageWidgetCommandHelper::ManageWidgetCommandHelper() :
+ m_widget(0)
+{
+}
+
+void ManageWidgetCommandHelper::init(const QDesignerFormWindowInterface *fw, QWidget *widget)
+{
+ m_widget = widget;
+ m_managedChildren.clear();
+
+ const QWidgetList children = qFindChildren<QWidget *>(m_widget);
+ if (children.empty())
+ return;
+
+ m_managedChildren.reserve(children.size());
+ const QWidgetList::const_iterator lcend = children.constEnd();
+ for (QWidgetList::const_iterator it = children.constBegin(); it != lcend; ++it)
+ if (fw->isManaged(*it))
+ m_managedChildren.push_back(*it);
+}
+
+void ManageWidgetCommandHelper::init(QWidget *widget, const WidgetVector &managedChildren)
+{
+ m_widget = widget;
+ m_managedChildren = managedChildren;
+}
+
+void ManageWidgetCommandHelper::manage(QDesignerFormWindowInterface *fw)
+{
+ // Manage the managed children after parent
+ fw->manageWidget(m_widget);
+ if (!m_managedChildren.empty()) {
+ const WidgetVector::const_iterator lcend = m_managedChildren.constEnd();
+ for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it)
+ fw->manageWidget(*it);
+ }
+}
+
+void ManageWidgetCommandHelper::unmanage(QDesignerFormWindowInterface *fw)
+{
+ // Unmanage the managed children first
+ if (!m_managedChildren.empty()) {
+ const WidgetVector::const_iterator lcend = m_managedChildren.constEnd();
+ for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it)
+ fw->unmanageWidget(*it);
+ }
+ fw->unmanageWidget(m_widget);
+}
+
+// ---- DeleteWidgetCommand ----
+DeleteWidgetCommand::DeleteWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_layoutType(LayoutInfo::NoLayout),
+ m_layoutHelper(0),
+ m_flags(0),
+ m_splitterIndex(-1),
+ m_layoutSimplified(false),
+ m_formItem(0),
+ m_tabOrderIndex(-1),
+ m_widgetOrderIndex(-1),
+ m_zOrderIndex(-1)
+{
+}
+
+DeleteWidgetCommand::~DeleteWidgetCommand()
+{
+ delete m_layoutHelper;
+}
+
+void DeleteWidgetCommand::init(QWidget *widget, unsigned flags)
+{
+ m_widget = widget;
+ m_parentWidget = widget->parentWidget();
+ m_geometry = widget->geometry();
+ m_flags = flags;
+ m_layoutType = LayoutInfo::NoLayout;
+ m_splitterIndex = -1;
+ bool isManaged; // Check for a managed layout
+ QLayout *layout;
+ m_layoutType = LayoutInfo::laidoutWidgetType(formWindow()->core(), m_widget, &isManaged, &layout);
+ if (!isManaged)
+ m_layoutType = LayoutInfo::NoLayout;
+ switch (m_layoutType) {
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter: {
+ QSplitter *splitter = qobject_cast<QSplitter *>(m_parentWidget);
+ Q_ASSERT(splitter);
+ m_splitterIndex = splitter->indexOf(widget);
+ }
+ break;
+ case LayoutInfo::NoLayout:
+ break;
+ default:
+ m_layoutHelper = LayoutHelper::createLayoutHelper(m_layoutType);
+ m_layoutPosition = m_layoutHelper->itemInfo(layout, m_widget);
+ break;
+ }
+
+ m_formItem = formWindow()->core()->metaDataBase()->item(formWindow());
+ m_tabOrderIndex = m_formItem->tabOrder().indexOf(widget);
+
+ // Build the list of managed children
+ m_manageHelper.init(formWindow(), m_widget);
+
+ setText(QApplication::translate("Command", "Delete '%1'").arg(widget->objectName()));
+}
+
+void DeleteWidgetCommand::redo()
+{
+ formWindow()->clearSelection();
+ QDesignerFormEditorInterface *core = formWindow()->core();
+
+ if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_parentWidget)) {
+ const int count = c->count();
+ for (int i=0; i<count; ++i) {
+ if (c->widget(i) == m_widget) {
+ c->remove(i);
+ return;
+ }
+ }
+ }
+
+ m_widgetOrderIndex = removeFromWidgetListDynamicProperty(m_parentWidget, m_widget, widgetOrderPropertyC);
+ m_zOrderIndex = removeFromWidgetListDynamicProperty(m_parentWidget, m_widget, zOrderPropertyC);
+
+ if (QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), m_parentWidget))
+ deco->removeWidget(m_widget);
+
+ if (m_layoutHelper)
+ switch (m_layoutType) {
+ case LayoutInfo::NoLayout:
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter:
+ break;
+ default:
+ // Attempt to simplify grids if a row/column becomes empty
+ m_layoutSimplified = (m_flags & DoNotSimplifyLayout) ? false : m_layoutHelper->canSimplify(core, m_parentWidget, m_layoutPosition);
+ if (m_layoutSimplified) {
+ m_layoutHelper->pushState(core, m_parentWidget);
+ m_layoutHelper->simplify(core, m_parentWidget, m_layoutPosition);
+ }
+ break;
+ }
+
+ if (!(m_flags & DoNotUnmanage))
+ m_manageHelper.unmanage(formWindow());
+
+ m_widget->setParent(formWindow());
+ m_widget->hide();
+
+ if (m_tabOrderIndex != -1) {
+ QList<QWidget*> tab_order = m_formItem->tabOrder();
+ tab_order.removeAt(m_tabOrderIndex);
+ m_formItem->setTabOrder(tab_order);
+ }
+}
+
+void DeleteWidgetCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ formWindow()->clearSelection();
+
+ m_widget->setParent(m_parentWidget);
+
+ if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_parentWidget)) {
+ c->addWidget(m_widget);
+ return;
+ }
+
+ addToWidgetListDynamicProperty(m_parentWidget, m_widget, widgetOrderPropertyC, m_widgetOrderIndex);
+ addToWidgetListDynamicProperty(m_parentWidget, m_widget, zOrderPropertyC, m_zOrderIndex);
+
+ m_widget->setGeometry(m_geometry);
+
+ if (!(m_flags & DoNotUnmanage))
+ m_manageHelper.manage(formWindow());
+ // ### set up alignment
+ switch (m_layoutType) {
+ case LayoutInfo::NoLayout:
+ break;
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter: {
+ QSplitter *splitter = qobject_cast<QSplitter *>(m_widget->parent());
+ Q_ASSERT(splitter);
+ splitter->insertWidget(m_splitterIndex, m_widget);
+ } break;
+ default: {
+ Q_ASSERT(m_layoutHelper);
+ if (m_layoutSimplified)
+ m_layoutHelper->popState(core, m_parentWidget);
+ QLayout *layout = LayoutInfo::managedLayout(core, m_parentWidget);
+ Q_ASSERT(m_layoutType == LayoutInfo::layoutType(core, layout));
+ m_layoutHelper->insertWidget(layout, m_layoutPosition, m_widget);
+ }
+ break;
+ }
+
+ m_widget->show();
+
+ if (m_tabOrderIndex != -1) {
+ QList<QWidget*> tab_order = m_formItem->tabOrder();
+ tab_order.insert(m_tabOrderIndex, m_widget);
+ m_formItem->setTabOrder(tab_order);
+ }
+}
+
+// ---- ReparentWidgetCommand ----
+ReparentWidgetCommand::ReparentWidgetCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow)
+{
+}
+
+void ReparentWidgetCommand::init(QWidget *widget, QWidget *parentWidget)
+{
+ Q_ASSERT(widget);
+
+ m_widget = widget;
+ m_oldParentWidget = widget->parentWidget();
+ m_newParentWidget = parentWidget;
+
+ m_oldPos = m_widget->pos();
+ m_newPos = m_newParentWidget->mapFromGlobal(m_oldParentWidget->mapToGlobal(m_oldPos));
+
+ setText(QApplication::translate("Command", "Reparent '%1'").arg(widget->objectName()));
+
+ m_oldParentList = qVariantValue<QWidgetList>(m_oldParentWidget->property("_q_widgetOrder"));
+ m_oldParentZOrder = qVariantValue<QWidgetList>(m_oldParentWidget->property("_q_zOrder"));
+}
+
+void ReparentWidgetCommand::redo()
+{
+ m_widget->setParent(m_newParentWidget);
+ m_widget->move(m_newPos);
+
+ QWidgetList oldList = m_oldParentList;
+ oldList.removeAll(m_widget);
+ m_oldParentWidget->setProperty("_q_widgetOrder", qVariantFromValue(oldList));
+
+ QWidgetList newList = qVariantValue<QWidgetList>(m_newParentWidget->property("_q_widgetOrder"));
+ newList.append(m_widget);
+ m_newParentWidget->setProperty("_q_widgetOrder", qVariantFromValue(newList));
+
+ QWidgetList oldZOrder = m_oldParentZOrder;
+ oldZOrder.removeAll(m_widget);
+ m_oldParentWidget->setProperty("_q_zOrder", qVariantFromValue(oldZOrder));
+
+ QWidgetList newZOrder = qVariantValue<QWidgetList>(m_newParentWidget->property("_q_zOrder"));
+ newZOrder.append(m_widget);
+ m_newParentWidget->setProperty("_q_zOrder", qVariantFromValue(newZOrder));
+
+ m_widget->show();
+ core()->objectInspector()->setFormWindow(formWindow());
+}
+
+void ReparentWidgetCommand::undo()
+{
+ m_widget->setParent(m_oldParentWidget);
+ m_widget->move(m_oldPos);
+
+ m_oldParentWidget->setProperty("_q_widgetOrder", qVariantFromValue(m_oldParentList));
+
+ QWidgetList newList = qVariantValue<QWidgetList>(m_newParentWidget->property("_q_widgetOrder"));
+ newList.removeAll(m_widget);
+ m_newParentWidget->setProperty("_q_widgetOrder", qVariantFromValue(newList));
+
+ m_oldParentWidget->setProperty("_q_zOrder", qVariantFromValue(m_oldParentZOrder));
+
+ QWidgetList newZOrder = qVariantValue<QWidgetList>(m_newParentWidget->property("_q_zOrder"));
+ m_newParentWidget->setProperty("_q_zOrder", qVariantFromValue(newZOrder));
+
+ m_widget->show();
+ core()->objectInspector()->setFormWindow(formWindow());
+}
+
+PromoteToCustomWidgetCommand::PromoteToCustomWidgetCommand
+ (QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Promote to custom widget"), formWindow)
+{
+}
+
+void PromoteToCustomWidgetCommand::init(const WidgetList &widgets,const QString &customClassName)
+{
+ m_widgets = widgets;
+ m_customClassName = customClassName;
+}
+
+void PromoteToCustomWidgetCommand::redo()
+{
+ foreach (QWidget *w, m_widgets) {
+ if (w)
+ promoteWidget(core(), w, m_customClassName);
+ }
+ updateSelection();
+}
+
+void PromoteToCustomWidgetCommand::updateSelection()
+{
+ // Update class names in ObjectInspector, PropertyEditor
+ QDesignerFormWindowInterface *fw = formWindow();
+ QDesignerFormEditorInterface *core = fw->core();
+ core->objectInspector()->setFormWindow(fw);
+ if (QObject *o = core->propertyEditor()->object())
+ core->propertyEditor()->setObject(o);
+}
+
+void PromoteToCustomWidgetCommand::undo()
+{
+ foreach (QWidget *w, m_widgets) {
+ if (w)
+ demoteWidget(core(), w);
+ }
+ updateSelection();
+}
+
+// ---- DemoteFromCustomWidgetCommand ----
+
+DemoteFromCustomWidgetCommand::DemoteFromCustomWidgetCommand
+ (QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Demote from custom widget"), formWindow),
+ m_promote_cmd(formWindow)
+{
+}
+
+void DemoteFromCustomWidgetCommand::init(const WidgetList &promoted)
+{
+ m_promote_cmd.init(promoted, promotedCustomClassName(core(), promoted.front()));
+}
+
+void DemoteFromCustomWidgetCommand::redo()
+{
+ m_promote_cmd.undo();
+}
+
+void DemoteFromCustomWidgetCommand::undo()
+{
+ m_promote_cmd.redo();
+}
+
+// ---------- CursorSelectionState
+CursorSelectionState::CursorSelectionState()
+{
+}
+
+void CursorSelectionState::save(const QDesignerFormWindowInterface *formWindow)
+{
+ const QDesignerFormWindowCursorInterface *cursor = formWindow->cursor();
+ m_selection.clear();
+ m_current = cursor->current();
+ if (cursor->hasSelection()) {
+ const int count = cursor->selectedWidgetCount();
+ for(int i = 0; i < count; i++)
+ m_selection.push_back(cursor->selectedWidget(i));
+ }
+}
+
+void CursorSelectionState::restore(QDesignerFormWindowInterface *formWindow) const
+{
+ if (m_selection.empty()) {
+ formWindow->clearSelection(true);
+ } else {
+ // Select current as last
+ formWindow->clearSelection(false);
+ const WidgetPointerList::const_iterator cend = m_selection.constEnd();
+ for (WidgetPointerList::const_iterator it = m_selection.constBegin(); it != cend; ++it)
+ if (QWidget *w = *it)
+ if (w != m_current)
+ formWindow->selectWidget(*it, true);
+ if (m_current)
+ formWindow->selectWidget(m_current, true);
+ }
+}
+
+// ---- LayoutCommand ----
+
+LayoutCommand::LayoutCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_setup(false)
+{
+}
+
+LayoutCommand::~LayoutCommand()
+{
+ delete m_layout;
+}
+
+void LayoutCommand::init(QWidget *parentWidget, const QWidgetList &widgets,
+ LayoutInfo::Type layoutType, QWidget *layoutBase,
+ bool reparentLayoutWidget)
+{
+ m_parentWidget = parentWidget;
+ m_widgets = widgets;
+ formWindow()->simplifySelection(&m_widgets);
+ m_layout = Layout::createLayout(widgets, parentWidget, formWindow(), layoutBase, layoutType);
+ m_layout->setReparentLayoutWidget(reparentLayoutWidget);
+
+ switch (layoutType) {
+ case LayoutInfo::Grid:
+ setText(QApplication::translate("Command", "Lay out using grid"));
+ break;
+ case LayoutInfo::VBox:
+ setText(QApplication::translate("Command", "Lay out vertically"));
+ break;
+ case LayoutInfo::HBox:
+ setText(QApplication::translate("Command", "Lay out horizontally"));
+ break;
+ default:
+ break;
+ }
+ // Delayed setup to avoid confusion in case we are chained
+ // with a BreakLayout in a morph layout macro
+ m_setup = false;
+}
+
+void LayoutCommand::redo()
+{
+ if (!m_setup) {
+ m_layout->setup();
+ m_cursorSelectionState.save(formWindow());
+ m_setup = true;
+ }
+ m_layout->doLayout();
+ core()->objectInspector()->setFormWindow(formWindow());
+}
+
+void LayoutCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+
+ QWidget *lb = m_layout->layoutBaseWidget();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), lb);
+ m_layout->undoLayout();
+ delete deco; // release the extension
+
+ // ### generalize (put in function)
+ if (!m_layoutBase && lb != 0 && !(qobject_cast<QLayoutWidget*>(lb) || qobject_cast<QSplitter*>(lb))) {
+ core->metaDataBase()->add(lb);
+ lb->show();
+ }
+ m_cursorSelectionState.restore(formWindow());
+ core->objectInspector()->setFormWindow(formWindow());
+}
+
+// ---- BreakLayoutCommand ----
+BreakLayoutCommand::BreakLayoutCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Break layout"), formWindow),
+ m_layoutHelper(0),
+ m_properties(0),
+ m_propertyMask(0)
+{
+}
+
+BreakLayoutCommand::~BreakLayoutCommand()
+{
+ delete m_layoutHelper;
+ delete m_layout;
+ delete m_properties;
+}
+
+const LayoutProperties *BreakLayoutCommand::layoutProperties() const
+{
+ return m_properties;
+}
+
+int BreakLayoutCommand::propertyMask() const
+{
+ return m_propertyMask;
+}
+
+void BreakLayoutCommand::init(const QWidgetList &widgets, QWidget *layoutBase, bool reparentLayoutWidget)
+{
+ enum Type { SplitterLayout, LayoutHasMarginSpacing, LayoutHasState };
+
+ const QDesignerFormEditorInterface *core = formWindow()->core();
+ m_widgets = widgets;
+ m_layoutBase = core->widgetFactory()->containerOfWidget(layoutBase);
+ QLayout *layoutToBeBroken;
+ const LayoutInfo::Type layoutType = LayoutInfo::managedLayoutType(core, m_layoutBase, &layoutToBeBroken);
+ m_layout = Layout::createLayout(widgets, m_layoutBase, formWindow(), layoutBase, layoutType);
+ m_layout->setReparentLayoutWidget(reparentLayoutWidget);
+
+ Type type = LayoutHasState;
+ switch (layoutType) {
+ case LayoutInfo::NoLayout:
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter:
+ type = SplitterLayout;
+ break;
+ case LayoutInfo::HBox:
+ case LayoutInfo::VBox: // Margin/spacing need to be saved
+ type = LayoutHasMarginSpacing;
+ break;
+ default: // Margin/spacing need to be saved + has a state (empty rows/columns of a grid)
+ type = LayoutHasState;
+ break;
+ }
+ Q_ASSERT(m_layout != 0);
+ m_layout->sort();
+
+
+ if (type >= LayoutHasMarginSpacing) {
+ m_properties = new LayoutProperties;
+ m_propertyMask = m_properties->fromPropertySheet(core, layoutToBeBroken, LayoutProperties::AllProperties);
+ }
+ if (type >= LayoutHasState)
+ m_layoutHelper = LayoutHelper::createLayoutHelper(layoutType);
+ m_cursorSelectionState.save(formWindow());
+}
+
+void BreakLayoutCommand::redo()
+{
+ if (!m_layout)
+ return;
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QWidget *lb = m_layout->layoutBaseWidget();
+ QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), lb);
+ formWindow()->clearSelection(false);
+ if (m_layoutHelper)
+ m_layoutHelper->pushState(core, m_layoutBase);
+ m_layout->breakLayout();
+ delete deco; // release the extension
+
+ foreach (QWidget *widget, m_widgets) {
+ widget->resize(widget->size().expandedTo(QSize(16, 16)));
+ }
+ // Update unless we are in an intermediate state of morphing layout
+ // in which a QLayoutWidget will have no layout at all.
+ if (m_layout->reparentLayoutWidget())
+ core->objectInspector()->setFormWindow(formWindow());
+}
+
+void BreakLayoutCommand::undo()
+{
+ if (!m_layout)
+ return;
+
+ formWindow()->clearSelection(false);
+ m_layout->doLayout();
+ if (m_layoutHelper)
+ m_layoutHelper->popState(formWindow()->core(), m_layoutBase);
+
+ QLayout *layoutToRestored = LayoutInfo::managedLayout(formWindow()->core(), m_layoutBase);
+ if (m_properties && m_layoutBase && layoutToRestored)
+ m_properties->toPropertySheet(formWindow()->core(), layoutToRestored, m_propertyMask);
+ m_cursorSelectionState.restore(formWindow());
+ core()->objectInspector()->setFormWindow(formWindow());
+}
+// ---- SimplifyLayoutCommand
+SimplifyLayoutCommand::SimplifyLayoutCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Simplify Grid Layout"), formWindow),
+ m_area(0, 0, 32767, 32767),
+ m_layoutBase(0),
+ m_layoutHelper(0),
+ m_layoutSimplified(false)
+{
+}
+
+SimplifyLayoutCommand::~SimplifyLayoutCommand()
+{
+ delete m_layoutHelper;
+}
+
+bool SimplifyLayoutCommand::canSimplify(QDesignerFormEditorInterface *core, const QWidget *w, int *layoutType)
+{
+ if (!w)
+ return false;
+ QLayout *layout;
+ const LayoutInfo::Type type = LayoutInfo::managedLayoutType(core, w, &layout);
+ if (layoutType)
+ *layoutType = type;
+ if (!layout)
+ return false;
+ switch (type) { // Known negatives
+ case LayoutInfo::NoLayout:
+ case LayoutInfo::UnknownLayout:
+ case LayoutInfo::HSplitter:
+ case LayoutInfo::VSplitter:
+ case LayoutInfo::HBox:
+ case LayoutInfo::VBox:
+ return false;
+ default:
+ break;
+ }
+ switch (type) {
+ case LayoutInfo::Grid:
+ return QLayoutSupport::canSimplifyQuickCheck(qobject_cast<QGridLayout*>(layout));
+ case LayoutInfo::Form:
+ return QLayoutSupport::canSimplifyQuickCheck(qobject_cast<const QFormLayout*>(layout));
+ default:
+ break;
+ }
+ return false;
+}
+
+bool SimplifyLayoutCommand::init(QWidget *layoutBase)
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ m_layoutSimplified = false;
+ int type;
+ if (canSimplify(core, layoutBase, &type)) {
+ m_layoutBase = layoutBase;
+ m_layoutHelper = LayoutHelper::createLayoutHelper(type);
+ m_layoutSimplified = m_layoutHelper->canSimplify(core, layoutBase, m_area);
+ }
+ return m_layoutSimplified;
+}
+
+void SimplifyLayoutCommand::redo()
+{
+ const QDesignerFormEditorInterface *core = formWindow()->core();
+ if (m_layoutSimplified) {
+ m_layoutHelper->pushState(core, m_layoutBase);
+ m_layoutHelper->simplify(core, m_layoutBase, m_area);
+ }
+}
+void SimplifyLayoutCommand::undo()
+{
+ if (m_layoutSimplified)
+ m_layoutHelper->popState(formWindow()->core(), m_layoutBase);
+}
+
+// ---- ToolBoxCommand ----
+ToolBoxCommand::ToolBoxCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_index(-1)
+{
+}
+
+ToolBoxCommand::~ToolBoxCommand()
+{
+}
+
+void ToolBoxCommand::init(QToolBox *toolBox)
+{
+ m_toolBox = toolBox;
+ m_index = m_toolBox->currentIndex();
+ m_widget = m_toolBox->widget(m_index);
+ m_itemText = m_toolBox->itemText(m_index);
+ m_itemIcon = m_toolBox->itemIcon(m_index);
+}
+
+void ToolBoxCommand::removePage()
+{
+ m_toolBox->removeItem(m_index);
+
+ m_widget->hide();
+ m_widget->setParent(formWindow());
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_toolBox, true);
+
+}
+
+void ToolBoxCommand::addPage()
+{
+ m_widget->setParent(m_toolBox);
+ m_toolBox->insertItem(m_index, m_widget, m_itemIcon, m_itemText);
+ m_toolBox->setCurrentIndex(m_index);
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(formWindow()->core()->extensionManager(), m_toolBox);
+ if (sheet) {
+ qdesigner_internal::PropertySheetStringValue itemText(m_itemText);
+ sheet->setProperty(sheet->indexOf(QLatin1String("currentItemText")), qVariantFromValue(itemText));
+ }
+
+ m_widget->show();
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_toolBox, true);
+}
+
+// ---- MoveToolBoxPageCommand ----
+MoveToolBoxPageCommand::MoveToolBoxPageCommand(QDesignerFormWindowInterface *formWindow) :
+ ToolBoxCommand(formWindow),
+ m_newIndex(-1),
+ m_oldIndex(-1)
+{
+}
+
+MoveToolBoxPageCommand::~MoveToolBoxPageCommand()
+{
+}
+
+void MoveToolBoxPageCommand::init(QToolBox *toolBox, QWidget *page, int newIndex)
+{
+ ToolBoxCommand::init(toolBox);
+ setText(QApplication::translate("Command", "Move Page"));
+
+ m_widget = page;
+ m_oldIndex = m_toolBox->indexOf(m_widget);
+ m_itemText = m_toolBox->itemText(m_oldIndex);
+ m_itemIcon = m_toolBox->itemIcon(m_oldIndex);
+ m_newIndex = newIndex;
+}
+
+void MoveToolBoxPageCommand::redo()
+{
+ m_toolBox->removeItem(m_oldIndex);
+ m_toolBox->insertItem(m_newIndex, m_widget, m_itemIcon, m_itemText);
+}
+
+void MoveToolBoxPageCommand::undo()
+{
+ m_toolBox->removeItem(m_newIndex);
+ m_toolBox->insertItem(m_oldIndex, m_widget, m_itemIcon, m_itemText);
+}
+
+// ---- DeleteToolBoxPageCommand ----
+DeleteToolBoxPageCommand::DeleteToolBoxPageCommand(QDesignerFormWindowInterface *formWindow)
+ : ToolBoxCommand(formWindow)
+{
+}
+
+DeleteToolBoxPageCommand::~DeleteToolBoxPageCommand()
+{
+}
+
+void DeleteToolBoxPageCommand::init(QToolBox *toolBox)
+{
+ ToolBoxCommand::init(toolBox);
+ setText(QApplication::translate("Command", "Delete Page"));
+}
+
+void DeleteToolBoxPageCommand::redo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+void DeleteToolBoxPageCommand::undo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+// ---- AddToolBoxPageCommand ----
+AddToolBoxPageCommand::AddToolBoxPageCommand(QDesignerFormWindowInterface *formWindow)
+ : ToolBoxCommand(formWindow)
+{
+}
+
+AddToolBoxPageCommand::~AddToolBoxPageCommand()
+{
+}
+
+void AddToolBoxPageCommand::init(QToolBox *toolBox)
+{
+ init(toolBox, InsertBefore);
+}
+
+void AddToolBoxPageCommand::init(QToolBox *toolBox, InsertionMode mode)
+{
+ m_toolBox = toolBox;
+
+ m_index = m_toolBox->currentIndex();
+ if (mode == InsertAfter)
+ m_index++;
+ m_widget = new QDesignerWidget(formWindow(), m_toolBox);
+ m_itemText = QApplication::translate("Command", "Page");
+ m_itemIcon = QIcon();
+ m_widget->setObjectName(QApplication::translate("Command", "page"));
+ formWindow()->ensureUniqueObjectName(m_widget);
+
+ setText(QApplication::translate("Command", "Insert Page"));
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->add(m_widget);
+}
+
+void AddToolBoxPageCommand::redo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+void AddToolBoxPageCommand::undo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+// ---- TabWidgetCommand ----
+TabWidgetCommand::TabWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_index(-1)
+{
+}
+
+TabWidgetCommand::~TabWidgetCommand()
+{
+}
+
+void TabWidgetCommand::init(QTabWidget *tabWidget)
+{
+ m_tabWidget = tabWidget;
+ m_index = m_tabWidget->currentIndex();
+ m_widget = m_tabWidget->widget(m_index);
+ m_itemText = m_tabWidget->tabText(m_index);
+ m_itemIcon = m_tabWidget->tabIcon(m_index);
+}
+
+void TabWidgetCommand::removePage()
+{
+ m_tabWidget->removeTab(m_index);
+
+ m_widget->hide();
+ m_widget->setParent(formWindow());
+ m_tabWidget->setCurrentIndex(qMin(m_index, m_tabWidget->count()));
+
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_tabWidget, true);
+}
+
+void TabWidgetCommand::addPage()
+{
+ m_widget->setParent(0);
+ m_tabWidget->insertTab(m_index, m_widget, m_itemIcon, m_itemText);
+ m_widget->show();
+ m_tabWidget->setCurrentIndex(m_index);
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(formWindow()->core()->extensionManager(), m_tabWidget);
+ if (sheet) {
+ qdesigner_internal::PropertySheetStringValue itemText(m_itemText);
+ sheet->setProperty(sheet->indexOf(QLatin1String("currentTabText")), qVariantFromValue(itemText));
+ }
+
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_tabWidget, true);
+}
+
+// ---- DeleteTabPageCommand ----
+DeleteTabPageCommand::DeleteTabPageCommand(QDesignerFormWindowInterface *formWindow)
+ : TabWidgetCommand(formWindow)
+{
+}
+
+DeleteTabPageCommand::~DeleteTabPageCommand()
+{
+}
+
+void DeleteTabPageCommand::init(QTabWidget *tabWidget)
+{
+ TabWidgetCommand::init(tabWidget);
+ setText(QApplication::translate("Command", "Delete Page"));
+}
+
+void DeleteTabPageCommand::redo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+void DeleteTabPageCommand::undo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+// ---- AddTabPageCommand ----
+AddTabPageCommand::AddTabPageCommand(QDesignerFormWindowInterface *formWindow)
+ : TabWidgetCommand(formWindow)
+{
+}
+
+AddTabPageCommand::~AddTabPageCommand()
+{
+}
+
+void AddTabPageCommand::init(QTabWidget *tabWidget)
+{
+ init(tabWidget, InsertBefore);
+}
+
+void AddTabPageCommand::init(QTabWidget *tabWidget, InsertionMode mode)
+{
+ m_tabWidget = tabWidget;
+
+ m_index = m_tabWidget->currentIndex();
+ if (mode == InsertAfter)
+ m_index++;
+ m_widget = new QDesignerWidget(formWindow(), m_tabWidget);
+ m_itemText = QApplication::translate("Command", "Page");
+ m_itemIcon = QIcon();
+ m_widget->setObjectName(QApplication::translate("Command", "tab"));
+ formWindow()->ensureUniqueObjectName(m_widget);
+
+ setText(QApplication::translate("Command", "Insert Page"));
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->add(m_widget);
+}
+
+void AddTabPageCommand::redo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+void AddTabPageCommand::undo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+// ---- MoveTabPageCommand ----
+MoveTabPageCommand::MoveTabPageCommand(QDesignerFormWindowInterface *formWindow) :
+ TabWidgetCommand(formWindow),
+ m_newIndex(-1),
+ m_oldIndex(-1)
+{
+}
+
+MoveTabPageCommand::~MoveTabPageCommand()
+{
+}
+
+void MoveTabPageCommand::init(QTabWidget *tabWidget, QWidget *page,
+ const QIcon &icon, const QString &label,
+ int index, int newIndex)
+{
+ TabWidgetCommand::init(tabWidget);
+ setText(QApplication::translate("Command", "Move Page"));
+
+ m_page = page;
+ m_newIndex = newIndex;
+ m_oldIndex = index;
+ m_label = label;
+ m_icon = icon;
+}
+
+void MoveTabPageCommand::redo()
+{
+ m_tabWidget->removeTab(m_oldIndex);
+ m_tabWidget->insertTab(m_newIndex, m_page, m_icon, m_label);
+ m_tabWidget->setCurrentIndex(m_newIndex);
+}
+
+void MoveTabPageCommand::undo()
+{
+ m_tabWidget->removeTab(m_newIndex);
+ m_tabWidget->insertTab(m_oldIndex, m_page, m_icon, m_label);
+ m_tabWidget->setCurrentIndex(m_oldIndex);
+}
+
+// ---- StackedWidgetCommand ----
+StackedWidgetCommand::StackedWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_index(-1)
+{
+}
+
+StackedWidgetCommand::~StackedWidgetCommand()
+{
+}
+
+void StackedWidgetCommand::init(QStackedWidget *stackedWidget)
+{
+ m_stackedWidget = stackedWidget;
+ m_index = m_stackedWidget->currentIndex();
+ m_widget = m_stackedWidget->widget(m_index);
+}
+
+void StackedWidgetCommand::removePage()
+{
+ m_stackedWidget->removeWidget(m_stackedWidget->widget(m_index));
+
+ m_widget->hide();
+ m_widget->setParent(formWindow());
+
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_stackedWidget, true);
+}
+
+void StackedWidgetCommand::addPage()
+{
+ m_stackedWidget->insertWidget(m_index, m_widget);
+
+ m_widget->show();
+ m_stackedWidget->setCurrentIndex(m_index);
+
+ formWindow()->clearSelection();
+ formWindow()->selectWidget(m_stackedWidget, true);
+}
+
+// ---- MoveStackedWidgetCommand ----
+MoveStackedWidgetCommand::MoveStackedWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ StackedWidgetCommand(formWindow),
+ m_newIndex(-1),
+ m_oldIndex(-1)
+{
+}
+
+MoveStackedWidgetCommand::~MoveStackedWidgetCommand()
+{
+}
+
+void MoveStackedWidgetCommand::init(QStackedWidget *stackedWidget, QWidget *page, int newIndex)
+{
+ StackedWidgetCommand::init(stackedWidget);
+ setText(QApplication::translate("Command", "Move Page"));
+
+ m_widget = page;
+ m_newIndex = newIndex;
+ m_oldIndex = m_stackedWidget->indexOf(m_widget);
+}
+
+void MoveStackedWidgetCommand::redo()
+{
+ m_stackedWidget->removeWidget(m_widget);
+ m_stackedWidget->insertWidget(m_newIndex, m_widget);
+}
+
+void MoveStackedWidgetCommand::undo()
+{
+ m_stackedWidget->removeWidget(m_widget);
+ m_stackedWidget->insertWidget(m_oldIndex, m_widget);
+}
+
+// ---- DeleteStackedWidgetPageCommand ----
+DeleteStackedWidgetPageCommand::DeleteStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow)
+ : StackedWidgetCommand(formWindow)
+{
+}
+
+DeleteStackedWidgetPageCommand::~DeleteStackedWidgetPageCommand()
+{
+}
+
+void DeleteStackedWidgetPageCommand::init(QStackedWidget *stackedWidget)
+{
+ StackedWidgetCommand::init(stackedWidget);
+ setText(QApplication::translate("Command", "Delete Page"));
+}
+
+void DeleteStackedWidgetPageCommand::redo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+void DeleteStackedWidgetPageCommand::undo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+// ---- AddStackedWidgetPageCommand ----
+AddStackedWidgetPageCommand::AddStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow)
+ : StackedWidgetCommand(formWindow)
+{
+}
+
+AddStackedWidgetPageCommand::~AddStackedWidgetPageCommand()
+{
+}
+
+void AddStackedWidgetPageCommand::init(QStackedWidget *stackedWidget)
+{
+ init(stackedWidget, InsertBefore);
+}
+
+void AddStackedWidgetPageCommand::init(QStackedWidget *stackedWidget, InsertionMode mode)
+{
+ m_stackedWidget = stackedWidget;
+
+ m_index = m_stackedWidget->currentIndex();
+ if (mode == InsertAfter)
+ m_index++;
+ m_widget = new QDesignerWidget(formWindow(), m_stackedWidget);
+ m_widget->setObjectName(QApplication::translate("Command", "page"));
+ formWindow()->ensureUniqueObjectName(m_widget);
+
+ setText(QApplication::translate("Command", "Insert Page"));
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->add(m_widget);
+}
+
+void AddStackedWidgetPageCommand::redo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+void AddStackedWidgetPageCommand::undo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+// ---- TabOrderCommand ----
+TabOrderCommand::TabOrderCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Tab order"), formWindow),
+ m_widgetItem(0)
+{
+}
+
+void TabOrderCommand::init(const QList<QWidget*> &newTabOrder)
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ Q_ASSERT(core);
+
+ m_widgetItem = core->metaDataBase()->item(formWindow());
+ Q_ASSERT(m_widgetItem);
+ m_oldTabOrder = m_widgetItem->tabOrder();
+ m_newTabOrder = newTabOrder;
+}
+
+void TabOrderCommand::redo()
+{
+ m_widgetItem->setTabOrder(m_newTabOrder);
+}
+
+void TabOrderCommand::undo()
+{
+ m_widgetItem->setTabOrder(m_oldTabOrder);
+}
+
+// ---- CreateMenuBarCommand ----
+CreateMenuBarCommand::CreateMenuBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Create Menu Bar"), formWindow)
+{
+}
+
+void CreateMenuBarCommand::init(QMainWindow *mainWindow)
+{
+ m_mainWindow = mainWindow;
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ m_menuBar = qobject_cast<QMenuBar*>(core->widgetFactory()->createWidget(QLatin1String("QMenuBar"), m_mainWindow));
+ core->widgetFactory()->initialize(m_menuBar);
+}
+
+void CreateMenuBarCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ c->addWidget(m_menuBar);
+
+ m_menuBar->setObjectName(QLatin1String("menuBar"));
+ formWindow()->ensureUniqueObjectName(m_menuBar);
+ core->metaDataBase()->add(m_menuBar);
+ formWindow()->emitSelectionChanged();
+ m_menuBar->setFocus();
+}
+
+void CreateMenuBarCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ for (int i = 0; i < c->count(); ++i) {
+ if (c->widget(i) == m_menuBar) {
+ c->remove(i);
+ break;
+ }
+ }
+
+ core->metaDataBase()->remove(m_menuBar);
+ formWindow()->emitSelectionChanged();
+}
+
+// ---- DeleteMenuBarCommand ----
+DeleteMenuBarCommand::DeleteMenuBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Menu Bar"), formWindow)
+{
+}
+
+void DeleteMenuBarCommand::init(QMenuBar *menuBar)
+{
+ m_menuBar = menuBar;
+ m_mainWindow = qobject_cast<QMainWindow*>(menuBar->parentWidget());
+}
+
+void DeleteMenuBarCommand::redo()
+{
+ if (m_mainWindow) {
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+ Q_ASSERT(c != 0);
+ for (int i=0; i<c->count(); ++i) {
+ if (c->widget(i) == m_menuBar) {
+ c->remove(i);
+ break;
+ }
+ }
+ }
+
+ core()->metaDataBase()->remove(m_menuBar);
+ m_menuBar->hide();
+ m_menuBar->setParent(formWindow());
+ formWindow()->emitSelectionChanged();
+}
+
+void DeleteMenuBarCommand::undo()
+{
+ if (m_mainWindow) {
+ m_menuBar->setParent(m_mainWindow);
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+
+ c->addWidget(m_menuBar);
+
+ core()->metaDataBase()->add(m_menuBar);
+ m_menuBar->show();
+ formWindow()->emitSelectionChanged();
+ }
+}
+
+// ---- CreateStatusBarCommand ----
+CreateStatusBarCommand::CreateStatusBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Create Status Bar"), formWindow)
+{
+}
+
+void CreateStatusBarCommand::init(QMainWindow *mainWindow)
+{
+ m_mainWindow = mainWindow;
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ m_statusBar = qobject_cast<QStatusBar*>(core->widgetFactory()->createWidget(QLatin1String("QStatusBar"), m_mainWindow));
+ core->widgetFactory()->initialize(m_statusBar);
+}
+
+void CreateStatusBarCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ c->addWidget(m_statusBar);
+
+ m_statusBar->setObjectName(QLatin1String("statusBar"));
+ formWindow()->ensureUniqueObjectName(m_statusBar);
+ core->metaDataBase()->add(m_statusBar);
+ formWindow()->emitSelectionChanged();
+}
+
+void CreateStatusBarCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ for (int i = 0; i < c->count(); ++i) {
+ if (c->widget(i) == m_statusBar) {
+ c->remove(i);
+ break;
+ }
+ }
+
+ core->metaDataBase()->remove(m_statusBar);
+ formWindow()->emitSelectionChanged();
+}
+
+// ---- DeleteStatusBarCommand ----
+DeleteStatusBarCommand::DeleteStatusBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Status Bar"), formWindow)
+{
+}
+
+void DeleteStatusBarCommand::init(QStatusBar *statusBar)
+{
+ m_statusBar = statusBar;
+ m_mainWindow = qobject_cast<QMainWindow*>(statusBar->parentWidget());
+}
+
+void DeleteStatusBarCommand::redo()
+{
+ if (m_mainWindow) {
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+ Q_ASSERT(c != 0);
+ for (int i=0; i<c->count(); ++i) {
+ if (c->widget(i) == m_statusBar) {
+ c->remove(i);
+ break;
+ }
+ }
+ }
+
+ core()->metaDataBase()->remove(m_statusBar);
+ m_statusBar->hide();
+ m_statusBar->setParent(formWindow());
+ formWindow()->emitSelectionChanged();
+}
+
+void DeleteStatusBarCommand::undo()
+{
+ if (m_mainWindow) {
+ m_statusBar->setParent(m_mainWindow);
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+
+ c->addWidget(m_statusBar);
+
+ core()->metaDataBase()->add(m_statusBar);
+ m_statusBar->show();
+ formWindow()->emitSelectionChanged();
+ }
+}
+
+// ---- AddToolBarCommand ----
+AddToolBarCommand::AddToolBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Add Tool Bar"), formWindow)
+{
+}
+
+void AddToolBarCommand::init(QMainWindow *mainWindow)
+{
+ m_mainWindow = mainWindow;
+ QDesignerWidgetFactoryInterface * wf = formWindow()->core()->widgetFactory();
+ // Pass on 0 parent first to avoid reparenting flicker.
+ m_toolBar = qobject_cast<QToolBar*>(wf->createWidget(QLatin1String("QToolBar"), 0));
+ wf->initialize(m_toolBar);
+ m_toolBar->hide();
+}
+
+void AddToolBarCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->add(m_toolBar);
+
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ c->addWidget(m_toolBar);
+
+ m_toolBar->setObjectName(QLatin1String("toolBar"));
+ formWindow()->ensureUniqueObjectName(m_toolBar);
+ setPropertySheetWindowTitle(core, m_toolBar, m_toolBar->objectName());
+ formWindow()->emitSelectionChanged();
+}
+
+void AddToolBarCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->remove(m_toolBar);
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ for (int i = 0; i < c->count(); ++i) {
+ if (c->widget(i) == m_toolBar) {
+ c->remove(i);
+ break;
+ }
+ }
+ formWindow()->emitSelectionChanged();
+}
+
+// ---- DockWidgetCommand:: ----
+DockWidgetCommand::DockWidgetCommand(const QString &description, QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(description, formWindow)
+{
+}
+
+DockWidgetCommand::~DockWidgetCommand()
+{
+}
+
+void DockWidgetCommand::init(QDockWidget *dockWidget)
+{
+ m_dockWidget = dockWidget;
+}
+
+// ---- AddDockWidgetCommand ----
+AddDockWidgetCommand::AddDockWidgetCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Add Dock Window"), formWindow)
+{
+}
+
+void AddDockWidgetCommand::init(QMainWindow *mainWindow, QDockWidget *dockWidget)
+{
+ m_mainWindow = mainWindow;
+ m_dockWidget = dockWidget;
+}
+
+void AddDockWidgetCommand::init(QMainWindow *mainWindow)
+{
+ m_mainWindow = mainWindow;
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ m_dockWidget = qobject_cast<QDockWidget*>(core->widgetFactory()->createWidget(QLatin1String("QDockWidget"), m_mainWindow));
+}
+
+void AddDockWidgetCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ c->addWidget(m_dockWidget);
+
+ m_dockWidget->setObjectName(QLatin1String("dockWidget"));
+ formWindow()->ensureUniqueObjectName(m_dockWidget);
+ formWindow()->manageWidget(m_dockWidget);
+ formWindow()->emitSelectionChanged();
+}
+
+void AddDockWidgetCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), m_mainWindow);
+ for (int i = 0; i < c->count(); ++i) {
+ if (c->widget(i) == m_dockWidget) {
+ c->remove(i);
+ break;
+ }
+ }
+
+ formWindow()->unmanageWidget(m_dockWidget);
+ formWindow()->emitSelectionChanged();
+}
+
+// ---- AdjustWidgetSizeCommand ----
+AdjustWidgetSizeCommand::AdjustWidgetSizeCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow)
+{
+}
+
+void AdjustWidgetSizeCommand::init(QWidget *widget)
+{
+ m_widget = widget;
+ setText(QApplication::translate("Command", "Adjust Size of '%1'").arg(widget->objectName()));
+}
+
+QWidget *AdjustWidgetSizeCommand::widgetForAdjust() const
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ // Return the outer, embedding widget if it is the main container
+ if (Utils::isCentralWidget(fw, m_widget))
+ return fw->core()->integration()->containerWindow(m_widget);
+ return m_widget;
+}
+
+void AdjustWidgetSizeCommand::redo()
+{
+ QWidget *aw = widgetForAdjust();
+ m_geometry = aw->geometry();
+ QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ aw->adjustSize();
+ const bool isMainContainer = aw != m_widget;
+ if (!isMainContainer) {
+ /* When doing adjustsize on a selected non-laid out child that has been enlarged
+ * and pushed partially over the top/left edge[s], it is possible that it "disappears"
+ * when shrinking. In that case, move it back so that it remains visible. */
+ if (aw->parentWidget()->layout() == 0) {
+ const QRect contentsRect = aw->parentWidget()->contentsRect();
+ const QRect newGeometry = aw->geometry();
+ QPoint newPos = m_geometry.topLeft();
+ if (newGeometry.bottom() <= contentsRect.y())
+ newPos.setY(contentsRect.y());
+ if (newGeometry.right() <= contentsRect.x())
+ newPos.setX(contentsRect.x());
+ if (newPos != m_geometry.topLeft())
+ aw->move(newPos);
+ }
+ }
+ updatePropertyEditor();
+}
+
+void AdjustWidgetSizeCommand::undo()
+{
+ QWidget *aw = widgetForAdjust();
+ aw->resize(m_geometry.size());
+ if (m_geometry.topLeft() != aw->geometry().topLeft())
+ aw->move(m_geometry.topLeft());
+ updatePropertyEditor();
+}
+
+void AdjustWidgetSizeCommand::updatePropertyEditor() const
+{
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ if (propertyEditor->object() == m_widget)
+ propertyEditor->setPropertyValue(QLatin1String("geometry"), m_widget->geometry(), true);
+ }
+}
+// ------------ ChangeFormLayoutItemRoleCommand
+
+ChangeFormLayoutItemRoleCommand::ChangeFormLayoutItemRoleCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Change Form Layout Item Geometry"), formWindow),
+ m_operation(SpanningToLabel)
+{
+}
+
+void ChangeFormLayoutItemRoleCommand::init(QWidget *widget, Operation op)
+{
+ m_widget = widget;
+ m_operation = op;
+}
+
+void ChangeFormLayoutItemRoleCommand::redo()
+{
+ doOperation(m_operation);
+}
+
+void ChangeFormLayoutItemRoleCommand::undo()
+{
+ doOperation(reverseOperation(m_operation));
+}
+
+ChangeFormLayoutItemRoleCommand::Operation ChangeFormLayoutItemRoleCommand::reverseOperation(Operation op)
+{
+ switch (op) {
+ case SpanningToLabel:
+ return LabelToSpanning;
+ case SpanningToField:
+ return FieldToSpanning;
+ case LabelToSpanning:
+ return SpanningToLabel;
+ case FieldToSpanning:
+ return SpanningToField;
+ }
+ return SpanningToField;
+}
+
+void ChangeFormLayoutItemRoleCommand::doOperation(Operation op)
+{
+ QFormLayout *fl = ChangeFormLayoutItemRoleCommand::managedFormLayoutOf(formWindow()->core(), m_widget);
+ const int index = fl->indexOf(m_widget);
+ Q_ASSERT(index != -1);
+ int row;
+ QFormLayout::ItemRole role;
+ fl->getItemPosition (index, &row, &role);
+ Q_ASSERT(index != -1);
+ QLayoutItem *item = fl->takeAt(index);
+ const QRect area = QRect(0, row, 2, 1);
+ switch (op) {
+ case SpanningToLabel:
+ fl->setItem(row, QFormLayout::LabelRole, item);
+ QLayoutSupport::createEmptyCells(fl);
+ break;
+ case SpanningToField:
+ fl->setItem(row, QFormLayout::FieldRole, item);
+ QLayoutSupport::createEmptyCells(fl);
+ break;
+ case LabelToSpanning:
+ case FieldToSpanning:
+ QLayoutSupport::removeEmptyCells(fl, area);
+ fl->setItem(row, QFormLayout::SpanningRole, item);
+ break;
+ }
+}
+
+unsigned ChangeFormLayoutItemRoleCommand::possibleOperations(QDesignerFormEditorInterface *core, QWidget *w)
+{
+ QFormLayout *fl = managedFormLayoutOf(core, w);
+ if (!fl)
+ return 0;
+ const int index = fl->indexOf(w);
+ if (index == -1)
+ return 0;
+ int row, col, colspan;
+ getFormLayoutItemPosition(fl, index, &row, &col, 0, &colspan);
+ // Spanning item?
+ if (colspan > 1)
+ return SpanningToLabel|SpanningToField;
+ // Is the neighbouring column free, that is, can the current item be expanded?
+ const QFormLayout::ItemRole neighbouringRole = col == 0 ? QFormLayout::FieldRole : QFormLayout::LabelRole;
+ const bool empty = LayoutInfo::isEmptyItem(fl->itemAt(row, neighbouringRole));
+ if (empty)
+ return col == 0 ? LabelToSpanning : FieldToSpanning;
+ return 0;
+}
+
+QFormLayout *ChangeFormLayoutItemRoleCommand::managedFormLayoutOf(QDesignerFormEditorInterface *core, QWidget *w)
+{
+ if (QLayout *layout = LayoutInfo::managedLayout(core, w->parentWidget()))
+ if (QFormLayout *fl = qobject_cast<QFormLayout *>(layout))
+ return fl;
+ return 0;
+}
+
+// ---- ChangeLayoutItemGeometry ----
+ChangeLayoutItemGeometry::ChangeLayoutItemGeometry(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Layout Item Geometry"), formWindow)
+{
+}
+
+void ChangeLayoutItemGeometry::init(QWidget *widget, int row, int column, int rowspan, int colspan)
+{
+ m_widget = widget;
+ Q_ASSERT(m_widget->parentWidget() != 0);
+
+ QLayout *layout = LayoutInfo::managedLayout(formWindow()->core(), m_widget->parentWidget());
+ Q_ASSERT(layout != 0);
+
+ QGridLayout *grid = qobject_cast<QGridLayout*>(layout);
+ Q_ASSERT(grid != 0);
+
+ const int itemIndex = grid->indexOf(m_widget);
+ Q_ASSERT(itemIndex != -1);
+
+ int current_row, current_column, current_rowspan, current_colspan;
+ grid->getItemPosition(itemIndex, &current_row, &current_column, &current_rowspan, &current_colspan);
+
+ m_oldInfo.setRect(current_column, current_row, current_colspan, current_rowspan);
+ m_newInfo.setRect(column, row, colspan, rowspan);
+}
+
+void ChangeLayoutItemGeometry::changeItemPosition(const QRect &g)
+{
+ QLayout *layout = LayoutInfo::managedLayout(formWindow()->core(), m_widget->parentWidget());
+ Q_ASSERT(layout != 0);
+
+ QGridLayout *grid = qobject_cast<QGridLayout*>(layout);
+ Q_ASSERT(grid != 0);
+
+ const int itemIndex = grid->indexOf(m_widget);
+ Q_ASSERT(itemIndex != -1);
+
+ QLayoutItem *item = grid->takeAt(itemIndex);
+ delete item;
+
+ if (!QLayoutSupport::removeEmptyCells(grid, g))
+ qWarning() << "ChangeLayoutItemGeometry::changeItemPosition: Nonempty cell at " << g << '.';
+
+ grid->addWidget(m_widget, g.top(), g.left(), g.height(), g.width());
+
+ grid->invalidate();
+ grid->activate();
+
+ QLayoutSupport::createEmptyCells(grid);
+
+ formWindow()->clearSelection(false);
+ formWindow()->selectWidget(m_widget, true);
+}
+
+void ChangeLayoutItemGeometry::redo()
+{
+ changeItemPosition(m_newInfo);
+}
+
+void ChangeLayoutItemGeometry::undo()
+{
+ changeItemPosition(m_oldInfo);
+}
+
+// ---- ContainerWidgetCommand ----
+ContainerWidgetCommand::ContainerWidgetCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_index(-1)
+{
+}
+
+ContainerWidgetCommand::~ContainerWidgetCommand()
+{
+}
+
+QDesignerContainerExtension *ContainerWidgetCommand::containerExtension() const
+{
+ QExtensionManager *mgr = core()->extensionManager();
+ return qt_extension<QDesignerContainerExtension*>(mgr, m_containerWidget);
+}
+
+void ContainerWidgetCommand::init(QWidget *containerWidget)
+{
+ m_containerWidget = containerWidget;
+
+ if (QDesignerContainerExtension *c = containerExtension()) {
+ m_index = c->currentIndex();
+ m_widget = c->widget(m_index);
+ }
+}
+
+void ContainerWidgetCommand::removePage()
+{
+ if (QDesignerContainerExtension *c = containerExtension()) {
+ if (const int count = c->count()) {
+ // Undo add after last?
+ const int deleteIndex = m_index >= 0 ? m_index : count - 1;
+ c->remove(deleteIndex);
+ m_widget->hide();
+ m_widget->setParent(formWindow());
+ }
+ }
+}
+
+void ContainerWidgetCommand::addPage()
+{
+ if (QDesignerContainerExtension *c = containerExtension()) {
+ int newCurrentIndex;
+ if (m_index >= 0) {
+ c->insertWidget(m_index, m_widget);
+ newCurrentIndex = m_index;
+ } else {
+ c->addWidget(m_widget);
+ newCurrentIndex = c->count() -1 ;
+ }
+ m_widget->show();
+ c->setCurrentIndex(newCurrentIndex);
+ }
+}
+
+// ---- DeleteContainerWidgetPageCommand ----
+DeleteContainerWidgetPageCommand::DeleteContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow)
+ : ContainerWidgetCommand(formWindow)
+{
+}
+
+DeleteContainerWidgetPageCommand::~DeleteContainerWidgetPageCommand()
+{
+}
+
+void DeleteContainerWidgetPageCommand::init(QWidget *containerWidget, ContainerType ct)
+{
+ ContainerWidgetCommand::init(containerWidget);
+ switch (ct) {
+ case WizardContainer:
+ case PageContainer:
+ setText(QApplication::translate("Command", "Delete Page"));
+ break;
+ case MdiContainer:
+ setText(QApplication::translate("Command", "Delete Subwindow"));
+ break;
+ }
+}
+
+void DeleteContainerWidgetPageCommand::redo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+void DeleteContainerWidgetPageCommand::undo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+// ---- AddContainerWidgetPageCommand ----
+AddContainerWidgetPageCommand::AddContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow)
+ : ContainerWidgetCommand(formWindow)
+{
+}
+
+AddContainerWidgetPageCommand::~AddContainerWidgetPageCommand()
+{
+}
+
+void AddContainerWidgetPageCommand::init(QWidget *containerWidget, ContainerType ct, InsertionMode mode)
+{
+ m_containerWidget = containerWidget;
+
+ if (QDesignerContainerExtension *c = containerExtension()) {
+ m_index = c->currentIndex();
+ if (m_index >= 0 && mode == InsertAfter)
+ m_index++;
+ m_widget = 0;
+ const QDesignerFormEditorInterface *core = formWindow()->core();
+ switch (ct) {
+ case PageContainer:
+ setText(QApplication::translate("Command", "Insert Page"));
+ m_widget = new QDesignerWidget(formWindow(), m_containerWidget);
+ m_widget->setObjectName(QApplication::translate("Command", "page"));
+ break;
+ case MdiContainer:
+ setText(QApplication::translate("Command", "Insert Subwindow"));
+ m_widget = new QDesignerWidget(formWindow(), m_containerWidget);
+ m_widget->setObjectName(QApplication::translate("Command", "subwindow"));
+ setPropertySheetWindowTitle(core, m_widget, QApplication::translate("Command", "Subwindow"));
+ break;
+ case WizardContainer: // Apply style, don't manage
+ m_widget = core->widgetFactory()->createWidget(QLatin1String("QWizardPage"), 0);
+ break;
+ }
+ formWindow()->ensureUniqueObjectName(m_widget);
+ core->metaDataBase()->add(m_widget);
+ }
+}
+
+void AddContainerWidgetPageCommand::redo()
+{
+ addPage();
+ cheapUpdate();
+}
+
+void AddContainerWidgetPageCommand::undo()
+{
+ removePage();
+ cheapUpdate();
+}
+
+ChangeCurrentPageCommand::ChangeCurrentPageCommand(QDesignerFormWindowInterface *formWindow)
+ :
+ QDesignerFormWindowCommand(QString(), formWindow), m_oldIndex(0), m_newIndex(0)
+{
+}
+
+ChangeCurrentPageCommand::~ChangeCurrentPageCommand()
+{
+}
+
+QDesignerContainerExtension *ChangeCurrentPageCommand::containerExtension() const
+{
+ QExtensionManager *mgr = core()->extensionManager();
+ return qt_extension<QDesignerContainerExtension*>(mgr, m_containerWidget);
+}
+
+void ChangeCurrentPageCommand::init(QWidget *containerWidget, int newIndex)
+{
+ m_containerWidget = containerWidget;
+
+ if (QDesignerContainerExtension *c = containerExtension()) {
+ m_newIndex = newIndex;
+ m_oldIndex = c->currentIndex();
+ m_widget = c->widget(m_oldIndex);
+ }
+}
+
+void ChangeCurrentPageCommand::redo()
+{
+ containerExtension()->setCurrentIndex(m_newIndex);
+}
+
+void ChangeCurrentPageCommand::undo()
+{
+ containerExtension()->setCurrentIndex(m_oldIndex);
+}
+
+static int itemRoles[] = {
+ Qt::DecorationPropertyRole,
+ Qt::DisplayPropertyRole,
+ Qt::ToolTipPropertyRole,
+ Qt::StatusTipPropertyRole,
+ Qt::WhatsThisPropertyRole,
+ Qt::FontRole,
+ Qt::TextAlignmentRole,
+ Qt::BackgroundRole,
+ Qt::ForegroundRole,
+ Qt::CheckStateRole,
+ -1
+};
+
+template<class T>
+static void copyRoleFromItem(ItemData *id, int role, const T *item)
+{
+ QVariant v = item->data(role);
+ if (v.isValid())
+ id->m_properties.insert(role, v);
+}
+
+template<class T>
+static void copyRolesFromItem(ItemData *id, const T *item, bool editor)
+{
+ static const int defaultFlags = T().flags();
+
+ for (int i = 0; itemRoles[i] != -1; i++)
+ copyRoleFromItem<T>(id, itemRoles[i], item);
+
+ if (editor)
+ copyRoleFromItem<T>(id, ItemFlagsShadowRole, item);
+ else if (item->flags() != defaultFlags)
+ id->m_properties.insert(ItemFlagsShadowRole, qVariantFromValue((int)item->flags()));
+}
+
+template<class T>
+static void copyRolesToItem(const ItemData *id, T *item, DesignerIconCache *iconCache, bool editor)
+{
+ QHash<int, QVariant>::const_iterator it = id->m_properties.constBegin(),
+ end = id->m_properties.constEnd();
+ for (; it != end; ++it)
+ if (it.value().isValid()) {
+ if (!editor && it.key() == ItemFlagsShadowRole) {
+ item->setFlags((Qt::ItemFlags)it.value().toInt());
+ } else {
+ item->setData(it.key(), it.value());
+ switch (it.key()) {
+ case Qt::DecorationPropertyRole:
+ if (iconCache)
+ item->setIcon(iconCache->icon(qVariantValue<PropertySheetIconValue>(it.value())));
+ break;
+ case Qt::DisplayPropertyRole:
+ item->setText(qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::ToolTipPropertyRole:
+ item->setToolTip(qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::StatusTipPropertyRole:
+ item->setStatusTip(qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::WhatsThisPropertyRole:
+ item->setWhatsThis(qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ }
+ }
+ }
+
+ if (editor)
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+}
+
+ItemData::ItemData(const QListWidgetItem *item, bool editor)
+{
+ copyRolesFromItem<QListWidgetItem>(this, item, editor);
+}
+
+QListWidgetItem *ItemData::createListItem(DesignerIconCache *iconCache, bool editor) const
+{
+ QListWidgetItem *item = new QListWidgetItem();
+ copyRolesToItem(this, item, iconCache, editor);
+ return item;
+}
+
+ItemData::ItemData(const QTableWidgetItem *item, bool editor)
+{
+ copyRolesFromItem(this, item, editor);
+}
+
+QTableWidgetItem *ItemData::createTableItem(DesignerIconCache *iconCache, bool editor) const
+{
+ QTableWidgetItem *item = new QTableWidgetItem;
+ copyRolesToItem(this, item, iconCache, editor);
+ return item;
+}
+
+static void copyRoleFromItem(ItemData *id, int role, const QTreeWidgetItem *item, int column)
+{
+ QVariant v = item->data(column, role);
+ if (v.isValid())
+ id->m_properties.insert(role, v);
+}
+
+ItemData::ItemData(const QTreeWidgetItem *item, int column)
+{
+ copyRoleFromItem(this, Qt::EditRole, item, column);
+ PropertySheetStringValue str(item->text(column));
+ m_properties.insert(Qt::DisplayPropertyRole, qVariantFromValue(str));
+
+ for (int i = 0; itemRoles[i] != -1; i++)
+ copyRoleFromItem(this, itemRoles[i], item, column);
+}
+
+void ItemData::fillTreeItemColumn(QTreeWidgetItem *item, int column, DesignerIconCache *iconCache) const
+{
+ QHash<int, QVariant>::const_iterator it = m_properties.constBegin(), end = m_properties.constEnd();
+ for (; it != end; ++it)
+ if (it.value().isValid()) {
+ item->setData(column, it.key(), it.value());
+ switch (it.key()) {
+ case Qt::DecorationPropertyRole:
+ if (iconCache)
+ item->setIcon(column, iconCache->icon(qVariantValue<PropertySheetIconValue>(it.value())));
+ break;
+ case Qt::DisplayPropertyRole:
+ item->setText(column, qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::ToolTipPropertyRole:
+ item->setToolTip(column, qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::StatusTipPropertyRole:
+ item->setStatusTip(column, qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ case Qt::WhatsThisPropertyRole:
+ item->setWhatsThis(column, qVariantValue<PropertySheetStringValue>(it.value()).value());
+ break;
+ }
+ }
+}
+
+ListContents::ListContents(const QTreeWidgetItem *item)
+{
+ for (int i = 0; i < item->columnCount(); i++)
+ m_items.append(ItemData(item, i));
+}
+
+QTreeWidgetItem *ListContents::createTreeItem(DesignerIconCache *iconCache) const
+{
+ QTreeWidgetItem *item = new QTreeWidgetItem;
+ int i = 0;
+ foreach (const ItemData &id, m_items)
+ id.fillTreeItemColumn(item, i++, iconCache);
+ return item;
+}
+
+void ListContents::createFromListWidget(const QListWidget *listWidget, bool editor)
+{
+ m_items.clear();
+
+ for (int i = 0; i < listWidget->count(); i++)
+ m_items.append(ItemData(listWidget->item(i), editor));
+}
+
+void ListContents::applyToListWidget(QListWidget *listWidget, DesignerIconCache *iconCache, bool editor) const
+{
+ listWidget->clear();
+
+ int i = 0;
+ foreach (const ItemData &entry, m_items) {
+ if (!entry.isValid())
+ new QListWidgetItem(TableWidgetContents::defaultHeaderText(i), listWidget);
+ else
+ listWidget->addItem(entry.createListItem(iconCache, editor));
+ i++;
+ }
+}
+
+void ListContents::createFromComboBox(const QComboBox *comboBox)
+{
+ m_items.clear();
+
+ const int count = comboBox->count();
+ for (int i = 0; i < count; i++) {
+ // We might encounter items added in a custom combo
+ // constructor. Ignore those.
+ const QVariant textValue = comboBox->itemData(i, Qt::DisplayPropertyRole);
+ if (!textValue.isNull()) {
+ ItemData entry;
+ entry.m_properties.insert(Qt::DisplayPropertyRole, textValue);
+ const QVariant iconValue = comboBox->itemData(i, Qt::DecorationPropertyRole);
+ if (!iconValue.isNull())
+ entry.m_properties.insert(Qt::DecorationPropertyRole, iconValue);
+ m_items.append(entry);
+ }
+ }
+}
+
+void ListContents::applyToComboBox(QComboBox *comboBox, DesignerIconCache *iconCache) const
+{
+ comboBox->clear();
+
+ foreach (const ItemData &hash, m_items) {
+ QIcon icon;
+ if (iconCache)
+ icon = iconCache->icon(qVariantValue<PropertySheetIconValue>(
+ hash.m_properties[Qt::DecorationPropertyRole]));
+ QVariant var = hash.m_properties[Qt::DisplayPropertyRole];
+ PropertySheetStringValue str = qVariantValue<PropertySheetStringValue>(var);
+ comboBox->addItem(icon, str.value());
+ comboBox->setItemData(comboBox->count() - 1,
+ var,
+ Qt::DisplayPropertyRole);
+ comboBox->setItemData(comboBox->count() - 1,
+ hash.m_properties[Qt::DecorationPropertyRole],
+ Qt::DecorationPropertyRole);
+ }
+}
+
+// --------- TableWidgetContents
+
+TableWidgetContents::TableWidgetContents() :
+ m_columnCount(0),
+ m_rowCount(0)
+{
+}
+
+void TableWidgetContents::clear()
+{
+ m_horizontalHeader.m_items.clear();
+ m_verticalHeader.m_items.clear();
+ m_items.clear();
+ m_columnCount = 0;
+ m_rowCount = 0;
+}
+
+QString TableWidgetContents::defaultHeaderText(int i)
+{
+ return QString::number(i + 1);
+}
+
+bool TableWidgetContents::nonEmpty(const QTableWidgetItem *item, int headerColumn)
+{
+ static int defaultFlags = QTableWidgetItem().flags();
+
+ if (item->flags() != defaultFlags)
+ return true;
+
+ QString text = qVariantValue<PropertySheetStringValue>(item->data(Qt::DisplayPropertyRole)).value();
+ if (!text.isEmpty()) {
+ if (headerColumn < 0 || text != defaultHeaderText(headerColumn))
+ return true;
+ } else {
+ // FIXME: This doesn't seem to make sense
+ return true;
+ }
+
+ for (int i = 0; itemRoles[i] != -1; i++)
+ if (itemRoles[i] != Qt::DisplayPropertyRole && item->data(itemRoles[i]).isValid())
+ return true;
+
+ return false;
+}
+
+void TableWidgetContents::insertHeaderItem(const QTableWidgetItem *item, int i, ListContents *header, bool editor)
+{
+ if (nonEmpty(item, i))
+ header->m_items.append(ItemData(item, editor));
+ else
+ header->m_items.append(ItemData());
+}
+
+void TableWidgetContents::fromTableWidget(const QTableWidget *tableWidget, bool editor)
+{
+ clear();
+ m_columnCount = tableWidget->columnCount();
+ m_rowCount = tableWidget->rowCount();
+ // horiz header: Legacy behaviour: auto-generate number for empty items
+ for (int col = 0; col < m_columnCount; col++)
+ if (const QTableWidgetItem *item = tableWidget->horizontalHeaderItem(col))
+ insertHeaderItem(item, col, &m_horizontalHeader, editor);
+ // vertical header: Legacy behaviour: auto-generate number for empty items
+ for (int row = 0; row < m_rowCount; row++)
+ if (const QTableWidgetItem *item = tableWidget->verticalHeaderItem(row))
+ insertHeaderItem(item, row, &m_verticalHeader, editor);
+ // cell data
+ for (int col = 0; col < m_columnCount; col++)
+ for (int row = 0; row < m_rowCount; row++)
+ if (const QTableWidgetItem *item = tableWidget->item(row, col))
+ if (nonEmpty(item, -1))
+ m_items.insert(CellRowColumnAddress(row, col), ItemData(item, editor));
+}
+
+void TableWidgetContents::applyToTableWidget(QTableWidget *tableWidget, DesignerIconCache *iconCache, bool editor) const
+{
+ tableWidget->clear();
+
+ tableWidget->setColumnCount(m_columnCount);
+ tableWidget->setRowCount(m_rowCount);
+
+ // horiz header
+ int col = 0;
+ foreach (const ItemData &id, m_horizontalHeader.m_items) {
+ if (id.isValid())
+ tableWidget->setHorizontalHeaderItem(col, id.createTableItem(iconCache, editor));
+ col++;
+ }
+ // vertical header
+ int row = 0;
+ foreach (const ItemData &id, m_verticalHeader.m_items) {
+ if (id.isValid())
+ tableWidget->setVerticalHeaderItem(row, id.createTableItem(iconCache, editor));
+ row++;
+ }
+ // items
+ const TableItemMap::const_iterator icend = m_items.constEnd();
+ for (TableItemMap::const_iterator it = m_items.constBegin(); it != icend; ++ it)
+ tableWidget->setItem(it.key().first, it.key().second, it.value().createTableItem(iconCache, editor));
+}
+
+bool TableWidgetContents::operator==(const TableWidgetContents &rhs) const
+{
+ if (m_columnCount != rhs.m_columnCount || m_rowCount != rhs.m_rowCount)
+ return false;
+
+ return m_horizontalHeader.m_items == rhs.m_horizontalHeader.m_items &&
+ m_verticalHeader.m_items == rhs.m_verticalHeader.m_items &&
+ m_items == rhs.m_items;
+}
+
+// ---- ChangeTableContentsCommand ----
+ChangeTableContentsCommand::ChangeTableContentsCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Change Table Contents"),
+ formWindow), m_iconCache(0)
+{
+ FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow);
+ if (fwb)
+ m_iconCache = fwb->iconCache();
+}
+
+void ChangeTableContentsCommand::init(QTableWidget *tableWidget,
+ const TableWidgetContents &oldCont, const TableWidgetContents &newCont)
+{
+ m_tableWidget = tableWidget;
+ m_oldContents = oldCont;
+ m_newContents = newCont;
+}
+
+void ChangeTableContentsCommand::redo()
+{
+ m_newContents.applyToTableWidget(m_tableWidget, m_iconCache, false);
+ QMetaObject::invokeMethod(m_tableWidget, "updateGeometries");
+}
+
+void ChangeTableContentsCommand::undo()
+{
+ m_oldContents.applyToTableWidget(m_tableWidget, m_iconCache, false);
+ QMetaObject::invokeMethod(m_tableWidget, "updateGeometries");
+}
+
+// --------- TreeWidgetContents
+TreeWidgetContents::ItemContents::ItemContents(const QTreeWidgetItem *item, bool editor) :
+ ListContents(item)
+{
+ static const int defaultFlags = QTreeWidgetItem().flags();
+
+ if (editor) {
+ QVariant v = item->data(0, ItemFlagsShadowRole);
+ m_itemFlags = v.isValid() ? v.toInt() : -1;
+ } else {
+ m_itemFlags = (item->flags() != defaultFlags) ? (int)item->flags() : -1;
+ }
+
+ for (int i = 0; i < item->childCount(); i++)
+ m_children.append(ItemContents(item->child(i), editor));
+}
+
+QTreeWidgetItem *TreeWidgetContents::ItemContents::createTreeItem(DesignerIconCache *iconCache, bool editor) const
+{
+ QTreeWidgetItem *item = ListContents::createTreeItem(iconCache);
+
+ if (editor)
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+
+ if (m_itemFlags != -1) {
+ if (editor)
+ item->setData(0, ItemFlagsShadowRole, qVariantFromValue(m_itemFlags));
+ else
+ item->setFlags((Qt::ItemFlags)m_itemFlags);
+ }
+
+ foreach (const ItemContents &ic, m_children)
+ item->addChild(ic.createTreeItem(iconCache, editor));
+
+ return item;
+}
+
+bool TreeWidgetContents::ItemContents::operator==(const TreeWidgetContents::ItemContents &rhs) const
+{
+ return
+ m_itemFlags == rhs.m_itemFlags &&
+ m_items == rhs.m_items &&
+ m_children == rhs.m_children;
+}
+
+void TreeWidgetContents::clear()
+{
+ m_headerItem.m_items.clear();
+ m_rootItems.clear();
+}
+
+void TreeWidgetContents::fromTreeWidget(const QTreeWidget *treeWidget, bool editor)
+{
+ clear();
+ m_headerItem = ListContents(treeWidget->headerItem());
+ for (int col = 0; col < treeWidget->topLevelItemCount(); col++)
+ m_rootItems.append(ItemContents(treeWidget->topLevelItem(col), editor));
+}
+
+void TreeWidgetContents::applyToTreeWidget(QTreeWidget *treeWidget, DesignerIconCache *iconCache, bool editor) const
+{
+ treeWidget->clear();
+
+ treeWidget->setColumnCount(m_headerItem.m_items.count());
+ treeWidget->setHeaderItem(m_headerItem.createTreeItem(iconCache));
+ foreach (const ItemContents &ic, m_rootItems)
+ treeWidget->addTopLevelItem(ic.createTreeItem(iconCache, editor));
+ treeWidget->expandAll();
+}
+
+bool TreeWidgetContents::operator==(const TreeWidgetContents &rhs) const
+{
+ return
+ m_headerItem == rhs.m_headerItem &&
+ m_rootItems == rhs.m_rootItems;
+}
+
+// ---- ChangeTreeContentsCommand ----
+ChangeTreeContentsCommand::ChangeTreeContentsCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Tree Contents"), formWindow),
+ m_iconCache(0)
+{
+ FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow);
+ if (fwb)
+ m_iconCache = fwb->iconCache();
+}
+
+void ChangeTreeContentsCommand::init(QTreeWidget *treeWidget,
+ const TreeWidgetContents &oldState, const TreeWidgetContents &newState)
+{
+ m_treeWidget = treeWidget;
+ m_oldState = oldState;
+ m_newState = newState;
+}
+
+void ChangeTreeContentsCommand::redo()
+{
+ m_newState.applyToTreeWidget(m_treeWidget, m_iconCache, false);
+}
+
+void ChangeTreeContentsCommand::undo()
+{
+ m_oldState.applyToTreeWidget(m_treeWidget, m_iconCache, false);
+}
+
+// ---- ChangeListContentsCommand ----
+ChangeListContentsCommand::ChangeListContentsCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow), m_iconCache(0)
+{
+ FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow);
+ if (fwb)
+ m_iconCache = fwb->iconCache();
+}
+
+void ChangeListContentsCommand::init(QListWidget *listWidget,
+ const ListContents &oldItems, const ListContents &items)
+{
+ m_listWidget = listWidget;
+ m_comboBox = 0;
+
+ m_newItemsState = items;
+ m_oldItemsState = oldItems;
+}
+
+void ChangeListContentsCommand::init(QComboBox *comboBox,
+ const ListContents &oldItems, const ListContents &items)
+{
+ m_listWidget = 0;
+ m_comboBox = comboBox;
+
+ m_newItemsState = items;
+ m_oldItemsState = oldItems;
+}
+
+void ChangeListContentsCommand::redo()
+{
+ if (m_listWidget)
+ m_newItemsState.applyToListWidget(m_listWidget, m_iconCache, false);
+ else if (m_comboBox)
+ m_newItemsState.applyToComboBox(m_comboBox, m_iconCache);
+}
+
+void ChangeListContentsCommand::undo()
+{
+ if (m_listWidget)
+ m_oldItemsState.applyToListWidget(m_listWidget, m_iconCache, false);
+ else if (m_comboBox)
+ m_oldItemsState.applyToComboBox(m_comboBox, m_iconCache);
+}
+
+// ---- AddActionCommand ----
+
+AddActionCommand::AddActionCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Add action"), formWindow)
+{
+ m_action = 0;
+}
+
+void AddActionCommand::init(QAction *action)
+{
+ Q_ASSERT(m_action == 0);
+ m_action = action;
+}
+
+void AddActionCommand::redo()
+{
+ core()->actionEditor()->setFormWindow(formWindow());
+ core()->actionEditor()->manageAction(m_action);
+}
+
+void AddActionCommand::undo()
+{
+ core()->actionEditor()->setFormWindow(formWindow());
+ core()->actionEditor()->unmanageAction(m_action);
+}
+
+// ---- RemoveActionCommand ----
+
+RemoveActionCommand::RemoveActionCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Remove action"), formWindow),
+ m_action(0)
+{
+}
+
+static RemoveActionCommand::ActionData findActionIn(QAction *action)
+{
+ RemoveActionCommand::ActionData result;
+ // We only want menus and toolbars, no toolbuttons.
+ foreach (QWidget *widget, action->associatedWidgets())
+ if (qobject_cast<const QMenu *>(widget) || qobject_cast<const QToolBar *>(widget)) {
+ const QList<QAction*> actionList = widget->actions();
+ const int size = actionList.size();
+ for (int i = 0; i < size; ++i) {
+ if (actionList.at(i) == action) {
+ QAction *before = 0;
+ if (i + 1 < size)
+ before = actionList.at(i + 1);
+ result.append(RemoveActionCommand::ActionDataItem(before, widget));
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+void RemoveActionCommand::init(QAction *action)
+{
+ Q_ASSERT(m_action == 0);
+ m_action = action;
+
+ m_actionData = findActionIn(action);
+}
+
+void RemoveActionCommand::redo()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ foreach (const ActionDataItem &item, m_actionData) {
+ item.widget->removeAction(m_action);
+ }
+ // Notify components (for example, signal slot editor)
+ if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(fw))
+ fwb->emitObjectRemoved(m_action);
+
+ core()->actionEditor()->setFormWindow(fw);
+ core()->actionEditor()->unmanageAction(m_action);
+ if (!m_actionData.empty())
+ core()->objectInspector()->setFormWindow(fw);
+}
+
+void RemoveActionCommand::undo()
+{
+ core()->actionEditor()->setFormWindow(formWindow());
+ core()->actionEditor()->manageAction(m_action);
+ foreach (const ActionDataItem &item, m_actionData) {
+ item.widget->insertAction(item.before, m_action);
+ }
+ if (!m_actionData.empty())
+ core()->objectInspector()->setFormWindow(formWindow());
+}
+
+// ---- ActionInsertionCommand ----
+
+ActionInsertionCommand::ActionInsertionCommand(const QString &text, QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(text, formWindow),
+ m_parentWidget(0),
+ m_action(0),
+ m_beforeAction(0),
+ m_update(false)
+{
+}
+
+void ActionInsertionCommand::init(QWidget *parentWidget, QAction *action, QAction *beforeAction, bool update)
+{
+ Q_ASSERT(m_parentWidget == 0);
+ Q_ASSERT(m_action == 0);
+
+ m_parentWidget = parentWidget;
+ m_action = action;
+ m_beforeAction = beforeAction;
+ m_update = update;
+}
+
+void ActionInsertionCommand::insertAction()
+{
+ Q_ASSERT(m_action != 0);
+ Q_ASSERT(m_parentWidget != 0);
+
+ if (m_beforeAction)
+ m_parentWidget->insertAction(m_beforeAction, m_action);
+ else
+ m_parentWidget->addAction(m_action);
+
+ if (m_update) {
+ cheapUpdate();
+ if (QMenu *menu = m_action->menu())
+ selectUnmanagedObject(menu);
+ else
+ selectUnmanagedObject(m_action);
+ PropertyHelper::triggerActionChanged(m_action); // Update Used column in action editor.
+ }
+}
+void ActionInsertionCommand::removeAction()
+{
+ Q_ASSERT(m_action != 0);
+ Q_ASSERT(m_parentWidget != 0);
+
+ if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(m_parentWidget))
+ menu->hideSubMenu();
+
+ m_parentWidget->removeAction(m_action);
+
+ if (m_update) {
+ cheapUpdate();
+ selectUnmanagedObject(m_parentWidget);
+ PropertyHelper::triggerActionChanged(m_action); // Update Used column in action editor.
+ }
+}
+
+InsertActionIntoCommand::InsertActionIntoCommand(QDesignerFormWindowInterface *formWindow) :
+ ActionInsertionCommand(QApplication::translate("Command", "Add action"), formWindow)
+{
+}
+// ---- RemoveActionFromCommand ----
+
+RemoveActionFromCommand::RemoveActionFromCommand(QDesignerFormWindowInterface *formWindow) :
+ ActionInsertionCommand(QApplication::translate("Command", "Remove action"), formWindow)
+{
+}
+
+// ---- AddMenuActionCommand ----
+
+MenuActionCommand::MenuActionCommand(const QString &text, QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(text, formWindow),
+ m_action(0),
+ m_actionBefore(0),
+ m_menuParent(0),
+ m_associatedWidget(0),
+ m_objectToSelect(0)
+{
+}
+
+void MenuActionCommand::init(QAction *action, QAction *actionBefore,
+ QWidget *associatedWidget, QWidget *objectToSelect)
+{
+ QMenu *menu = action->menu();
+ Q_ASSERT(menu);
+ m_menuParent = menu->parentWidget();
+ m_action = action;
+ m_actionBefore = actionBefore;
+ m_associatedWidget = associatedWidget;
+ m_objectToSelect = objectToSelect;
+}
+
+void MenuActionCommand::insertMenu()
+{
+ core()->metaDataBase()->add(m_action);
+ QMenu *menu = m_action->menu();
+ if (m_menuParent && menu->parentWidget() != m_menuParent)
+ menu->setParent(m_menuParent);
+ core()->metaDataBase()->add(menu);
+ m_associatedWidget->insertAction(m_actionBefore, m_action);
+ cheapUpdate();
+ selectUnmanagedObject(menu);
+}
+
+void MenuActionCommand::removeMenu()
+{
+ m_action->menu()->setParent(0);
+ QMenu *menu = m_action->menu();
+ core()->metaDataBase()->remove(menu);
+ menu->setParent(0);
+ core()->metaDataBase()->remove(m_action);
+ m_associatedWidget->removeAction(m_action);
+ cheapUpdate();
+ selectUnmanagedObject(m_objectToSelect);
+}
+
+AddMenuActionCommand::AddMenuActionCommand(QDesignerFormWindowInterface *formWindow) :
+ MenuActionCommand(QApplication::translate("Command", "Add menu"), formWindow)
+{
+}
+
+// ---- RemoveMenuActionCommand ----
+RemoveMenuActionCommand::RemoveMenuActionCommand(QDesignerFormWindowInterface *formWindow) :
+ MenuActionCommand(QApplication::translate("Command", "Remove menu"), formWindow)
+{
+}
+
+// ---- CreateSubmenuCommand ----
+CreateSubmenuCommand::CreateSubmenuCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QApplication::translate("Command", "Create submenu"), formWindow),
+ m_action(0),
+ m_menu(0),
+ m_objectToSelect(0)
+{
+}
+
+void CreateSubmenuCommand::init(QDesignerMenu *menu, QAction *action, QObject *objectToSelect)
+{
+ m_menu = menu;
+ m_action = action;
+ m_objectToSelect = objectToSelect;
+}
+
+void CreateSubmenuCommand::redo()
+{
+ m_menu->createRealMenuAction(m_action);
+ cheapUpdate();
+ if (m_objectToSelect)
+ selectUnmanagedObject(m_objectToSelect);
+}
+
+void CreateSubmenuCommand::undo()
+{
+ m_menu->removeRealMenu(m_action);
+ cheapUpdate();
+ selectUnmanagedObject(m_menu);
+}
+
+// ---- DeleteToolBarCommand ----
+DeleteToolBarCommand::DeleteToolBarCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Tool Bar"), formWindow)
+{
+}
+
+void DeleteToolBarCommand::init(QToolBar *toolBar)
+{
+ m_toolBar = toolBar;
+ m_mainWindow = qobject_cast<QMainWindow*>(toolBar->parentWidget());
+}
+
+void DeleteToolBarCommand::redo()
+{
+ if (m_mainWindow) {
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+ Q_ASSERT(c != 0);
+ for (int i=0; i<c->count(); ++i) {
+ if (c->widget(i) == m_toolBar) {
+ c->remove(i);
+ break;
+ }
+ }
+ }
+
+ core()->metaDataBase()->remove(m_toolBar);
+ m_toolBar->hide();
+ m_toolBar->setParent(formWindow());
+ formWindow()->emitSelectionChanged();
+}
+
+void DeleteToolBarCommand::undo()
+{
+ if (m_mainWindow) {
+ m_toolBar->setParent(m_mainWindow);
+ QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), m_mainWindow);
+
+ c->addWidget(m_toolBar);
+
+ core()->metaDataBase()->add(m_toolBar);
+ m_toolBar->show();
+ formWindow()->emitSelectionChanged();
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_command2.cpp b/tools/designer/src/lib/shared/qdesigner_command2.cpp
new file mode 100644
index 0000000..db534c0
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_command2.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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_command2_p.h"
+#include "formwindowbase_p.h"
+#include "layoutinfo_p.h"
+#include "qdesigner_command_p.h"
+#include "widgetfactory_p.h"
+#include "qlayout_widget_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+
+#include <QtGui/QApplication>
+#include <QtGui/QLayout>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+MorphLayoutCommand::MorphLayoutCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow),
+ m_breakLayoutCommand(new BreakLayoutCommand(formWindow)),
+ m_layoutCommand(new LayoutCommand(formWindow)),
+ m_newType(LayoutInfo::VBox),
+ m_layoutBase(0)
+{
+}
+
+MorphLayoutCommand::~MorphLayoutCommand()
+{
+ delete m_layoutCommand;
+ delete m_breakLayoutCommand;
+}
+
+bool MorphLayoutCommand::init(QWidget *w, int newType)
+{
+ int oldType;
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!canMorph(fw, w, &oldType) || oldType == newType)
+ return false;
+ m_layoutBase = w;
+ m_newType = newType;
+ // Find all managed widgets
+ m_widgets.clear();
+ const QLayout *layout = LayoutInfo::managedLayout(fw->core(), w);
+ const int count = layout->count();
+ for (int i = 0; i < count ; i++) {
+ if (QWidget *w = layout->itemAt(i)->widget())
+ if (fw->isManaged(w))
+ m_widgets.push_back(w);
+ }
+ const bool reparentLayoutWidget = false; // leave QLayoutWidget intact
+ m_breakLayoutCommand->init(m_widgets, m_layoutBase, reparentLayoutWidget);
+ m_layoutCommand->init(m_layoutBase, m_widgets, static_cast<LayoutInfo::Type>(m_newType), m_layoutBase, reparentLayoutWidget);
+ setText(formatDescription(core(), m_layoutBase, oldType, newType));
+ return true;
+}
+
+bool MorphLayoutCommand::canMorph(const QDesignerFormWindowInterface *formWindow, QWidget *w, int *ptrToCurrentType)
+{
+ if (ptrToCurrentType)
+ *ptrToCurrentType = LayoutInfo::NoLayout;
+ // We want a managed widget or a container page
+ // with a level-0 managed layout
+ QDesignerFormEditorInterface *core = formWindow->core();
+ QLayout *layout = LayoutInfo::managedLayout(core, w);
+ if (!layout)
+ return false;
+ const LayoutInfo::Type type = LayoutInfo::layoutType(core, layout);
+ if (ptrToCurrentType)
+ *ptrToCurrentType = type;
+ switch (type) {
+ case LayoutInfo::HBox:
+ case LayoutInfo::VBox:
+ case LayoutInfo::Grid:
+ case LayoutInfo::Form:
+ return true;
+ break;
+ case LayoutInfo::NoLayout:
+ case LayoutInfo::HSplitter: // Nothing doing
+ case LayoutInfo::VSplitter:
+ case LayoutInfo::UnknownLayout:
+ break;
+ }
+ return false;
+}
+
+void MorphLayoutCommand::redo()
+{
+ m_breakLayoutCommand->redo();
+ m_layoutCommand->redo();
+ /* Transfer applicable properties which is a cross-section of the modified
+ * properties except object name. */
+ if (const LayoutProperties *properties = m_breakLayoutCommand->layoutProperties()) {
+ const int oldMask = m_breakLayoutCommand->propertyMask();
+ QLayout *newLayout = LayoutInfo::managedLayout(core(), m_layoutBase);
+ const int newMask = LayoutProperties::visibleProperties(newLayout);
+ const int applicableMask = (oldMask & newMask) & ~LayoutProperties::ObjectNameProperty;
+ if (applicableMask)
+ properties->toPropertySheet(core(), newLayout, applicableMask);
+ }
+}
+
+void MorphLayoutCommand::undo()
+{
+ m_layoutCommand->undo();
+ m_breakLayoutCommand->undo();
+}
+
+QString MorphLayoutCommand::formatDescription(QDesignerFormEditorInterface * /* core*/, const QWidget *w, int oldType, int newType)
+{
+ const QString oldName = LayoutInfo::layoutName(static_cast<LayoutInfo::Type>(oldType));
+ const QString newName = LayoutInfo::layoutName(static_cast<LayoutInfo::Type>(newType));
+ const QString widgetName = qobject_cast<const QLayoutWidget*>(w) ? w->layout()->objectName() : w->objectName();
+ return QApplication::translate("Command", "Change layout of '%1' from %2 to %3").arg(widgetName, oldName, newName);
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_command2_p.h b/tools/designer/src/lib/shared/qdesigner_command2_p.h
new file mode 100644
index 0000000..e61222b
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_command2_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_COMMAND2_H
+#define QDESIGNER_COMMAND2_H
+
+#include "shared_global_p.h"
+#include "qdesigner_formwindowcommand_p.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class LayoutCommand;
+class BreakLayoutCommand;
+
+/* This command changes the type of a managed layout on a widget (including
+ * red layouts of type 'QLayoutWidget') into another type, maintaining the
+ * applicable properties. It does this by chaining BreakLayoutCommand and
+ * LayoutCommand, parametrizing them not to actually delete/reparent
+ * QLayoutWidget's. */
+
+class QDESIGNER_SHARED_EXPORT MorphLayoutCommand : public QDesignerFormWindowCommand {
+ Q_DISABLE_COPY(MorphLayoutCommand)
+public:
+ explicit MorphLayoutCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~MorphLayoutCommand();
+
+ bool init(QWidget *w, int newType);
+
+ static bool canMorph(const QDesignerFormWindowInterface *formWindow, QWidget *w, int *ptrToCurrentType = 0);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ static QString formatDescription(QDesignerFormEditorInterface *core, const QWidget *w, int oldType, int newType);
+
+ BreakLayoutCommand *m_breakLayoutCommand;
+ LayoutCommand *m_layoutCommand;
+ int m_newType;
+ QWidgetList m_widgets;
+ QWidget *m_layoutBase;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_COMMAND2_H
diff --git a/tools/designer/src/lib/shared/qdesigner_command_p.h b/tools/designer/src/lib/shared/qdesigner_command_p.h
new file mode 100644
index 0000000..3a4ce2d
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_command_p.h
@@ -0,0 +1,1136 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_COMMAND_H
+#define QDESIGNER_COMMAND_H
+
+#include "shared_global_p.h"
+#include "shared_enums_p.h"
+#include "layoutinfo_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_formwindowcommand_p.h"
+#include "qdesigner_formeditorcommand_p.h"
+
+#include <QtDesigner/layoutdecoration.h>
+
+#include <QtGui/QIcon>
+#include <QtCore/QObject>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+#include <QtCore/QHash>
+#include <QtCore/QPoint>
+#include <QtCore/QRect>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerContainerExtension;
+class QDesignerMetaDataBaseItemInterface;
+class QDesignerMenu;
+
+class QMenuBar;
+class QStatusBar;
+class QToolBar;
+class QToolBox;
+class QTabWidget;
+class QTableWidget;
+class QTableWidgetItem;
+class QTreeWidget;
+class QTreeWidgetItem;
+class QListWidget;
+class QListWidgetItem;
+class QComboBox;
+class QStackedWidget;
+class QDockWidget;
+class QMainWindow;
+class QFormLayout;
+
+namespace qdesigner_internal {
+
+class Layout;
+class LayoutHelper;
+class PropertySheetIconValue;
+class DesignerIconCache;
+struct LayoutProperties;
+
+class QDESIGNER_SHARED_EXPORT InsertWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit InsertWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ ~InsertWidgetCommand();
+
+ void init(QWidget *widget, bool already_in_form = false, int layoutRow = -1, int layoutColumn = -1);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ void refreshBuddyLabels();
+
+ QPointer<QWidget> m_widget;
+ QDesignerLayoutDecorationExtension::InsertMode m_insertMode;
+ QPair<int, int> m_cell;
+ LayoutHelper* m_layoutHelper;
+ bool m_widgetWasManaged;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeZOrderCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ChangeZOrderCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget);
+
+ virtual void redo();
+ virtual void undo();
+protected:
+ virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const = 0;
+ virtual void reorder(QWidget *widget) const = 0;
+
+private:
+ QPointer<QWidget> m_widget;
+ QPointer<QWidget> m_oldPreceding;
+ QList<QWidget *> m_oldParentZOrder;
+};
+
+class QDESIGNER_SHARED_EXPORT RaiseWidgetCommand: public ChangeZOrderCommand
+{
+
+public:
+ explicit RaiseWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget);
+
+protected:
+ virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const;
+ virtual void reorder(QWidget *widget) const;
+};
+
+class QDESIGNER_SHARED_EXPORT LowerWidgetCommand: public ChangeZOrderCommand
+{
+
+public:
+ explicit LowerWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget);
+
+protected:
+ virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const;
+ virtual void reorder(QWidget *widget) const;
+};
+
+class QDESIGNER_SHARED_EXPORT AdjustWidgetSizeCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit AdjustWidgetSizeCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QWidget *widgetForAdjust() const;
+ bool adjustNonLaidOutMainContainer(QWidget *integrationContainer);
+ void updatePropertyEditor() const;
+
+ QPointer<QWidget> m_widget;
+ QRect m_geometry;
+};
+
+// Helper to correctly unmanage a widget and its children for delete operations
+class QDESIGNER_SHARED_EXPORT ManageWidgetCommandHelper {
+public:
+ typedef QVector<QWidget*> WidgetVector;
+
+ ManageWidgetCommandHelper();
+ void init(const QDesignerFormWindowInterface *fw, QWidget *widget);
+ void init(QWidget *widget, const WidgetVector &managedChildren);
+
+ void manage(QDesignerFormWindowInterface *fw);
+ void unmanage(QDesignerFormWindowInterface *fw);
+
+ const WidgetVector &managedChildren() const { return m_managedChildren; }
+private:
+ QWidget *m_widget;
+ WidgetVector m_managedChildren;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit DeleteWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ ~DeleteWidgetCommand();
+
+ enum DeleteFlags { DoNotUnmanage = 0x1, DoNotSimplifyLayout = 0x2 };
+
+ void init(QWidget *widget, unsigned flags = 0);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QPointer<QWidget> m_widget;
+ QPointer<QWidget> m_parentWidget;
+ QRect m_geometry;
+ LayoutInfo::Type m_layoutType;
+ LayoutHelper* m_layoutHelper;
+ unsigned m_flags;
+ QRect m_layoutPosition;
+ int m_splitterIndex;
+ bool m_layoutSimplified;
+ QDesignerMetaDataBaseItemInterface *m_formItem;
+ int m_tabOrderIndex;
+ int m_widgetOrderIndex;
+ int m_zOrderIndex;
+ ManageWidgetCommandHelper m_manageHelper;
+};
+
+class QDESIGNER_SHARED_EXPORT ReparentWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ReparentWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget, QWidget *parentWidget);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QPointer<QWidget> m_widget;
+ QPoint m_oldPos;
+ QPoint m_newPos;
+ QPointer<QWidget> m_oldParentWidget;
+ QPointer<QWidget> m_newParentWidget;
+ QList<QWidget *> m_oldParentList;
+ QList<QWidget *> m_oldParentZOrder;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeFormLayoutItemRoleCommand : public QDesignerFormWindowCommand
+{
+public:
+ enum Operation { SpanningToLabel = 0x1, SpanningToField = 0x2, LabelToSpanning = 0x4, FieldToSpanning =0x8 };
+
+ explicit ChangeFormLayoutItemRoleCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget, Operation op);
+
+ virtual void redo();
+ virtual void undo();
+
+ // Return a mask of possible operations of that item
+ static unsigned possibleOperations(QDesignerFormEditorInterface *core, QWidget *w);
+
+private:
+ static QFormLayout *managedFormLayoutOf(QDesignerFormEditorInterface *core, QWidget *w);
+ static Operation reverseOperation(Operation op);
+ void doOperation(Operation op);
+
+ QPointer<QWidget> m_widget;
+ Operation m_operation;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeLayoutItemGeometry: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ChangeLayoutItemGeometry(QDesignerFormWindowInterface *formWindow);
+
+ void init(QWidget *widget, int row, int column, int rowspan, int colspan);
+
+ virtual void redo();
+ virtual void undo();
+
+protected:
+ void changeItemPosition(const QRect &g);
+
+private:
+ QPointer<QWidget> m_widget;
+ QRect m_oldInfo;
+ QRect m_newInfo;
+};
+
+class QDESIGNER_SHARED_EXPORT TabOrderCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit TabOrderCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(const QList<QWidget*> &newTabOrder);
+
+ inline QList<QWidget*> oldTabOrder() const
+ { return m_oldTabOrder; }
+
+ inline QList<QWidget*> newTabOrder() const
+ { return m_newTabOrder; }
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QDesignerMetaDataBaseItemInterface *m_widgetItem;
+ QList<QWidget*> m_oldTabOrder;
+ QList<QWidget*> m_newTabOrder;
+};
+
+class QDESIGNER_SHARED_EXPORT PromoteToCustomWidgetCommand : public QDesignerFormWindowCommand
+{
+public:
+ typedef QList<QPointer<QWidget> > WidgetList;
+
+ explicit PromoteToCustomWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(const WidgetList &widgets, const QString &customClassName);
+ virtual void redo();
+ virtual void undo();
+
+private:
+ void updateSelection();
+ WidgetList m_widgets;
+ QString m_customClassName;
+};
+
+class QDESIGNER_SHARED_EXPORT DemoteFromCustomWidgetCommand : public QDesignerFormWindowCommand
+{
+public:
+ typedef PromoteToCustomWidgetCommand::WidgetList WidgetList;
+
+ explicit DemoteFromCustomWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(const WidgetList &promoted);
+ virtual void redo();
+ virtual void undo();
+private:
+ PromoteToCustomWidgetCommand m_promote_cmd;
+};
+
+// Mixin class for storing the selection state
+class QDESIGNER_SHARED_EXPORT CursorSelectionState {
+ Q_DISABLE_COPY(CursorSelectionState)
+public:
+ CursorSelectionState();
+
+ void save(const QDesignerFormWindowInterface *formWindow);
+ void restore(QDesignerFormWindowInterface *formWindow) const;
+
+private:
+ typedef QList<QPointer<QWidget> > WidgetPointerList;
+ WidgetPointerList m_selection;
+ QPointer<QWidget> m_current;
+};
+
+class QDESIGNER_SHARED_EXPORT LayoutCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit LayoutCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~LayoutCommand();
+
+ inline QWidgetList widgets() const { return m_widgets; }
+
+ void init(QWidget *parentWidget, const QWidgetList &widgets, LayoutInfo::Type layoutType,
+ QWidget *layoutBase = 0,
+ // Reparent/Hide instances of QLayoutWidget.
+ bool reparentLayoutWidget = true);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QPointer<QWidget> m_parentWidget;
+ QWidgetList m_widgets;
+ QPointer<QWidget> m_layoutBase;
+ QPointer<Layout> m_layout;
+ CursorSelectionState m_cursorSelectionState;
+ bool m_setup;
+};
+
+class QDESIGNER_SHARED_EXPORT BreakLayoutCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit BreakLayoutCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~BreakLayoutCommand();
+
+ inline QWidgetList widgets() const { return m_widgets; }
+
+ void init(const QWidgetList &widgets, QWidget *layoutBase,
+ // Reparent/Hide instances of QLayoutWidget.
+ bool reparentLayoutWidget = true);
+
+ virtual void redo();
+ virtual void undo();
+
+ // Access the properties of the layout, 0 in case of splitters.
+ const LayoutProperties *layoutProperties() const;
+ int propertyMask() const;
+
+private:
+ QWidgetList m_widgets;
+ QPointer<QWidget> m_layoutBase;
+ QPointer<Layout> m_layout;
+ LayoutHelper* m_layoutHelper;
+ LayoutProperties *m_properties;
+ int m_propertyMask;
+ CursorSelectionState m_cursorSelectionState;
+};
+
+class QDESIGNER_SHARED_EXPORT SimplifyLayoutCommand: public QDesignerFormWindowCommand
+{
+public:
+ explicit SimplifyLayoutCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~SimplifyLayoutCommand();
+
+ bool init(QWidget *layoutBase);
+
+ // Quick check
+ static bool canSimplify(QDesignerFormEditorInterface *core, const QWidget *w, int *layoutType = 0);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ const QRect m_area;
+ QWidget *m_layoutBase;
+ LayoutHelper* m_layoutHelper;
+ bool m_layoutSimplified;
+};
+
+class QDESIGNER_SHARED_EXPORT ToolBoxCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ToolBoxCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~ToolBoxCommand();
+
+ void init(QToolBox *toolBox);
+
+ virtual void removePage();
+ virtual void addPage();
+
+protected:
+ QPointer<QToolBox> m_toolBox;
+ QPointer<QWidget> m_widget;
+ int m_index;
+ QString m_itemText;
+ QIcon m_itemIcon;
+};
+
+class QDESIGNER_SHARED_EXPORT MoveToolBoxPageCommand: public ToolBoxCommand
+{
+
+public:
+ explicit MoveToolBoxPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~MoveToolBoxPageCommand();
+
+ void init(QToolBox *toolBox, QWidget *page, int newIndex);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ int m_newIndex;
+ int m_oldIndex;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteToolBoxPageCommand: public ToolBoxCommand
+{
+
+public:
+ explicit DeleteToolBoxPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~DeleteToolBoxPageCommand();
+
+ void init(QToolBox *toolBox);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT AddToolBoxPageCommand: public ToolBoxCommand
+{
+
+public:
+ enum InsertionMode {
+ InsertBefore,
+ InsertAfter
+ };
+ explicit AddToolBoxPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~AddToolBoxPageCommand();
+
+ void init(QToolBox *toolBox);
+ void init(QToolBox *toolBox, InsertionMode mode);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT TabWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit TabWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~TabWidgetCommand();
+
+ void init(QTabWidget *tabWidget);
+
+ virtual void removePage();
+ virtual void addPage();
+
+protected:
+ QPointer<QTabWidget> m_tabWidget;
+ QPointer<QWidget> m_widget;
+ int m_index;
+ QString m_itemText;
+ QIcon m_itemIcon;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteTabPageCommand: public TabWidgetCommand
+{
+
+public:
+ explicit DeleteTabPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~DeleteTabPageCommand();
+
+ void init(QTabWidget *tabWidget);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT AddTabPageCommand: public TabWidgetCommand
+{
+
+public:
+ enum InsertionMode {
+ InsertBefore,
+ InsertAfter
+ };
+ explicit AddTabPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~AddTabPageCommand();
+
+ void init(QTabWidget *tabWidget);
+ void init(QTabWidget *tabWidget, InsertionMode mode);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT MoveTabPageCommand: public TabWidgetCommand
+{
+
+public:
+ explicit MoveTabPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~MoveTabPageCommand();
+
+ void init(QTabWidget *tabWidget, QWidget *page,
+ const QIcon &icon, const QString &label,
+ int index, int newIndex);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ int m_newIndex;
+ int m_oldIndex;
+ QPointer<QWidget> m_page;
+ QString m_label;
+ QIcon m_icon;
+};
+
+class QDESIGNER_SHARED_EXPORT StackedWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit StackedWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~StackedWidgetCommand();
+
+ void init(QStackedWidget *stackedWidget);
+
+ virtual void removePage();
+ virtual void addPage();
+
+protected:
+ QPointer<QStackedWidget> m_stackedWidget;
+ QPointer<QWidget> m_widget;
+ int m_index;
+};
+
+class QDESIGNER_SHARED_EXPORT MoveStackedWidgetCommand: public StackedWidgetCommand
+{
+
+public:
+ explicit MoveStackedWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~MoveStackedWidgetCommand();
+
+ void init(QStackedWidget *stackedWidget, QWidget *page, int newIndex);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ int m_newIndex;
+ int m_oldIndex;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteStackedWidgetPageCommand: public StackedWidgetCommand
+{
+
+public:
+ explicit DeleteStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~DeleteStackedWidgetPageCommand();
+
+ void init(QStackedWidget *stackedWidget);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT AddStackedWidgetPageCommand: public StackedWidgetCommand
+{
+
+public:
+ enum InsertionMode {
+ InsertBefore,
+ InsertAfter
+ };
+ explicit AddStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~AddStackedWidgetPageCommand();
+
+ void init(QStackedWidget *stackedWidget);
+ void init(QStackedWidget *stackedWidget, InsertionMode mode);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT CreateMenuBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit CreateMenuBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QMainWindow *mainWindow);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QMenuBar> m_menuBar;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteMenuBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit DeleteMenuBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QMenuBar *menuBar);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QMenuBar> m_menuBar;
+};
+
+class QDESIGNER_SHARED_EXPORT CreateStatusBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit CreateStatusBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QMainWindow *mainWindow);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QStatusBar> m_statusBar;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteStatusBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit DeleteStatusBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QStatusBar *statusBar);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QStatusBar> m_statusBar;
+};
+
+class QDESIGNER_SHARED_EXPORT AddToolBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit AddToolBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QMainWindow *mainWindow);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QToolBar> m_toolBar;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteToolBarCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit DeleteToolBarCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QToolBar *toolBar);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QToolBar> m_toolBar;
+};
+
+class QDESIGNER_SHARED_EXPORT DockWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit DockWidgetCommand(const QString &description, QDesignerFormWindowInterface *formWindow);
+ virtual ~DockWidgetCommand();
+
+ void init(QDockWidget *dockWidget);
+
+protected:
+ QPointer<QDockWidget> m_dockWidget;
+};
+
+class QDESIGNER_SHARED_EXPORT AddDockWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit AddDockWidgetCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QMainWindow *mainWindow, QDockWidget *dockWidget);
+ void init(QMainWindow *mainWindow);
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ QPointer<QMainWindow> m_mainWindow;
+ QPointer<QDockWidget> m_dockWidget;
+};
+
+class QDESIGNER_SHARED_EXPORT ContainerWidgetCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ContainerWidgetCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~ContainerWidgetCommand();
+
+ QDesignerContainerExtension *containerExtension() const;
+
+ void init(QWidget *containerWidget);
+
+ virtual void removePage();
+ virtual void addPage();
+
+protected:
+ QPointer<QWidget> m_containerWidget;
+ QPointer<QWidget> m_widget;
+ int m_index;
+};
+
+class QDESIGNER_SHARED_EXPORT DeleteContainerWidgetPageCommand: public ContainerWidgetCommand
+{
+
+public:
+ explicit DeleteContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~DeleteContainerWidgetPageCommand();
+
+ void init(QWidget *containerWidget, ContainerType ct);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT AddContainerWidgetPageCommand: public ContainerWidgetCommand
+{
+
+public:
+ enum InsertionMode {
+ InsertBefore,
+ InsertAfter
+ };
+ explicit AddContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~AddContainerWidgetPageCommand();
+
+ void init(QWidget *containerWidget, ContainerType ct, InsertionMode mode);
+
+ virtual void redo();
+ virtual void undo();
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeCurrentPageCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ChangeCurrentPageCommand(QDesignerFormWindowInterface *formWindow);
+ virtual ~ChangeCurrentPageCommand();
+
+ QDesignerContainerExtension *containerExtension() const;
+
+ void init(QWidget *containerWidget, int newIndex);
+
+ virtual void redo();
+ virtual void undo();
+
+protected:
+ QPointer<QWidget> m_containerWidget;
+ QPointer<QWidget> m_widget;
+ int m_oldIndex;
+ int m_newIndex;
+};
+
+struct QDESIGNER_SHARED_EXPORT ItemData {
+ ItemData() {}
+
+ ItemData(const QListWidgetItem *item, bool editor);
+ ItemData(const QTableWidgetItem *item, bool editor);
+ ItemData(const QTreeWidgetItem *item, int column);
+ QListWidgetItem *createListItem(DesignerIconCache *iconCache, bool editor) const;
+ QTableWidgetItem *createTableItem(DesignerIconCache *iconCache, bool editor) const;
+ void fillTreeItemColumn(QTreeWidgetItem *item, int column, DesignerIconCache *iconCache) const;
+
+ bool isValid() const { return !m_properties.isEmpty(); }
+ bool operator==(const ItemData &rhs) const { return m_properties == rhs.m_properties; }
+ bool operator!=(const ItemData &rhs) const { return m_properties != rhs.m_properties; }
+
+ QHash<int, QVariant> m_properties;
+};
+
+struct QDESIGNER_SHARED_EXPORT ListContents {
+ ListContents() {}
+
+ ListContents(const QTreeWidgetItem *item);
+ QTreeWidgetItem *createTreeItem(DesignerIconCache *iconCache) const;
+
+ void createFromListWidget(const QListWidget *listWidget, bool editor);
+ void applyToListWidget(QListWidget *listWidget, DesignerIconCache *iconCache, bool editor) const;
+ void createFromComboBox(const QComboBox *listWidget);
+ void applyToComboBox(QComboBox *listWidget, DesignerIconCache *iconCache) const;
+
+ bool operator==(const ListContents &rhs) const { return m_items == rhs.m_items; }
+ bool operator!=(const ListContents &rhs) const { return m_items != rhs.m_items; }
+
+ QList<ItemData> m_items;
+};
+
+// Data structure representing the contents of a QTableWidget with
+// methods to retrieve and apply for ChangeTableContentsCommand
+struct QDESIGNER_SHARED_EXPORT TableWidgetContents {
+
+ typedef QPair<int, int> CellRowColumnAddress;
+ typedef QMap<CellRowColumnAddress, ItemData> TableItemMap;
+
+ TableWidgetContents();
+ void clear();
+
+ void fromTableWidget(const QTableWidget *tableWidget, bool editor);
+ void applyToTableWidget(QTableWidget *tableWidget, DesignerIconCache *iconCache, bool editor) const;
+
+ bool operator==(const TableWidgetContents &rhs) const;
+ bool operator!=(const TableWidgetContents &rhs) const { return !(*this == rhs); }
+
+ static bool nonEmpty(const QTableWidgetItem *item, int headerColumn);
+ static QString defaultHeaderText(int i);
+ static void insertHeaderItem(const QTableWidgetItem *item, int i, ListContents *header, bool editor);
+
+ int m_columnCount;
+ int m_rowCount;
+ ListContents m_horizontalHeader;
+ ListContents m_verticalHeader;
+ TableItemMap m_items;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeTableContentsCommand: public QDesignerFormWindowCommand
+{
+public:
+ explicit ChangeTableContentsCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QTableWidget *tableWidget, const TableWidgetContents &oldCont, const TableWidgetContents &newCont);
+ virtual void redo();
+ virtual void undo();
+
+private:
+ QPointer<QTableWidget> m_tableWidget;
+ TableWidgetContents m_oldContents;
+ TableWidgetContents m_newContents;
+ DesignerIconCache *m_iconCache;
+};
+
+// Data structure representing the contents of a QTreeWidget with
+// methods to retrieve and apply for ChangeTreeContentsCommand
+struct QDESIGNER_SHARED_EXPORT TreeWidgetContents {
+
+ struct ItemContents : public ListContents {
+ ItemContents() : m_itemFlags(-1) {}
+ ItemContents(const QTreeWidgetItem *item, bool editor);
+ QTreeWidgetItem *createTreeItem(DesignerIconCache *iconCache, bool editor) const;
+
+ bool operator==(const ItemContents &rhs) const;
+ bool operator!=(const ItemContents &rhs) const { return !(*this == rhs); }
+
+ int m_itemFlags;
+ //bool m_firstColumnSpanned:1;
+ //bool m_hidden:1;
+ //bool m_expanded:1;
+ QList<ItemContents> m_children;
+ };
+
+ void clear();
+
+ void fromTreeWidget(const QTreeWidget *treeWidget, bool editor);
+ void applyToTreeWidget(QTreeWidget *treeWidget, DesignerIconCache *iconCache, bool editor) const;
+
+ bool operator==(const TreeWidgetContents &rhs) const;
+ bool operator!=(const TreeWidgetContents &rhs) const { return !(*this == rhs); }
+
+ ListContents m_headerItem;
+ QList<ItemContents> m_rootItems;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeTreeContentsCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ChangeTreeContentsCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QTreeWidget *treeWidget, const TreeWidgetContents &oldState, const TreeWidgetContents &newState);
+ virtual void redo();
+ virtual void undo();
+ enum ApplyIconStrategy {
+ SetIconStrategy,
+ ResetIconStrategy
+ };
+private:
+ QPointer<QTreeWidget> m_treeWidget;
+ TreeWidgetContents m_oldState;
+ TreeWidgetContents m_newState;
+ DesignerIconCache *m_iconCache;
+};
+
+class QDESIGNER_SHARED_EXPORT ChangeListContentsCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit ChangeListContentsCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QListWidget *listWidget, const ListContents &oldItems, const ListContents &items);
+ void init(QComboBox *comboBox, const ListContents &oldItems, const ListContents &items);
+ virtual void redo();
+ virtual void undo();
+private:
+ QPointer<QListWidget> m_listWidget;
+ QPointer<QComboBox> m_comboBox;
+ ListContents m_oldItemsState;
+ ListContents m_newItemsState;
+ DesignerIconCache *m_iconCache;
+};
+
+class QDESIGNER_SHARED_EXPORT AddActionCommand : public QDesignerFormWindowCommand
+{
+
+public:
+ explicit AddActionCommand(QDesignerFormWindowInterface *formWindow);
+ void init(QAction *action);
+ virtual void redo();
+ virtual void undo();
+private:
+ QAction *m_action;
+};
+
+// Note: This 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 QDESIGNER_SHARED_EXPORT RemoveActionCommand : public QDesignerFormWindowCommand
+{
+
+public:
+ explicit RemoveActionCommand(QDesignerFormWindowInterface *formWindow);
+ void init(QAction *action);
+ virtual void redo();
+ virtual void undo();
+
+ struct ActionDataItem {
+ ActionDataItem(QAction *_before = 0, QWidget *_widget = 0)
+ : before(_before), widget(_widget) {}
+ QAction *before;
+ QWidget *widget;
+ };
+ typedef QList<ActionDataItem> ActionData;
+
+private:
+ QAction *m_action;
+
+ ActionData m_actionData;
+};
+
+class QDESIGNER_SHARED_EXPORT ActionInsertionCommand : public QDesignerFormWindowCommand
+{
+
+protected:
+ ActionInsertionCommand(const QString &text, QDesignerFormWindowInterface *formWindow);
+
+public:
+ void init(QWidget *parentWidget, QAction *action, QAction *beforeAction = 0, bool update = true);
+
+protected:
+ void insertAction();
+ void removeAction();
+
+private:
+ QWidget *m_parentWidget;
+ QAction *m_action;
+ QAction *m_beforeAction;
+ bool m_update;
+};
+
+class QDESIGNER_SHARED_EXPORT InsertActionIntoCommand : public ActionInsertionCommand
+{
+
+public:
+ explicit InsertActionIntoCommand(QDesignerFormWindowInterface *formWindow);
+
+ virtual void redo() { insertAction(); }
+ virtual void undo() { removeAction(); }
+};
+
+class QDESIGNER_SHARED_EXPORT RemoveActionFromCommand : public ActionInsertionCommand
+{
+
+public:
+ explicit RemoveActionFromCommand(QDesignerFormWindowInterface *formWindow);
+
+ virtual void redo() { removeAction(); }
+ virtual void undo() { insertAction(); }
+};
+
+class QDESIGNER_SHARED_EXPORT MenuActionCommand : public QDesignerFormWindowCommand
+{
+public:
+ void init(QAction *action, QAction *actionBefore, QWidget *associatedWidget, QWidget *objectToSelect);
+
+protected:
+ MenuActionCommand(const QString &text, QDesignerFormWindowInterface *formWindow);
+ void insertMenu();
+ void removeMenu();
+
+private:
+ QAction *m_action;
+ QAction *m_actionBefore;
+ QWidget *m_menuParent;
+ QWidget *m_associatedWidget;
+ QWidget *m_objectToSelect;
+};
+
+class QDESIGNER_SHARED_EXPORT AddMenuActionCommand : public MenuActionCommand
+{
+
+public:
+ explicit AddMenuActionCommand(QDesignerFormWindowInterface *formWindow);
+
+ virtual void redo() { insertMenu(); }
+ virtual void undo() { removeMenu(); }
+};
+
+class QDESIGNER_SHARED_EXPORT RemoveMenuActionCommand : public MenuActionCommand
+{
+
+public:
+ explicit RemoveMenuActionCommand(QDesignerFormWindowInterface *formWindow);
+
+ virtual void redo() { removeMenu(); }
+ virtual void undo() { insertMenu(); }
+};
+
+class QDESIGNER_SHARED_EXPORT CreateSubmenuCommand : public QDesignerFormWindowCommand
+{
+
+public:
+ explicit CreateSubmenuCommand(QDesignerFormWindowInterface *formWindow);
+ void init(QDesignerMenu *menu, QAction *action, QObject *m_objectToSelect = 0);
+ virtual void redo();
+ virtual void undo();
+private:
+ QAction *m_action;
+ QDesignerMenu *m_menu;
+ QObject *m_objectToSelect;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_COMMAND_H
diff --git a/tools/designer/src/lib/shared/qdesigner_dnditem.cpp b/tools/designer/src/lib/shared/qdesigner_dnditem.cpp
new file mode 100644
index 0000000..5dfbb65
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_dnditem.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** 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_dnditem_p.h"
+#include "formwindowbase_p.h"
+#include "ui4_p.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QBitmap>
+#include <QtGui/QPixmap>
+#include <QtGui/QImage>
+#include <QtGui/QLabel>
+#include <QtGui/QDrag>
+#include <QtGui/QCursor>
+#include <QtGui/QDropEvent>
+#include <QtGui/QRgb>
+
+#include <QtCore/QMultiMap>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+QDesignerDnDItem::QDesignerDnDItem(DropType type, QWidget *source) :
+ m_source(source),
+ m_type(type),
+ m_dom_ui(0),
+ m_widget(0),
+ m_decoration(0)
+{
+}
+
+void QDesignerDnDItem::init(DomUI *ui, QWidget *widget, QWidget *decoration,
+ const QPoint &global_mouse_pos)
+{
+ Q_ASSERT(widget != 0 || ui != 0);
+ Q_ASSERT(decoration != 0);
+
+ m_dom_ui = ui;
+ m_widget = widget;
+ m_decoration = decoration;
+
+ const QRect geometry = m_decoration->geometry();
+ m_hot_spot = global_mouse_pos - m_decoration->geometry().topLeft();
+}
+
+QDesignerDnDItem::~QDesignerDnDItem()
+{
+ if (m_decoration != 0)
+ m_decoration->deleteLater();
+ delete m_dom_ui;
+}
+
+DomUI *QDesignerDnDItem::domUi() const
+{
+ return m_dom_ui;
+}
+
+QWidget *QDesignerDnDItem::decoration() const
+{
+ return m_decoration;
+}
+
+QPoint QDesignerDnDItem::hotSpot() const
+{
+ return m_hot_spot;
+}
+
+QWidget *QDesignerDnDItem::widget() const
+{
+ return m_widget;
+}
+
+QDesignerDnDItem::DropType QDesignerDnDItem::type() const
+{
+ return m_type;
+}
+
+QWidget *QDesignerDnDItem::source() const
+{
+ return m_source;
+}
+
+void QDesignerDnDItem::setDomUi(DomUI *dom_ui)
+{
+ delete m_dom_ui;
+ m_dom_ui = dom_ui;
+}
+
+// ---------- QDesignerMimeData
+
+// Make pixmap transparent on Windows only. Mac is transparent by default, Unix usually does not work.
+#ifdef Q_WS_WIN
+# define TRANSPARENT_DRAG_PIXMAP
+#endif
+
+QDesignerMimeData::QDesignerMimeData(const QDesignerDnDItems &items, QDrag *drag) :
+ m_items(items)
+{
+ enum { Alpha = 200 };
+ QPoint decorationTopLeft;
+ switch (m_items.size()) {
+ case 0:
+ break;
+ case 1: {
+ QWidget *deco = m_items.first()->decoration();
+ decorationTopLeft = deco->pos();
+ const QPixmap widgetPixmap = QPixmap::grabWidget(deco);
+#ifdef TRANSPARENT_DRAG_PIXMAP
+ QImage image(widgetPixmap.size(), QImage::Format_ARGB32);
+ image.fill(QColor(Qt::transparent).rgba());
+ QPainter painter(&image);
+ painter.drawPixmap(QPoint(0, 0), widgetPixmap);
+ painter.end();
+ setImageTransparency(image, Alpha);
+ drag->setPixmap(QPixmap::fromImage(image));
+#else
+ drag->setPixmap(widgetPixmap);
+#endif
+ }
+ break;
+ default: {
+ // determine size of drag decoration by uniting all geometries
+ const QDesignerDnDItems::const_iterator cend = m_items.constEnd();
+ QDesignerDnDItems::const_iterator it =m_items.constBegin();
+ QRect unitedGeometry = (*it)->decoration()->geometry();
+ for (++it; it != cend; ++it )
+ unitedGeometry = unitedGeometry .united((*it)->decoration()->geometry());
+
+ // paint with offset. At the same time, create a mask bitmap, containing widget rectangles.
+ QImage image(unitedGeometry.size(), QImage::Format_ARGB32);
+ image.fill(QColor(Qt::transparent).rgba());
+ QBitmap mask(unitedGeometry.size());
+ mask.clear();
+ // paint with offset, determine action
+ QPainter painter(&image);
+ QPainter maskPainter(&mask);
+ decorationTopLeft = unitedGeometry.topLeft();
+ for (it = m_items.constBegin() ; it != cend; ++it ) {
+ QWidget *w = (*it)->decoration();
+ const QPixmap wp = QPixmap::grabWidget(w);
+ const QPoint pos = w->pos() - decorationTopLeft;
+ painter.drawPixmap(pos, wp);
+ maskPainter.fillRect(QRect(pos, wp.size()), Qt::color1);
+ }
+ painter.end();
+ maskPainter.end();
+#ifdef TRANSPARENT_DRAG_PIXMAP
+ setImageTransparency(image, Alpha);
+#endif
+ QPixmap pixmap = QPixmap::fromImage(image);
+ pixmap.setMask(mask);
+ drag->setPixmap(pixmap);
+ }
+ break;
+ }
+ // determine hot spot and reconstruct the exact starting position as form window
+ // introduces some offset when detecting DnD
+ m_globalStartPos = m_items.first()->decoration()->pos() + m_items.first()->hotSpot();
+ m_hotSpot = m_globalStartPos - decorationTopLeft;
+ drag->setHotSpot(m_hotSpot);
+
+ drag->setMimeData(this);
+}
+
+QDesignerMimeData::~QDesignerMimeData()
+{
+ const QDesignerDnDItems::const_iterator cend = m_items.constEnd();
+ for (QDesignerDnDItems::const_iterator it = m_items.constBegin(); it != cend; ++it )
+ delete *it;
+}
+
+Qt::DropAction QDesignerMimeData::proposedDropAction() const
+{
+ return m_items.first()->type() == QDesignerDnDItemInterface::CopyDrop ? Qt::CopyAction : Qt::MoveAction;
+}
+
+Qt::DropAction QDesignerMimeData::execDrag(const QDesignerDnDItems &items, QWidget * dragSource)
+{
+ if (items.empty())
+ return Qt::IgnoreAction;
+
+ QDrag *drag = new QDrag(dragSource);
+ QDesignerMimeData *mimeData = new QDesignerMimeData(items, drag);
+
+ // Store pointers to widgets that are to be re-shown if a move operation is canceled
+ QWidgetList reshowWidgets;
+ const QDesignerDnDItems::const_iterator cend = items.constEnd();
+ for (QDesignerDnDItems::const_iterator it = items.constBegin(); it != cend; ++it )
+ if (QWidget *w = (*it)->widget())
+ if ((*it)->type() == QDesignerDnDItemInterface::MoveDrop)
+ reshowWidgets.push_back(w);
+
+ const Qt::DropAction executedAction = drag->exec(Qt::CopyAction|Qt::MoveAction, mimeData->proposedDropAction());
+
+ if (executedAction == Qt::IgnoreAction && !reshowWidgets.empty())
+ foreach (QWidget *w, reshowWidgets)
+ w->show();
+
+ return executedAction;
+}
+
+
+void QDesignerMimeData::moveDecoration(const QPoint &globalPos) const
+{
+ const QPoint relativeDistance = globalPos - m_globalStartPos;
+ const QDesignerDnDItems::const_iterator cend = m_items.constEnd();
+ for (QDesignerDnDItems::const_iterator it =m_items.constBegin(); it != cend; ++it ) {
+ QWidget *w = (*it)->decoration();
+ w->move(w->pos() + relativeDistance);
+ }
+}
+
+void QDesignerMimeData::removeMovedWidgetsFromSourceForm(const QDesignerDnDItems &items)
+{
+ typedef QMultiMap<FormWindowBase *, QWidget *> FormWidgetMap;
+ FormWidgetMap formWidgetMap;
+ // Find moved widgets per form
+ const QDesignerDnDItems::const_iterator cend = items.constEnd();
+ for (QDesignerDnDItems::const_iterator it = items.constBegin(); it != cend; ++it )
+ if ((*it)->type() == QDesignerDnDItemInterface::MoveDrop)
+ if (QWidget *w = (*it)->widget())
+ if (FormWindowBase *fb = qobject_cast<FormWindowBase *>((*it)->source()))
+ formWidgetMap.insert(fb, w);
+ if (formWidgetMap.empty())
+ return;
+
+ foreach (FormWindowBase * fb, formWidgetMap.keys())
+ fb->deleteWidgetList(formWidgetMap.values(fb));
+}
+
+void QDesignerMimeData::acceptEventWithAction(Qt::DropAction desiredAction, QDropEvent *e)
+{
+ if (e->proposedAction() == desiredAction) {
+ e->acceptProposedAction();
+ } else {
+ e->setDropAction(desiredAction);
+ e->accept();
+ }
+}
+
+void QDesignerMimeData::acceptEvent(QDropEvent *e) const
+{
+ acceptEventWithAction(proposedDropAction(), e);
+}
+
+void QDesignerMimeData::setImageTransparency(QImage &image, int alpha)
+{
+ const int height = image.height();
+ for (int l = 0; l < height; l++) {
+ QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(l));
+ QRgb *lineEnd = line + image.width();
+ for ( ; line < lineEnd; line++) {
+ const QRgb rgba = *line;
+ *line = qRgba(qRed(rgba), qGreen(rgba), qBlue(rgba), alpha);
+ }
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_dnditem_p.h b/tools/designer/src/lib/shared/qdesigner_dnditem_p.h
new file mode 100644
index 0000000..cf36b39
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_dnditem_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_DNDITEM_H
+#define QDESIGNER_DNDITEM_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/abstractdnditem.h>
+
+#include <QtCore/QPoint>
+#include <QtCore/QList>
+#include <QtCore/QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+class QDrag;
+class QImage;
+class QDropEvent;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT QDesignerDnDItem: public QDesignerDnDItemInterface
+{
+public:
+ explicit QDesignerDnDItem(DropType type, QWidget *source = 0);
+ virtual ~QDesignerDnDItem();
+
+ virtual DomUI *domUi() const;
+ virtual QWidget *decoration() const;
+ virtual QWidget *widget() const;
+ virtual QPoint hotSpot() const;
+ virtual QWidget *source() const;
+
+ virtual DropType type() const;
+
+protected:
+ void setDomUi(DomUI *dom_ui);
+ void init(DomUI *ui, QWidget *widget, QWidget *decoration, const QPoint &global_mouse_pos);
+
+private:
+ QWidget *m_source;
+ const DropType m_type;
+ const QPoint m_globalStartPos;
+ DomUI *m_dom_ui;
+ QWidget *m_widget;
+ QWidget *m_decoration;
+ QPoint m_hot_spot;
+
+ Q_DISABLE_COPY(QDesignerDnDItem)
+};
+
+// Mime data for use with designer drag and drop operations.
+
+class QDESIGNER_SHARED_EXPORT QDesignerMimeData : public QMimeData {
+ Q_OBJECT
+
+public:
+ typedef QList<QDesignerDnDItemInterface *> QDesignerDnDItems;
+
+ virtual ~QDesignerMimeData();
+
+ const QDesignerDnDItems &items() const { return m_items; }
+
+ // Execute a drag and drop operation.
+ static Qt::DropAction execDrag(const QDesignerDnDItems &items, QWidget * dragSource);
+
+ QPoint hotSpot() const { return m_hotSpot; }
+
+ // Move the decoration. Required for drops over form windows as the position
+ // is derived from the decoration position.
+ void moveDecoration(const QPoint &globalPos) const;
+
+ // For a move operation, create the undo command sequence to remove
+ // the widgets from the source form.
+ static void removeMovedWidgetsFromSourceForm(const QDesignerDnDItems &items);
+
+ // Accept an event with the proper action.
+ void acceptEvent(QDropEvent *e) const;
+
+ // Helper to accept an event with the desired action.
+ static void acceptEventWithAction(Qt::DropAction desiredAction, QDropEvent *e);
+
+private:
+ QDesignerMimeData(const QDesignerDnDItems &items, QDrag *drag);
+ Qt::DropAction proposedDropAction() const;
+
+ static void setImageTransparency(QImage &image, int alpha);
+
+ const QDesignerDnDItems m_items;
+ QPoint m_globalStartPos;
+ QPoint m_hotSpot;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_DNDITEM_H
diff --git a/tools/designer/src/lib/shared/qdesigner_dockwidget.cpp b/tools/designer/src/lib/shared/qdesigner_dockwidget.cpp
new file mode 100644
index 0000000..b678982
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_dockwidget.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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_dockwidget_p.h"
+#include "layoutinfo_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+
+#include <QtGui/QMainWindow>
+#include <QtGui/QLayout>
+
+QT_BEGIN_NAMESPACE
+
+QDesignerDockWidget::QDesignerDockWidget(QWidget *parent)
+ : QDockWidget(parent)
+{
+}
+
+QDesignerDockWidget::~QDesignerDockWidget()
+{
+}
+
+bool QDesignerDockWidget::docked() const
+{
+ return qobject_cast<QMainWindow*>(parentWidget()) != 0;
+}
+
+void QDesignerDockWidget::setDocked(bool b)
+{
+ if (QMainWindow *mainWindow = findMainWindow()) {
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerContainerExtension *c;
+ c = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), mainWindow);
+ if (b && !docked()) {
+ // Dock it
+ // ### undo/redo stack
+ setParent(0);
+ c->addWidget(this);
+ formWindow()->selectWidget(this, formWindow()->cursor()->isWidgetSelected(this));
+ } else if (!b && docked()) {
+ // Undock it
+ for (int i = 0; i < c->count(); ++i) {
+ if (c->widget(i) == this) {
+ c->remove(i);
+ break;
+ }
+ }
+ // #### restore the position
+ setParent(mainWindow->centralWidget());
+ show();
+ formWindow()->selectWidget(this, formWindow()->cursor()->isWidgetSelected(this));
+ }
+ }
+}
+
+Qt::DockWidgetArea QDesignerDockWidget::dockWidgetArea() const
+{
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(parentWidget()))
+ return mainWindow->dockWidgetArea(const_cast<QDesignerDockWidget*>(this));
+
+ return Qt::LeftDockWidgetArea;
+}
+
+void QDesignerDockWidget::setDockWidgetArea(Qt::DockWidgetArea dockWidgetArea)
+{
+ if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(parentWidget())) {
+ if ((dockWidgetArea != Qt::NoDockWidgetArea)
+ && isAreaAllowed(dockWidgetArea)) {
+ mainWindow->addDockWidget(dockWidgetArea, this);
+ }
+ }
+}
+
+bool QDesignerDockWidget::inMainWindow() const
+{
+ QMainWindow *mw = findMainWindow();
+ if (mw && !mw->centralWidget()->layout()) {
+ if (mw == parentWidget())
+ return true;
+ if (mw->centralWidget() == parentWidget())
+ return true;
+ }
+ return false;
+}
+
+QDesignerFormWindowInterface *QDesignerDockWidget::formWindow() const
+{
+ return QDesignerFormWindowInterface::findFormWindow(const_cast<QDesignerDockWidget*>(this));
+}
+
+QMainWindow *QDesignerDockWidget::findMainWindow() const
+{
+ if (QDesignerFormWindowInterface *fw = formWindow())
+ return qobject_cast<QMainWindow*>(fw->mainContainer());
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_dockwidget_p.h b/tools/designer/src/lib/shared/qdesigner_dockwidget_p.h
new file mode 100644
index 0000000..f055908
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_dockwidget_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_DOCKWIDGET_H
+#define QDESIGNER_DOCKWIDGET_H
+
+#include "shared_global_p.h"
+#include <QtGui/QDockWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+class QDESIGNER_SHARED_EXPORT QDesignerDockWidget: public QDockWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea DESIGNABLE docked STORED false)
+ Q_PROPERTY(bool docked READ docked WRITE setDocked DESIGNABLE inMainWindow STORED false)
+public:
+ QDesignerDockWidget(QWidget *parent = 0);
+ virtual ~QDesignerDockWidget();
+
+ bool docked() const;
+ void setDocked(bool b);
+
+ Qt::DockWidgetArea dockWidgetArea() const;
+ void setDockWidgetArea(Qt::DockWidgetArea dockWidgetArea);
+
+ bool inMainWindow() const;
+
+private:
+ QDesignerFormWindowInterface *formWindow() const;
+ QMainWindow *findMainWindow() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_DOCKWIDGET_H
diff --git a/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp b/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp
new file mode 100644
index 0000000..6394847
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp
@@ -0,0 +1,478 @@
+/****************************************************************************
+**
+** 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_formbuilder_p.h"
+#include "dynamicpropertysheet.h"
+#include "qsimpleresource_p.h"
+#include "widgetfactory_p.h"
+#include "qdesigner_introspection_p.h"
+
+#include <ui4_p.h>
+#include <formbuilderextra_p.h>
+// sdk
+#include <QtDesigner/container.h>
+#include <QtDesigner/customwidget.h>
+#include <QtDesigner/propertysheet.h>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QDesignerCustomWidgetInterface>
+#include <abstractdialoggui_p.h>
+
+// shared
+#include <qdesigner_propertysheet_p.h>
+#include <qdesigner_utils_p.h>
+#include <formwindowbase_p.h>
+#include <qtresourcemodel_p.h>
+#include <scripterrordialog_p.h>
+
+#include <QtGui/QWidget>
+#include <QtGui/QMenu>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenuBar>
+#include <QtGui/QMainWindow>
+#include <QtGui/QStyleFactory>
+#include <QtGui/QStyle>
+#include <QtGui/QApplication>
+#include <QtGui/QAbstractScrollArea>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPixmap>
+
+#include <QtCore/QBuffer>
+#include <QtCore/qdebug.h>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+static QString summarizeScriptErrors(const QFormScriptRunner::Errors &errors)
+{
+ QString rc = QCoreApplication::translate("QDesignerFormBuilder", "Script errors occurred:");
+ foreach (QFormScriptRunner::Error error, errors) {
+ rc += QLatin1Char('\n');
+ rc += error.errorMessage;
+ }
+ return rc;
+}
+
+namespace qdesigner_internal {
+
+QDesignerFormBuilder::QDesignerFormBuilder(QDesignerFormEditorInterface *core,
+ Mode mode,
+ const DeviceProfile &deviceProfile) :
+ m_core(core),
+ m_mode(mode),
+ m_deviceProfile(deviceProfile),
+ m_pixmapCache(0),
+ m_iconCache(0),
+ m_ignoreCreateResources(false),
+ m_tempResourceSet(0),
+ m_mainWidget(true)
+{
+ Q_ASSERT(m_core);
+ // Disable scripting in the editors.
+ QFormScriptRunner::Options options = formScriptRunner()->options();
+ switch (m_mode) {
+ case DisableScripts:
+ options |= QFormScriptRunner::DisableScripts;
+ break;
+ case EnableScripts:
+ options |= QFormScriptRunner::DisableWarnings;
+ options &= ~QFormScriptRunner::DisableScripts;
+ break;
+ }
+ formScriptRunner()-> setOptions(options);
+}
+
+QString QDesignerFormBuilder::systemStyle() const
+{
+ return m_deviceProfile.isEmpty() ?
+ QString::fromUtf8(QApplication::style()->metaObject()->className()) :
+ m_deviceProfile.style();
+}
+
+QWidget *QDesignerFormBuilder::createWidgetFromContents(const QString &contents, QWidget *parentWidget)
+{
+ QByteArray data = contents.toUtf8();
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ return load(&buffer, parentWidget);
+}
+
+QWidget *QDesignerFormBuilder::create(DomUI *ui, QWidget *parentWidget)
+{
+ m_mainWidget = true;
+ QtResourceSet *resourceSet = core()->resourceModel()->currentResourceSet();
+
+ // reload resource properties;
+ createResources(ui->elementResources());
+ core()->resourceModel()->setCurrentResourceSet(m_tempResourceSet);
+
+ m_ignoreCreateResources = true;
+ DesignerPixmapCache pixmapCache;
+ DesignerIconCache iconCache(&pixmapCache);
+ m_pixmapCache = &pixmapCache;
+ m_iconCache = &iconCache;
+
+ QWidget *widget = QFormBuilder::create(ui, parentWidget);
+
+ core()->resourceModel()->setCurrentResourceSet(resourceSet);
+ core()->resourceModel()->removeResourceSet(m_tempResourceSet);
+ m_tempResourceSet = 0;
+ m_ignoreCreateResources = false;
+ m_pixmapCache = 0;
+ m_iconCache = 0;
+
+ m_customWidgetsWithScript.clear();
+ return widget;
+}
+
+QWidget *QDesignerFormBuilder::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name)
+{
+ QWidget *widget = 0;
+
+ if (widgetName == QLatin1String("QToolBar")) {
+ widget = new QToolBar(parentWidget);
+ } else if (widgetName == QLatin1String("QMenu")) {
+ widget = new QMenu(parentWidget);
+ } else if (widgetName == QLatin1String("QMenuBar")) {
+ widget = new QMenuBar(parentWidget);
+ } else {
+ widget = core()->widgetFactory()->createWidget(widgetName, parentWidget);
+ }
+
+ if (widget) {
+ widget->setObjectName(name);
+ if (QSimpleResource::hasCustomWidgetScript(m_core, widget))
+ m_customWidgetsWithScript.insert(widget);
+ }
+
+ if (m_mainWidget) { // We need to apply the DPI here to take effect on size hints, etc.
+ m_deviceProfile.apply(m_core, widget, DeviceProfile::ApplyPreview);
+ m_mainWidget = false;
+ }
+ return widget;
+}
+
+bool QDesignerFormBuilder::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
+{
+ // Use container extension or rely on scripts unless main window.
+ if (QFormBuilder::addItem(ui_widget, widget, parentWidget))
+ return true;
+
+ if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), parentWidget)) {
+ container->addWidget(widget);
+ return true;
+ }
+ return false;
+}
+
+bool QDesignerFormBuilder::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout)
+{
+ return QFormBuilder::addItem(ui_item, item, layout);
+}
+
+QIcon QDesignerFormBuilder::nameToIcon(const QString &filePath, const QString &qrcPath)
+{
+ Q_UNUSED(filePath)
+ Q_UNUSED(qrcPath)
+ qWarning() << "QDesignerFormBuilder::nameToIcon() is obsoleted";
+ return QIcon();
+}
+
+QPixmap QDesignerFormBuilder::nameToPixmap(const QString &filePath, const QString &qrcPath)
+{
+ Q_UNUSED(filePath)
+ Q_UNUSED(qrcPath)
+ qWarning() << "QDesignerFormBuilder::nameToPixmap() is obsoleted";
+ return QPixmap();
+}
+
+/* If the property is a enum or flag value, retrieve
+ * the existing enum/flag type via property sheet and use it to convert */
+
+static bool readDomEnumerationValue(const DomProperty *p,
+ const QDesignerPropertySheetExtension* sheet,
+ QVariant &v)
+{
+ switch (p->kind()) {
+ case DomProperty::Set: {
+ const int index = sheet->indexOf(p->attributeName());
+ if (index == -1)
+ return false;
+ 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 int index = sheet->indexOf(p->attributeName());
+ if (index == -1)
+ return false;
+ 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 QDesignerFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &properties)
+{
+ typedef QList<DomProperty*> DomPropertyList;
+
+ if (properties.empty())
+ return;
+
+ QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this);
+ const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o);
+ const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), o);
+ const bool changingMetaObject = WidgetFactory::classNameOf(core(), o) == QLatin1String("QAxWidget");
+ const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(o);
+ const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed();
+
+ QDesignerPropertySheet *designerPropertySheet = qobject_cast<QDesignerPropertySheet *>(
+ core()->extensionManager()->extension(o, Q_TYPEID(QDesignerPropertySheetExtension)));
+
+ if (designerPropertySheet) {
+ if (designerPropertySheet->pixmapCache())
+ designerPropertySheet->setPixmapCache(m_pixmapCache);
+ if (designerPropertySheet->iconCache())
+ designerPropertySheet->setIconCache(m_iconCache);
+ }
+
+ const DomPropertyList::const_iterator cend = properties.constEnd();
+ for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
+ DomProperty *p = *it;
+ QVariant v;
+ if (!readDomEnumerationValue(p, sheet, v))
+ v = toVariant(o->metaObject(), p);
+
+ if (v.isNull())
+ continue;
+
+ const QString attributeName = p->attributeName();
+ if (formBuilderExtra->applyPropertyInternally(o, attributeName, v))
+ continue;
+
+ // refuse fake properties like current tab name (weak test)
+ if (!dynamicPropertiesAllowed) {
+ if (changingMetaObject) // Changes after setting control of QAxWidget
+ meta = core()->introspection()->metaObject(o);
+ if (meta->indexOfProperty(attributeName) == -1)
+ continue;
+ }
+
+ QObject *obj = o;
+ QAbstractScrollArea *scroll = qobject_cast<QAbstractScrollArea *>(o);
+ if (scroll && attributeName == QLatin1String("cursor") && scroll->viewport())
+ obj = scroll->viewport();
+
+ // a real property
+ obj->setProperty(attributeName.toUtf8(), v);
+ }
+}
+
+DomWidget *QDesignerFormBuilder::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive)
+{
+ DomWidget *ui_widget = QFormBuilder::createDom(widget, ui_parentWidget, recursive);
+ QSimpleResource::addExtensionDataToDOM(this, m_core, ui_widget, widget);
+ return ui_widget;
+}
+
+QWidget *QDesignerFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget)
+{
+ QWidget *widget = QFormBuilder::create(ui_widget, parentWidget);
+ // Do not apply state if scripts are to be run in preview mode
+ QSimpleResource::applyExtensionDataFromDOM(this, m_core, ui_widget, widget, m_mode == DisableScripts);
+ return widget;
+}
+
+void QDesignerFormBuilder::createResources(DomResources *resources)
+{
+ if (m_ignoreCreateResources)
+ return;
+ QStringList paths;
+ if (resources != 0) {
+ const QList<DomResource*> dom_include = resources->elementInclude();
+ foreach (DomResource *res, dom_include) {
+ QString path = QDir::cleanPath(workingDirectory().absoluteFilePath(res->attributeLocation()));
+ paths << path;
+ }
+ }
+
+ m_tempResourceSet = core()->resourceModel()->addResourceSet(paths);
+}
+
+QLayout *QDesignerFormBuilder::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget)
+{
+ return QFormBuilder::create(ui_layout, layout, parentWidget);
+}
+
+void QDesignerFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
+{
+ QFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget);
+}
+
+QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw,
+ const QString &styleName,
+ const QString &appStyleSheet,
+ const DeviceProfile &deviceProfile,
+ ScriptErrors *scriptErrors,
+ QString *errorMessage)
+{
+ scriptErrors->clear();
+
+ // load
+ QDesignerFormBuilder builder(fw->core(), EnableScripts, deviceProfile);
+ builder.setWorkingDirectory(fw->absoluteDir());
+
+ const bool warningsEnabled = QSimpleResource::setWarningsEnabled(false);
+ QByteArray bytes = fw->contents().toUtf8();
+ QSimpleResource::setWarningsEnabled(warningsEnabled);
+
+ QBuffer buffer(&bytes);
+ buffer.open(QIODevice::ReadOnly);
+
+ QWidget *widget = builder.load(&buffer, 0);
+ if (!widget) { // Shouldn't happen
+ *errorMessage = QCoreApplication::translate("QDesignerFormBuilder", "The preview failed to build.");
+ return 0;
+ }
+ // Make sure palette is applied
+ const QString styleToUse = styleName.isEmpty() ? builder.deviceProfile().style() : styleName;
+ if (!styleToUse.isEmpty()) {
+ if (WidgetFactory *wf = qobject_cast<qdesigner_internal::WidgetFactory *>(fw->core()->widgetFactory())) {
+ if (styleToUse != wf->styleName())
+ WidgetFactory::applyStyleToTopLevel(wf->getStyle(styleToUse), widget);
+ }
+ }
+ // Check for script errors
+ *scriptErrors = builder.formScriptRunner()->errors();
+ if (!scriptErrors->empty()) {
+ *errorMessage = summarizeScriptErrors(*scriptErrors);
+ delete widget;
+ return 0;
+ }
+ // Fake application style sheet by prepending. (If this doesn't work, fake by nesting
+ // into parent widget).
+ if (!appStyleSheet.isEmpty()) {
+ QString styleSheet = appStyleSheet;
+ styleSheet += QLatin1Char('\n');
+ styleSheet += widget->styleSheet();
+ widget->setStyleSheet(styleSheet);
+ }
+ return widget;
+}
+
+QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName)
+{
+ return createPreview(fw, styleName, QString());
+}
+
+QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw,
+ const QString &styleName,
+ const QString &appStyleSheet,
+ const DeviceProfile &deviceProfile,
+ QString *errorMessage)
+{
+ ScriptErrors scriptErrors;
+ return createPreview(fw, styleName, appStyleSheet, deviceProfile, &scriptErrors, errorMessage);
+}
+
+QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw,
+ const QString &styleName,
+ const QString &appStyleSheet,
+ QString *errorMessage)
+{
+ ScriptErrors scriptErrors;
+ return createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, errorMessage);
+}
+
+QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet)
+{
+ ScriptErrors scriptErrors;
+ QString errorMessage;
+ QWidget *widget = createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, &errorMessage);
+ if (!widget) {
+ // Display Script errors or message box
+ QWidget *dialogParent = fw->core()->topLevel();
+ if (scriptErrors.empty()) {
+ fw->core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::PreviewFailureMessage,
+ QMessageBox::Warning, QCoreApplication::translate("QDesignerFormBuilder", "Designer"), errorMessage, QMessageBox::Ok);
+ } else {
+ ScriptErrorDialog scriptErrorDialog(scriptErrors, dialogParent);
+ scriptErrorDialog.exec();
+ }
+ return 0;
+ }
+ return widget;
+}
+
+QPixmap QDesignerFormBuilder::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet)
+{
+ QWidget *widget = createPreview(fw, styleName, appStyleSheet);
+ if (!widget)
+ return QPixmap();
+
+ const QPixmap rc = QPixmap::grabWidget (widget);
+ widget->deleteLater();
+ return rc;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h b/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h
new file mode 100644
index 0000000..b982e1c
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_FORMBUILDER_H
+#define QDESIGNER_FORMBUILDER_H
+
+#include "shared_global_p.h"
+#include "deviceprofile_p.h"
+
+#include <QtDesigner/private/formscriptrunner_p.h>
+#include <QtDesigner/formbuilder.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+
+class QPixmap;
+class QtResourceSet;
+
+namespace qdesigner_internal {
+
+class DesignerPixmapCache;
+class DesignerIconCache;
+
+/* Form builder used for previewing forms, widget box and new form dialog.
+ * It applies the system settings to its toplevel window. */
+
+class QDESIGNER_SHARED_EXPORT QDesignerFormBuilder: public QFormBuilder
+{
+public:
+ enum Mode {
+ DisableScripts,
+ EnableScripts
+ };
+
+ QDesignerFormBuilder(QDesignerFormEditorInterface *core,
+ Mode mode,
+ const DeviceProfile &deviceProfile = DeviceProfile());
+
+ QWidget *createWidgetFromContents(const QString &contents, QWidget *parentWidget = 0);
+
+ virtual QWidget *createWidget(DomWidget *ui_widget, QWidget *parentWidget = 0)
+ { return QFormBuilder::create(ui_widget, parentWidget); }
+
+ inline QDesignerFormEditorInterface *core() const
+ { return m_core; }
+
+ QString systemStyle() const;
+
+ typedef QFormScriptRunner::Errors ScriptErrors;
+ // Create a preview widget (for integrations) or return 0. The widget has to be embedded into a main window.
+ // Experimental, depending on script support.
+ static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName /* ="" */,
+ const QString &appStyleSheet /* ="" */,
+ const DeviceProfile &deviceProfile,
+ ScriptErrors *scriptErrors, QString *errorMessage);
+ // Convenience that pops up message boxes in case of failures.
+ static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName = QString());
+ // Create a preview widget (for integrations) or return 0. The widget has to be embedded into a main window.
+ static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet, QString *errorMessage);
+ static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet, const DeviceProfile &deviceProfile, QString *errorMessage);
+ // Convenience that pops up message boxes in case of failures.
+ static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet);
+
+ // Create a preview image
+ static QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &styleName = QString(), const QString &appStyleSheet = QString());
+
+protected:
+ using QFormBuilder::createDom;
+ using QFormBuilder::create;
+
+ virtual QWidget *create(DomUI *ui, QWidget *parentWidget);
+ virtual DomWidget *createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive = true);
+ virtual QWidget *create(DomWidget *ui_widget, QWidget *parentWidget);
+ virtual QLayout *create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget);
+ virtual void createResources(DomResources *resources);
+
+ virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name);
+ virtual bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget);
+ virtual bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout);
+
+ virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath);
+ virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath);
+
+ virtual void applyProperties(QObject *o, const QList<DomProperty*> &properties);
+
+ virtual void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget);
+
+ QtResourceSet *internalResourceSet() const { return m_tempResourceSet; }
+
+ DeviceProfile deviceProfile() const { return m_deviceProfile; }
+
+private:
+ QDesignerFormEditorInterface *m_core;
+ const Mode m_mode;
+
+ typedef QSet<QWidget *> WidgetSet;
+ WidgetSet m_customWidgetsWithScript;
+
+ const DeviceProfile m_deviceProfile;
+
+ DesignerPixmapCache *m_pixmapCache;
+ DesignerIconCache *m_iconCache;
+ bool m_ignoreCreateResources;
+ QtResourceSet *m_tempResourceSet;
+ bool m_mainWidget;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_FORMBUILDER_H
diff --git a/tools/designer/src/lib/shared/qdesigner_formeditorcommand.cpp b/tools/designer/src/lib/shared/qdesigner_formeditorcommand.cpp
new file mode 100644
index 0000000..5e5e661
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formeditorcommand.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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_formeditorcommand_p.h"
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// ---- QDesignerFormEditorCommand ----
+QDesignerFormEditorCommand::QDesignerFormEditorCommand(const QString &description, QDesignerFormEditorInterface *core)
+ : QUndoCommand(description),
+ m_core(core)
+{
+}
+
+QDesignerFormEditorInterface *QDesignerFormEditorCommand::core() const
+{
+ return m_core;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_formeditorcommand_p.h b/tools/designer/src/lib/shared/qdesigner_formeditorcommand_p.h
new file mode 100644
index 0000000..b0fdd77
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formeditorcommand_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_FORMEDITORCOMMAND_H
+#define QDESIGNER_FORMEDITORCOMMAND_H
+
+#include "shared_global_p.h"
+#include <QtCore/QPointer>
+#include <QtGui/QUndoCommand>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT QDesignerFormEditorCommand: public QUndoCommand
+{
+
+public:
+ QDesignerFormEditorCommand(const QString &description, QDesignerFormEditorInterface *core);
+
+protected:
+ QDesignerFormEditorInterface *core() const;
+
+private:
+ QPointer<QDesignerFormEditorInterface> m_core;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_FORMEDITORCOMMAND_H
diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp b/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp
new file mode 100644
index 0000000..9d6d57e
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formwindowcommand.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 "qdesigner_formwindowcommand_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "layout_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerObjectInspectorInterface>
+#include <QtDesigner/QDesignerActionEditorInterface>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QVariant>
+#include <QtGui/QWidget>
+#include <QtGui/QLabel>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// ---- QDesignerFormWindowCommand ----
+QDesignerFormWindowCommand::QDesignerFormWindowCommand(const QString &description, QDesignerFormWindowInterface *formWindow)
+ : QUndoCommand(description),
+ m_formWindow(formWindow)
+{
+}
+
+QDesignerFormWindowInterface *QDesignerFormWindowCommand::formWindow() const
+{
+ return m_formWindow;
+}
+
+QDesignerFormEditorInterface *QDesignerFormWindowCommand::core() const
+{
+ if (QDesignerFormWindowInterface *fw = formWindow())
+ return fw->core();
+
+ return 0;
+}
+
+void QDesignerFormWindowCommand::undo()
+{
+ cheapUpdate();
+}
+
+void QDesignerFormWindowCommand::redo()
+{
+ cheapUpdate();
+}
+
+void QDesignerFormWindowCommand::cheapUpdate()
+{
+ if (core()->objectInspector())
+ core()->objectInspector()->setFormWindow(formWindow());
+
+ if (core()->actionEditor())
+ core()->actionEditor()->setFormWindow(formWindow());
+}
+
+QDesignerPropertySheetExtension* QDesignerFormWindowCommand::propertySheet(QObject *object) const
+{
+ return qt_extension<QDesignerPropertySheetExtension*>(formWindow()->core()->extensionManager(), object);
+}
+
+void QDesignerFormWindowCommand::updateBuddies(QDesignerFormWindowInterface *form,
+ const QString &old_name,
+ const QString &new_name)
+{
+ QExtensionManager* extensionManager = form->core()->extensionManager();
+
+ typedef QList<QLabel*> LabelList;
+
+ const LabelList label_list = qFindChildren<QLabel*>(form);
+ if (label_list.empty())
+ return;
+
+ const QString buddyProperty = QLatin1String("buddy");
+ const QByteArray oldNameU8 = old_name.toUtf8();
+ const QByteArray newNameU8 = new_name.toUtf8();
+
+ const LabelList::const_iterator cend = label_list.constEnd();
+ for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) {
+ if (QDesignerPropertySheetExtension* sheet = qt_extension<QDesignerPropertySheetExtension*>(extensionManager, *it)) {
+ const int idx = sheet->indexOf(buddyProperty);
+ if (idx != -1) {
+ const QByteArray oldBuddy = sheet->property(idx).toByteArray();
+ if (oldBuddy == oldNameU8)
+ sheet->setProperty(idx, newNameU8);
+ }
+ }
+ }
+}
+
+void QDesignerFormWindowCommand::selectUnmanagedObject(QObject *unmanagedObject)
+{
+ // Keep selection in sync
+ if (QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(core()->objectInspector())) {
+ oi->clearSelection();
+ oi->selectObject(unmanagedObject);
+ }
+ core()->propertyEditor()->setObject(unmanagedObject);
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h b/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h
new file mode 100644
index 0000000..f640e66
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_FORMWINDOWCOMMAND_H
+#define QDESIGNER_FORMWINDOWCOMMAND_H
+
+#include "shared_global_p.h"
+
+#include <QtCore/QPointer>
+#include <QtGui/QUndoCommand>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+class QDesignerPropertySheetExtension;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand: public QUndoCommand
+{
+
+public:
+ QDesignerFormWindowCommand(const QString &description, QDesignerFormWindowInterface *formWindow);
+
+ virtual void undo();
+ virtual void redo();
+
+ static void updateBuddies(QDesignerFormWindowInterface *form,
+ const QString &old_name, const QString &new_name);
+protected:
+ QDesignerFormWindowInterface *formWindow() const;
+ QDesignerFormEditorInterface *core() const;
+ QDesignerPropertySheetExtension* propertySheet(QObject *object) const;
+
+ void cheapUpdate();
+
+ void selectUnmanagedObject(QObject *unmanagedObject);
+private:
+ QPointer<QDesignerFormWindowInterface> m_formWindow;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_COMMAND_H
diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowmanager.cpp b/tools/designer/src/lib/shared/qdesigner_formwindowmanager.cpp
new file mode 100644
index 0000000..87213b4
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formwindowmanager.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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_formwindowmanager_p.h"
+#include "plugindialog_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+QT_BEGIN_NAMESPACE
+
+using namespace qdesigner_internal;
+
+/*!
+ \class QDesignerFormWindowManager
+
+ Extends QDesignerFormWindowManagerInterface with methods to control
+ the preview and printing of forms. It provides a facade that simplifies
+ the complexity of the more general PreviewConfiguration & PreviewManager
+ interfaces.
+
+ \since 4.5
+ */
+
+
+QDesignerFormWindowManager::QDesignerFormWindowManager(QObject *parent)
+ : QDesignerFormWindowManagerInterface(parent), m_unused(0)
+{
+}
+
+QDesignerFormWindowManager::~QDesignerFormWindowManager()
+{
+}
+
+/*!
+ Allows you to intervene and control \QD's form "Preview" action. The
+ function returns the original action.
+
+ \since 4.5
+ */
+QAction *QDesignerFormWindowManager::actionDefaultPreview() const
+{
+ return 0;
+}
+
+/*!
+ Allows you to intervene and control \QD's form "Preview in" style action. The
+ function returns the original list of actions.
+
+ The method calls PreviewManager::createStyleActionGroup() internally.
+
+ \since 4.5
+ */
+QActionGroup *QDesignerFormWindowManager::actionGroupPreviewInStyle() const
+{
+ return 0;
+}
+
+/*!
+ \fn QPixmap QDesignerFormWindowManager::createPreviewPixmap(QString *errorMessage)
+
+ Creates a pixmap representing the preview of the currently active form.
+
+ The method calls PreviewManager::createPreviewPixmap() internally.
+
+ \since 4.5
+ */
+
+
+/*!
+ \fn QPixmap QDesignerFormWindowManager::closeAllPreviews()
+
+ Closes all preview windows generated by actionDefaultPreview, actionGroupPreviewInStyle
+ and the corresponding methods in PreviewManager.
+
+ \since 4.5
+ */
+
+/*!
+ \fn PreviewManager *QDesignerFormWindowManager::previewManager()
+
+ Accesses the previewmanager implementation.
+
+ \since 4.5
+ \internal
+ */
+
+/*!
+ \fn QAction *QDesignerFormWindowManager::actionShowFormWindowSettingsDialog() const;
+
+ Allows you to intervene and control \QD's form "Form Settings" action. The
+ function returns the original action.
+
+ \since 4.5
+ \internal
+ */
+
+QAction *QDesignerFormWindowManager::actionShowFormWindowSettingsDialog() const
+{
+ return 0;
+}
+
+/*!
+ \fn void QDesignerFormWindowManager::aboutPlugins()
+
+ Pops up an "About plugins" dialog.
+
+ \since 4.5
+ \internal
+ */
+
+void QDesignerFormWindowManager::aboutPlugins()
+{
+ PluginDialog dlg(core(), core()->topLevel());
+ dlg.exec();
+}
+
+/*!
+ \fn
+ void QDesignerFormWindowManager::formWindowSettingsChanged(QDesignerFormWindowInterface *fw);
+
+ This signal is emitted when the form settings dialog was shown
+ and changes have been made to the form.
+
+ \since 4.5
+ \internal
+ */
+
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowmanager_p.h b/tools/designer/src/lib/shared/qdesigner_formwindowmanager_p.h
new file mode 100644
index 0000000..61aee72
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_formwindowmanager_p.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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_FORMWINDOMANAGER_H
+#define QDESIGNER_FORMWINDOMANAGER_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class PreviewManager;
+
+//
+// Convenience methods to manage form previews (ultimately forwarded to PreviewManager).
+//
+class QDESIGNER_SHARED_EXPORT QDesignerFormWindowManager
+ : public QDesignerFormWindowManagerInterface
+{
+ Q_OBJECT
+public:
+ explicit QDesignerFormWindowManager(QObject *parent = 0);
+ virtual ~QDesignerFormWindowManager();
+
+ virtual QAction *actionDefaultPreview() const;
+ virtual QActionGroup *actionGroupPreviewInStyle() const;
+ virtual QAction *actionShowFormWindowSettingsDialog() const;
+
+ virtual QPixmap createPreviewPixmap(QString *errorMessage) = 0;
+
+ virtual PreviewManager *previewManager() const = 0;
+
+Q_SIGNALS:
+ void formWindowSettingsChanged(QDesignerFormWindowInterface *fw);
+
+public Q_SLOTS:
+ virtual void closeAllPreviews() = 0;
+ void aboutPlugins();
+
+private:
+ void *m_unused;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_FORMWINDOMANAGER_H
diff --git a/tools/designer/src/lib/shared/qdesigner_integration.cpp b/tools/designer/src/lib/shared/qdesigner_integration.cpp
new file mode 100644
index 0000000..02e0246
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_integration.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** 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_integration_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "qdesigner_propertyeditor_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "widgetdatabase_p.h"
+#include "pluginmanager_p.h"
+#include "widgetfactory_p.h"
+#include "qdesigner_widgetbox_p.h"
+#include "qtgradientmanager.h"
+#include "qtgradientutils.h"
+#include "qtresourcemodel_p.h"
+
+// sdk
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtDesigner/QDesignerActionEditorInterface>
+#include <QtDesigner/QDesignerWidgetBoxInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerResourceBrowserInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+
+#include <QtCore/QVariant>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// ---------------- DesignerIntegrationPrivate
+class QDesignerIntegrationPrivate {
+public:
+ QDesignerIntegrationPrivate()
+ : m_gradientManager(0),
+ m_fileWatcherBehaviour(QDesignerIntegration::PromptAndReload),
+ m_resourceEditingEnabled(true),
+ m_slotNavigationEnabled(false)
+ {}
+
+ QString m_gradientsPath;
+ QtGradientManager *m_gradientManager;
+ QDesignerIntegration::ResourceFileWatcherBehaviour m_fileWatcherBehaviour;
+ bool m_resourceEditingEnabled;
+ bool m_slotNavigationEnabled;
+};
+
+// -------------- QDesignerIntegration
+// As of 4.4, the header will be distributed with the Eclipse plugin.
+
+QDesignerIntegration::QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent) :
+ QDesignerIntegrationInterface(core, parent),
+ m_d(new QDesignerIntegrationPrivate)
+{
+ initialize();
+}
+
+QDesignerIntegration::~QDesignerIntegration()
+{
+ QFile f(m_d->m_gradientsPath);
+ if (f.open(QIODevice::WriteOnly)) {
+ f.write(QtGradientUtils::saveState(m_d->m_gradientManager).toUtf8());
+ f.close();
+ }
+ delete m_d;
+}
+
+void QDesignerIntegration::initialize()
+{
+ //
+ // integrate the `Form Editor component'
+ //
+
+ // Extensions
+ if (QDesignerPropertyEditor *designerPropertyEditor= qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor())) {
+ connect(designerPropertyEditor, SIGNAL(propertyValueChanged(QString, QVariant, bool)), this, SLOT(updateProperty(QString, QVariant, bool)));
+ connect(designerPropertyEditor, SIGNAL(resetProperty(QString)), this, SLOT(resetProperty(QString)));
+ connect(designerPropertyEditor, SIGNAL(addDynamicProperty(QString,QVariant)),
+ this, SLOT(addDynamicProperty(QString,QVariant)));
+ connect(designerPropertyEditor, SIGNAL(removeDynamicProperty(QString)),
+ this, SLOT(removeDynamicProperty(QString)));
+ } else {
+ connect(core()->propertyEditor(), SIGNAL(propertyChanged(QString,QVariant)),
+ this, SLOT(updatePropertyPrivate(QString,QVariant)));
+ }
+
+ connect(core()->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)),
+ this, SLOT(setupFormWindow(QDesignerFormWindowInterface*)));
+
+ connect(core()->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)),
+ this, SLOT(updateActiveFormWindow(QDesignerFormWindowInterface*)));
+
+ m_d->m_gradientManager = new QtGradientManager(this);
+ core()->setGradientManager(m_d->m_gradientManager);
+
+ QString designerFolder = QDir::homePath();
+ designerFolder += QDir::separator();
+ designerFolder += QLatin1String(".designer");
+ m_d->m_gradientsPath = designerFolder;
+ m_d->m_gradientsPath += QDir::separator();
+ m_d->m_gradientsPath += QLatin1String("gradients.xml");
+
+ QFile f(m_d->m_gradientsPath);
+ if (f.open(QIODevice::ReadOnly)) {
+ QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(f.readAll()));
+ f.close();
+ } else {
+ QFile defaultGradients(QLatin1String(":/trolltech/designer/defaultgradients.xml"));
+ if (defaultGradients.open(QIODevice::ReadOnly)) {
+ QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(defaultGradients.readAll()));
+ defaultGradients.close();
+ }
+ }
+
+ if (WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(core()->widgetDataBase()))
+ widgetDataBase->grabStandardWidgetBoxIcons();
+}
+
+void QDesignerIntegration::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
+{
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ if (!formWindow)
+ return;
+
+ Selection selection;
+ getSelection(selection);
+ if (selection.empty())
+ return;
+
+ SetPropertyCommand *cmd = new SetPropertyCommand(formWindow);
+ // find a reference object to compare to and to find the right group
+ if (cmd->init(selection.selection(), name, value, propertyEditorObject(), enableSubPropertyHandling)) {
+ formWindow->commandHistory()->push(cmd);
+ } else {
+ delete cmd;
+ qDebug() << "Unable to set property " << name << '.';
+ }
+
+ emit propertyChanged(formWindow, name, value);
+}
+
+void QDesignerIntegration::updatePropertyPrivate(const QString &name, const QVariant &value)
+{
+ updateProperty(name, value, true);
+}
+
+void QDesignerIntegration::resetProperty(const QString &name)
+{
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ if (!formWindow)
+ return;
+
+ Selection selection;
+ getSelection(selection);
+ if (selection.empty())
+ return;
+
+
+ ResetPropertyCommand *cmd = new ResetPropertyCommand(formWindow);
+ // find a reference object to find the right group
+ if (cmd->init(selection.selection(), name, propertyEditorObject())) {
+ formWindow->commandHistory()->push(cmd);
+ } else {
+ delete cmd;
+ qDebug() << "** WARNING Unable to reset property " << name << '.';
+ }
+}
+
+void QDesignerIntegration::addDynamicProperty(const QString &name, const QVariant &value)
+{
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ if (!formWindow)
+ return;
+
+ Selection selection;
+ getSelection(selection);
+ if (selection.empty())
+ return;
+
+ AddDynamicPropertyCommand *cmd = new AddDynamicPropertyCommand(formWindow);
+ if (cmd->init(selection.selection(), propertyEditorObject(), name, value)) {
+ formWindow->commandHistory()->push(cmd);
+ } else {
+ delete cmd;
+ qDebug() << "** WARNING Unable to add dynamic property " << name << '.';
+ }
+}
+
+void QDesignerIntegration::removeDynamicProperty(const QString &name)
+{
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ if (!formWindow)
+ return;
+
+ Selection selection;
+ getSelection(selection);
+ if (selection.empty())
+ return;
+
+ RemoveDynamicPropertyCommand *cmd = new RemoveDynamicPropertyCommand(formWindow);
+ if (cmd->init(selection.selection(), propertyEditorObject(), name)) {
+ formWindow->commandHistory()->push(cmd);
+ } else {
+ delete cmd;
+ qDebug() << "** WARNING Unable to remove dynamic property " << name << '.';
+ }
+
+}
+
+
+void QDesignerIntegration::updateActiveFormWindow(QDesignerFormWindowInterface *formWindow)
+{
+ Q_UNUSED(formWindow);
+ updateSelection();
+}
+
+void QDesignerIntegration::setupFormWindow(QDesignerFormWindowInterface *formWindow)
+{
+ connect(formWindow, SIGNAL(selectionChanged()), this, SLOT(updateSelection()));
+ connect(formWindow, SIGNAL(activated(QWidget*)), this, SLOT(activateWidget(QWidget*)));
+}
+
+void QDesignerIntegration::updateGeometry()
+{
+}
+
+void QDesignerIntegration::updateSelection()
+{
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ QWidget *selection = 0;
+
+ if (formWindow) {
+ selection = formWindow->cursor()->current();
+ }
+
+ if (QDesignerActionEditorInterface *actionEditor = core()->actionEditor())
+ actionEditor->setFormWindow(formWindow);
+
+ if (QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor())
+ propertyEditor->setObject(selection);
+
+ if (QDesignerObjectInspectorInterface *objectInspector = core()->objectInspector())
+ objectInspector->setFormWindow(formWindow);
+
+}
+
+void QDesignerIntegration::activateWidget(QWidget *widget)
+{
+ Q_UNUSED(widget);
+}
+
+QWidget *QDesignerIntegration::containerWindow(QWidget *widget) const
+{
+ // Find the parent window to apply a geometry to.
+ while (widget) {
+ if (widget->isWindow())
+ break;
+ if (!qstrcmp(widget->metaObject()->className(), "QMdiSubWindow"))
+ break;
+
+ widget = widget->parentWidget();
+ }
+
+ return widget;
+}
+
+void QDesignerIntegration::getSelection(Selection &s)
+{
+ // Get multiselection from object inspector
+ if (QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(core()->objectInspector())) {
+ designerObjectInspector->getSelection(s);
+ // Action editor puts actions that are not on the form yet
+ // into the property editor only.
+ if (s.empty())
+ if (QObject *object = core()->propertyEditor()->object())
+ s.objects.push_back(object);
+
+ } else {
+ // Just in case someone plugs in an old-style object inspector: Emulate selection
+ s.clear();
+ QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
+ if (!formWindow)
+ return;
+
+ QObject *object = core()->propertyEditor()->object();
+ if (object->isWidgetType()) {
+ QWidget *widget = static_cast<QWidget*>(object);
+ QDesignerFormWindowCursorInterface *cursor = formWindow->cursor();
+ if (cursor->isWidgetSelected(widget)) {
+ s.managed.push_back(widget);
+ } else {
+ s.unmanaged.push_back(widget);
+ }
+ } else {
+ s.objects.push_back(object);
+ }
+ }
+}
+
+QObject *QDesignerIntegration::propertyEditorObject()
+{
+ QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor();
+ if (!propertyEditor)
+ return 0;
+ return propertyEditor->object();
+}
+
+// Load plugins into widget database and factory.
+void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor)
+{
+ // load the plugins
+ WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(formEditor->widgetDataBase());
+ if (widgetDataBase) {
+ widgetDataBase->loadPlugins();
+ }
+
+ if (WidgetFactory *widgetFactory = qobject_cast<WidgetFactory*>(formEditor->widgetFactory())) {
+ widgetFactory->loadPlugins();
+ }
+
+ if (widgetDataBase) {
+ widgetDataBase->grabDefaultPropertyValues();
+ }
+}
+
+void QDesignerIntegration::updateCustomWidgetPlugins()
+{
+ QDesignerFormEditorInterface *formEditor = core();
+ if (QDesignerPluginManager *pm = formEditor->pluginManager())
+ pm->registerNewPlugins();
+
+ initializePlugins(formEditor);
+
+ // Do not just reload the last file as the WidgetBox merges the compiled-in resources
+ // and $HOME/.designer/widgetbox.xml. This would also double the scratchpad.
+ if (QDesignerWidgetBox *wb = qobject_cast<QDesignerWidgetBox*>(formEditor->widgetBox())) {
+ const QDesignerWidgetBox::LoadMode oldLoadMode = wb->loadMode();
+ wb->setLoadMode(QDesignerWidgetBox::LoadCustomWidgetsOnly);
+ wb->load();
+ wb->setLoadMode(oldLoadMode);
+ }
+}
+
+void QDesignerIntegration::emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName)
+{
+ emit objectNameChanged(formWindow, object, newName, oldName);
+}
+
+void QDesignerIntegration::emitNavigateToSlot(const QString &objectName,
+ const QString &signalSignature,
+ const QStringList &parameterNames)
+{
+ emit navigateToSlot(objectName, signalSignature, parameterNames);
+}
+
+void QDesignerIntegration::emitNavigateToSlot(const QString &slotSignature)
+{
+ emit navigateToSlot(slotSignature);
+}
+
+void QDesignerIntegration::requestHelp(const QDesignerFormEditorInterface *core, const QString &manual, const QString &document)
+{
+ if (QDesignerIntegration *di = qobject_cast<QDesignerIntegration *>(core->integration()))
+ emit di->helpRequested(manual, document);
+}
+
+QDesignerResourceBrowserInterface *QDesignerIntegration::createResourceBrowser(QWidget *)
+{
+ return 0;
+}
+
+void QDesignerIntegration::setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour)
+{
+ m_d->m_fileWatcherBehaviour = behaviour;
+ core()->resourceModel()->setWatcherEnabled(behaviour != QDesignerIntegration::NoWatcher);
+}
+
+QDesignerIntegration::ResourceFileWatcherBehaviour QDesignerIntegration::resourceFileWatcherBehaviour() const
+{
+ return m_d->m_fileWatcherBehaviour;
+}
+
+void QDesignerIntegration::setResourceEditingEnabled(bool enable)
+{
+ m_d->m_resourceEditingEnabled = enable;
+}
+
+bool QDesignerIntegration::isResourceEditingEnabled() const
+{
+ return m_d->m_resourceEditingEnabled;
+}
+
+void QDesignerIntegration::setSlotNavigationEnabled(bool enable)
+{
+ m_d->m_slotNavigationEnabled = enable;
+}
+
+bool QDesignerIntegration::isSlotNavigationEnabled() const
+{
+ return m_d->m_slotNavigationEnabled;
+}
+
+static QString fixHelpClassName(const QString &className)
+{
+ // ### generalize using the Widget Data Base
+ if (className == QLatin1String("Line"))
+ return QLatin1String("QFrame");
+ if (className == QLatin1String("Spacer"))
+ return QLatin1String("QSpacerItem");
+ if (className == QLatin1String("QLayoutWidget"))
+ return QLatin1String("QLayout");
+ return className;
+}
+
+// Return class in which the property is defined
+static QString classForProperty(QDesignerFormEditorInterface *core,
+ QObject *object,
+ const QString &property)
+{
+ if (const QDesignerPropertySheetExtension *ps = qt_extension<QDesignerPropertySheetExtension *>(core->extensionManager(), object)) {
+ const int index = ps->indexOf(property);
+ if (index >= 0)
+ return ps->propertyGroup(index);
+ }
+ return QString();
+}
+
+QString QDesignerIntegration::contextHelpId() const
+{
+ QObject *currentObject = core()->propertyEditor()->object();
+ if (!currentObject)
+ return QString();
+ // Return a help index id consisting of "class::property"
+ QString className;
+ QString currentPropertyName = core()->propertyEditor()->currentPropertyName();
+ if (!currentPropertyName.isEmpty())
+ className = classForProperty(core(), currentObject, currentPropertyName);
+ if (className.isEmpty()) {
+ currentPropertyName.clear(); // We hit on some fake property.
+ className = WidgetFactory::classNameOf(core(), currentObject);
+ }
+ QString helpId = fixHelpClassName(className);
+ if (!currentPropertyName.isEmpty()) {
+ helpId += QLatin1String("::");
+ helpId += currentPropertyName;
+ }
+ return helpId;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_integration_p.h b/tools/designer/src/lib/shared/qdesigner_integration_p.h
new file mode 100644
index 0000000..6938bfb
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_integration_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_INTEGRATION_H
+#define QDESIGNER_INTEGRATION_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/QDesignerIntegrationInterface>
+
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+class QDesignerResourceBrowserInterface;
+
+class QVariant;
+class QWidget;
+
+namespace qdesigner_internal {
+
+struct Selection;
+class QDesignerIntegrationPrivate;
+
+class QDESIGNER_SHARED_EXPORT QDesignerIntegration: public QDesignerIntegrationInterface
+{
+ Q_OBJECT
+public:
+ explicit QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent = 0);
+ virtual ~QDesignerIntegration();
+
+ static void requestHelp(const QDesignerFormEditorInterface *core, const QString &manual, const QString &document);
+
+ virtual QWidget *containerWindow(QWidget *widget) const;
+
+ // Load plugins into widget database and factory.
+ static void initializePlugins(QDesignerFormEditorInterface *formEditor);
+ void emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object,
+ const QString &newName, const QString &oldName);
+ void emitNavigateToSlot(const QString &objectName, const QString &signalSignature, const QStringList &parameterNames);
+ void emitNavigateToSlot(const QString &slotSignature);
+
+ // Create a resource browser specific to integration. Language integration takes precedence
+ virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = 0);
+
+ enum ResourceFileWatcherBehaviour {
+ NoWatcher,
+ ReloadSilently,
+ PromptAndReload
+ };
+
+ ResourceFileWatcherBehaviour resourceFileWatcherBehaviour() const;
+ bool isResourceEditingEnabled() const;
+ bool isSlotNavigationEnabled() const;
+
+ QString contextHelpId() const;
+
+protected:
+
+ void setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour); // PromptAndReload by default
+ void setResourceEditingEnabled(bool enable); // true by default
+ void setSlotNavigationEnabled(bool enable); // false by default
+
+signals:
+ void propertyChanged(QDesignerFormWindowInterface *formWindow, const QString &name, const QVariant &value);
+ void objectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName);
+ void helpRequested(const QString &manual, const QString &document);
+
+ void navigateToSlot(const QString &objectName, const QString &signalSignature, const QStringList &parameterNames);
+ void navigateToSlot(const QString &slotSignature);
+
+public slots:
+ virtual void updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling);
+ // Additional signals of designer property editor
+ virtual void resetProperty(const QString &name);
+ virtual void addDynamicProperty(const QString &name, const QVariant &value);
+ virtual void removeDynamicProperty(const QString &name);
+
+ virtual void updateActiveFormWindow(QDesignerFormWindowInterface *formWindow);
+ virtual void setupFormWindow(QDesignerFormWindowInterface *formWindow);
+ virtual void updateSelection();
+ virtual void updateGeometry();
+ virtual void activateWidget(QWidget *widget);
+
+ void updateCustomWidgetPlugins();
+
+private slots:
+ void updatePropertyPrivate(const QString &name, const QVariant &value);
+
+private:
+ void initialize();
+ void getSelection(Selection &s);
+ QObject *propertyEditorObject();
+
+ QDesignerIntegrationPrivate *m_d;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_INTEGRATION_H
diff --git a/tools/designer/src/lib/shared/qdesigner_introspection.cpp b/tools/designer/src/lib/shared/qdesigner_introspection.cpp
new file mode 100644
index 0000000..c512a97
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_introspection.cpp
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** 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_introspection_p.h"
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaEnum>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+
+// Qt Implementation
+static QStringList byteArrayListToStringList(const QList<QByteArray> &l)
+{
+ if (l.empty())
+ return QStringList();
+ QStringList rc;
+ const QList<QByteArray>::const_iterator cend = l.constEnd();
+ for (QList<QByteArray>::const_iterator it = l.constBegin(); it != cend; ++it)
+ rc += QString::fromUtf8(*it);
+ return rc;
+}
+
+static inline QString charToQString(const char *c)
+{
+ if (!c)
+ return QString::null;
+ return QString::fromUtf8(c);
+}
+
+namespace {
+ // ------- QDesignerMetaEnum
+ class QDesignerMetaEnum : public QDesignerMetaEnumInterface {
+ public:
+ QDesignerMetaEnum(const QMetaEnum &qEnum);
+ virtual bool isFlag() const { return m_enum.isFlag(); }
+ virtual QString key(int index) const { return charToQString(m_enum.key(index)); }
+ virtual int keyCount() const { return m_enum.keyCount(); }
+ virtual int keyToValue(const QString &key) const { return m_enum.keyToValue(key.toUtf8()); }
+ virtual int keysToValue(const QString &keys) const { return m_enum.keysToValue(keys.toUtf8()); }
+ virtual QString name() const { return m_name; }
+ virtual QString scope() const { return m_scope; }
+ virtual QString separator() const;
+ virtual int value(int index) const { return m_enum.value(index); }
+ virtual QString valueToKey(int value) const { return charToQString(m_enum.valueToKey(value)); }
+ virtual QString valueToKeys(int value) const { return charToQString(m_enum.valueToKeys(value)); }
+
+ private:
+ const QMetaEnum m_enum;
+ const QString m_name;
+ const QString m_scope;
+ };
+
+ QDesignerMetaEnum::QDesignerMetaEnum(const QMetaEnum &qEnum) :
+ m_enum(qEnum),
+ m_name(charToQString(m_enum.name())),
+ m_scope(charToQString(m_enum.scope()))
+ {
+ }
+
+ QString QDesignerMetaEnum::separator() const
+ {
+ static const QString rc = QLatin1String("::");
+ return rc;
+ }
+
+ // ------- QDesignerMetaProperty
+ class QDesignerMetaProperty : public QDesignerMetaPropertyInterface {
+ public:
+ QDesignerMetaProperty(const QMetaProperty &property);
+ virtual ~QDesignerMetaProperty();
+
+ virtual const QDesignerMetaEnumInterface *enumerator() const { return m_enumerator; }
+
+ virtual Kind kind() const { return m_kind; }
+
+ virtual AccessFlags accessFlags() const { return m_access; }
+ virtual Attributes attributes(const QObject *object = 0) const;
+
+ virtual QVariant::Type type() const { return m_property.type(); }
+ virtual QString name() const { return m_name; }
+ virtual QString typeName() const { return m_typeName; }
+ virtual int userType() const { return m_property.userType(); }
+ virtual bool hasSetter() const { return m_property.hasStdCppSet(); }
+
+ virtual QVariant read(const QObject *object) const { return m_property.read(object); }
+ virtual bool reset(QObject *object) const { return m_property.reset(object); }
+ virtual bool write(QObject *object, const QVariant &value) const { return m_property.write(object, value); }
+
+ private:
+ const QMetaProperty m_property;
+ const QString m_name;
+ const QString m_typeName;
+ Kind m_kind;
+ AccessFlags m_access;
+ Attributes m_defaultAttributes;
+ QDesignerMetaEnumInterface *m_enumerator;
+ };
+
+ QDesignerMetaProperty::QDesignerMetaProperty(const QMetaProperty &property) :
+ m_property(property),
+ m_name(charToQString(m_property.name())),
+ m_typeName(charToQString(m_property.typeName())),
+ m_kind(OtherKind),
+ m_enumerator(0)
+ {
+ if (m_property.isFlagType() || m_property.isEnumType()) {
+ const QMetaEnum metaEnum = m_property.enumerator();
+ Q_ASSERT(metaEnum.isValid());
+ m_enumerator = new QDesignerMetaEnum(metaEnum);
+ }
+ // kind
+ if (m_property.isFlagType())
+ m_kind = FlagKind;
+ else
+ if (m_property.isEnumType())
+ m_kind = EnumKind;
+ // flags and attributes
+ if (m_property.isReadable())
+ m_access |= ReadAccess;
+ if (m_property.isWritable())
+ m_access |= WriteAccess;
+ if (m_property.isResettable())
+ m_access |= ResetAccess;
+
+ if (m_property.isDesignable())
+ m_defaultAttributes |= DesignableAttribute;
+ if (m_property.isScriptable())
+ m_defaultAttributes |= ScriptableAttribute;
+ if (m_property.isStored())
+ m_defaultAttributes |= StoredAttribute;
+ if (m_property.isUser())
+ m_defaultAttributes |= UserAttribute;
+ }
+
+ QDesignerMetaProperty::~QDesignerMetaProperty()
+ {
+ delete m_enumerator;
+ }
+
+ QDesignerMetaProperty::Attributes QDesignerMetaProperty::attributes(const QObject *object) const
+ {
+ if (!object)
+ return m_defaultAttributes;
+ Attributes rc;
+ if (m_property.isDesignable(object))
+ rc |= DesignableAttribute;
+ if (m_property.isScriptable(object))
+ rc |= ScriptableAttribute;
+ if (m_property.isStored(object))
+ rc |= StoredAttribute;
+ if (m_property.isUser(object))
+ rc |= UserAttribute;
+ return rc;
+ }
+
+ // -------------- QDesignerMetaMethod
+
+ class QDesignerMetaMethod : public QDesignerMetaMethodInterface {
+ public:
+ QDesignerMetaMethod(const QMetaMethod &method);
+
+ virtual Access access() const { return m_access; }
+ virtual MethodType methodType() const { return m_methodType; }
+ virtual QStringList parameterNames() const { return m_parameterNames; }
+ virtual QStringList parameterTypes() const { return m_parameterTypes; }
+ virtual QString signature() const { return m_signature; }
+ virtual QString normalizedSignature() const { return m_normalizedSignature; }
+ virtual QString tag() const { return m_tag; }
+ virtual QString typeName() const { return m_typeName; }
+
+ private:
+ Access m_access;
+ MethodType m_methodType;
+ const QStringList m_parameterNames;
+ const QStringList m_parameterTypes;
+ const QString m_signature;
+ const QString m_normalizedSignature;
+ const QString m_tag;
+ const QString m_typeName;
+ };
+
+ QDesignerMetaMethod::QDesignerMetaMethod(const QMetaMethod &method) :
+ m_parameterNames(byteArrayListToStringList(method.parameterNames())),
+ m_parameterTypes(byteArrayListToStringList(method.parameterTypes())),
+ m_signature(charToQString(method.signature())),
+ m_normalizedSignature(charToQString(QMetaObject::normalizedSignature(method.signature()))),
+ m_tag(charToQString(method.tag())),
+ m_typeName(charToQString(method.typeName()))
+ {
+ switch (method.access()) {
+ case QMetaMethod::Public:
+ m_access = Public;
+ break;
+ case QMetaMethod::Protected:
+ m_access = Protected;
+ break;
+ case QMetaMethod::Private:
+ m_access = Private;
+ break;
+
+ }
+ switch (method.methodType()) {
+ case QMetaMethod::Constructor:
+ m_methodType = Constructor;
+ break;
+ case QMetaMethod::Method:
+ m_methodType = Method;
+ break;
+ case QMetaMethod::Signal:
+ m_methodType = Signal;
+ break;
+
+ case QMetaMethod::Slot:
+ m_methodType = Slot;
+ break;
+ }
+ }
+
+ // ------------- QDesignerMetaObject
+ class QDesignerMetaObject : public QDesignerMetaObjectInterface {
+ public:
+ QDesignerMetaObject(const qdesigner_internal::QDesignerIntrospection *introspection, const QMetaObject *metaObject);
+ virtual ~QDesignerMetaObject();
+
+ virtual QString className() const { return m_className; }
+ virtual const QDesignerMetaEnumInterface *enumerator(int index) const { return m_enumerators[index]; }
+ virtual int enumeratorCount() const { return m_enumerators.size(); }
+ virtual int enumeratorOffset() const { return m_metaObject->enumeratorOffset(); }
+
+ virtual int indexOfEnumerator(const QString &name) const { return m_metaObject->indexOfEnumerator(name.toUtf8()); }
+ virtual int indexOfMethod(const QString &method) const { return m_metaObject->indexOfMethod(method.toUtf8()); }
+ virtual int indexOfProperty(const QString &name) const { return m_metaObject->indexOfProperty(name.toUtf8()); }
+ virtual int indexOfSignal(const QString &signal) const { return m_metaObject->indexOfSignal(signal.toUtf8()); }
+ virtual int indexOfSlot(const QString &slot) const { return m_metaObject->indexOfSlot(slot.toUtf8()); }
+
+ virtual const QDesignerMetaMethodInterface *method(int index) const { return m_methods[index]; }
+ virtual int methodCount() const { return m_methods.size(); }
+ virtual int methodOffset() const { return m_metaObject->methodOffset(); }
+
+ virtual const QDesignerMetaPropertyInterface *property(int index) const { return m_properties[index]; }
+ virtual int propertyCount() const { return m_properties.size(); }
+ virtual int propertyOffset() const { return m_metaObject->propertyOffset(); }
+
+ const QDesignerMetaObjectInterface *superClass() const;
+ virtual const QDesignerMetaPropertyInterface *userProperty() const { return m_userProperty; }
+
+ private:
+ const QString m_className;
+ const qdesigner_internal::QDesignerIntrospection *m_introspection;
+ const QMetaObject *m_metaObject;
+
+ typedef QVector<QDesignerMetaEnumInterface *> Enumerators;
+ Enumerators m_enumerators;
+
+ typedef QVector<QDesignerMetaMethodInterface *> Methods;
+ Methods m_methods;
+
+ typedef QVector<QDesignerMetaPropertyInterface *> Properties;
+ Properties m_properties;
+
+ QDesignerMetaPropertyInterface *m_userProperty;
+ };
+
+ QDesignerMetaObject::QDesignerMetaObject(const qdesigner_internal::QDesignerIntrospection *introspection, const QMetaObject *metaObject) :
+ m_className(charToQString(metaObject->className())),
+ m_introspection(introspection),
+ m_metaObject(metaObject),
+ m_userProperty(0)
+ {
+ const int numEnumerators = metaObject->enumeratorCount();
+ m_enumerators.reserve(numEnumerators);
+ for (int i = 0; i < numEnumerators; i++)
+ m_enumerators.push_back(new QDesignerMetaEnum(metaObject->enumerator(i)));
+ const int numMethods = metaObject->methodCount();
+ m_methods.reserve(numMethods);
+ for (int i = 0; i < numMethods; i++)
+ m_methods.push_back(new QDesignerMetaMethod(metaObject->method(i)));
+
+ const int numProperties = metaObject->propertyCount();
+ m_properties.reserve(numProperties);
+ for (int i = 0; i < numProperties; i++)
+ m_properties.push_back(new QDesignerMetaProperty(metaObject->property(i)));
+
+ const QMetaProperty userProperty = metaObject->userProperty();
+ if (userProperty.isValid())
+ m_userProperty = new QDesignerMetaProperty(userProperty);
+ }
+
+ QDesignerMetaObject::~QDesignerMetaObject()
+ {
+ qDeleteAll(m_enumerators);
+ qDeleteAll(m_methods);
+ qDeleteAll(m_properties);
+ delete m_userProperty;
+ }
+
+ const QDesignerMetaObjectInterface *QDesignerMetaObject::superClass() const
+ {
+ const QMetaObject *qSuperClass = m_metaObject->superClass();
+ if (!qSuperClass)
+ return 0;
+ return m_introspection->metaObjectForQMetaObject(qSuperClass);
+ }
+
+}
+
+namespace qdesigner_internal {
+
+ QDesignerIntrospection::QDesignerIntrospection()
+ {
+ }
+
+ QDesignerIntrospection::~QDesignerIntrospection()
+ {
+ qDeleteAll(m_metaObjectMap.values());
+ }
+
+ const QDesignerMetaObjectInterface* QDesignerIntrospection::metaObject(const QObject *object) const
+ {
+ return metaObjectForQMetaObject(object->metaObject());
+ }
+
+ const QDesignerMetaObjectInterface* QDesignerIntrospection::metaObjectForQMetaObject(const QMetaObject *metaObject) const
+ {
+ MetaObjectMap::iterator it = m_metaObjectMap.find(metaObject);
+ if (it == m_metaObjectMap.end())
+ it = m_metaObjectMap.insert(metaObject, new QDesignerMetaObject(this, metaObject));
+ return it.value();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_introspection_p.h b/tools/designer/src/lib/shared/qdesigner_introspection_p.h
new file mode 100644
index 0000000..89f4c53
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_introspection_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** 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 DESIGNERINTROSPECTION
+#define DESIGNERINTROSPECTION
+
+#include "shared_global_p.h"
+#include <abstractintrospection_p.h>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+struct QMetaObject;
+class QWidget;
+
+namespace qdesigner_internal {
+ // Qt C++ introspection with helpers to find core and meta object for an object
+ class QDESIGNER_SHARED_EXPORT QDesignerIntrospection : public QDesignerIntrospectionInterface {
+ public:
+ QDesignerIntrospection();
+ virtual ~QDesignerIntrospection();
+
+ virtual const QDesignerMetaObjectInterface* metaObject(const QObject *object) const;
+
+ const QDesignerMetaObjectInterface* metaObjectForQMetaObject(const QMetaObject *metaObject) const;
+ private:
+ typedef QMap<const QMetaObject*, QDesignerMetaObjectInterface*> MetaObjectMap;
+ mutable MetaObjectMap m_metaObjectMap;
+
+ };
+}
+
+QT_END_NAMESPACE
+
+#endif // DESIGNERINTROSPECTION
diff --git a/tools/designer/src/lib/shared/qdesigner_membersheet.cpp b/tools/designer/src/lib/shared/qdesigner_membersheet.cpp
new file mode 100644
index 0000000..e51d2fe
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_membersheet.cpp
@@ -0,0 +1,371 @@
+/****************************************************************************
+**
+** 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_membersheet_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <abstractintrospection_p.h>
+
+#include <QtGui/QWidget>
+
+namespace {
+
+class Qt3Members
+ {
+ public:
+ static Qt3Members *instance();
+ QMap<QString, QStringList> getSignals() const { return m_classNameToSignals; }
+ QMap<QString, QStringList> getSlots() const { return m_classNameToSlots; }
+ private:
+ Qt3Members();
+ static Qt3Members *m_instance;
+ QMap<QString, QStringList> m_classNameToSignals;
+ QMap<QString, QStringList> m_classNameToSlots;
+ };
+
+Qt3Members *Qt3Members::m_instance = 0;
+
+Qt3Members::Qt3Members()
+{
+ m_classNameToSignals[QLatin1String("QTextEdit")].append(QLatin1String("currentFontChanged(QFont)"));
+ m_classNameToSignals[QLatin1String("QTextEdit")].append(QLatin1String("currentColorChanged(QColor)"));
+ m_classNameToSignals[QLatin1String("QTabWidget")].append(QLatin1String("currentChanged(QWidget*)"));
+ m_classNameToSignals[QLatin1String("QTabWidget")].append(QLatin1String("selected(QString)"));
+ m_classNameToSignals[QLatin1String("QTabBar")].append(QLatin1String("selected(int)"));
+ m_classNameToSignals[QLatin1String("QMenuBar")].append(QLatin1String("activated(int)"));
+ m_classNameToSignals[QLatin1String("QMenuBar")].append(QLatin1String("highlighted(int)"));
+ m_classNameToSignals[QLatin1String("QMenu")].append(QLatin1String("activated(int)"));
+ m_classNameToSignals[QLatin1String("QMenu")].append(QLatin1String("highlighted(int)"));
+ m_classNameToSignals[QLatin1String("QLineEdit")].append(QLatin1String("lostFocus()"));
+ m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialPressed()"));
+ m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialMoved(int)"));
+ m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialReleased()"));
+ m_classNameToSignals[QLatin1String("QComboBox")].append(QLatin1String("textChanged(QString)"));
+ m_classNameToSignals[QLatin1String("QActionGroup")].append(QLatin1String("selected(QAction*)"));
+ m_classNameToSignals[QLatin1String("QAction")].append(QLatin1String("activated(int)"));
+ m_classNameToSignals[QLatin1String("QAbstractSocket")].append(QLatin1String("connectionClosed()"));
+ m_classNameToSignals[QLatin1String("QAbstractSocket")].append(QLatin1String("delayedCloseFinished()"));
+
+ m_classNameToSlots[QLatin1String("QWidget")].append(QLatin1String("setShown(bool)"));
+ m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setTextPosition(QToolButton::TextPosition)"));
+ m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setUsesBigPixmap(bool)"));
+ m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setUsesTextLabel(bool)"));
+ m_classNameToSlots[QLatin1String("QTextEdit")].append(QLatin1String("setModified(bool)"));
+ m_classNameToSlots[QLatin1String("QTextEdit")].append(QLatin1String("setColor(QColor)"));
+ m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("setCurrentPage(int)"));
+ m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("showPage(QWidget*)"));
+ m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("removePage(QWidget*)"));
+ m_classNameToSlots[QLatin1String("QTabBar")].append(QLatin1String("setCurrentTab(int)"));
+ m_classNameToSlots[QLatin1String("QStatusBar")].append(QLatin1String("message(QString,int)"));
+ m_classNameToSlots[QLatin1String("QStatusBar")].append(QLatin1String("clear()"));
+ m_classNameToSlots[QLatin1String("QSplashScreen")].append(QLatin1String("message(QString,int)"));
+ m_classNameToSlots[QLatin1String("QSplashScreen")].append(QLatin1String("clear()"));
+ m_classNameToSlots[QLatin1String("QSlider")].append(QLatin1String("addStep()"));
+ m_classNameToSlots[QLatin1String("QSlider")].append(QLatin1String("subtractStep()"));
+ m_classNameToSlots[QLatin1String("QAbstractButton")].append(QLatin1String("setOn(bool)"));
+ m_classNameToSlots[QLatin1String("QAction")].append(QLatin1String("setOn(bool)"));
+ m_classNameToSlots[QLatin1String("QErrorMessage")].append(QLatin1String("message(QString)"));
+ m_classNameToSlots[QLatin1String("QTimer")].append(QLatin1String("changeInterval(int)"));
+ m_classNameToSlots[QLatin1String("QTimer")].append(QLatin1String("start(int,bool)"));
+}
+
+Qt3Members *Qt3Members::instance()
+{
+ if (!m_instance)
+ m_instance = new Qt3Members();
+ return m_instance;
+}
+}
+
+QT_BEGIN_NAMESPACE
+
+static QList<QByteArray> stringListToByteArray(const QStringList &l)
+{
+ if (l.empty())
+ return QList<QByteArray>();
+ QList<QByteArray> rc;
+ const QStringList::const_iterator cend = l.constEnd();
+ for (QStringList::const_iterator it = l.constBegin(); it != cend; ++it)
+ rc += it->toUtf8();
+ return rc;
+}
+
+// Find the form editor in the hierarchy.
+// We know that the parent of the sheet is the extension manager
+// whose parent is the core.
+
+static QDesignerFormEditorInterface *formEditorForObject(QObject *o) {
+ do {
+ if (QDesignerFormEditorInterface* core = qobject_cast<QDesignerFormEditorInterface*>(o))
+ return core;
+ o = o->parent();
+ } while(o);
+ Q_ASSERT(o);
+ return 0;
+}
+
+// ------------ QDesignerMemberSheetPrivate
+class QDesignerMemberSheetPrivate {
+public:
+ explicit QDesignerMemberSheetPrivate(QObject *object, QObject *sheetParent);
+
+ QDesignerFormEditorInterface *m_core;
+ const QDesignerMetaObjectInterface *m_meta;
+
+ class Info {
+ public:
+ inline Info() : visible(true) {}
+
+ QString group;
+ bool visible;
+ };
+
+ typedef QHash<int, Info> InfoHash;
+
+ Info &ensureInfo(int index);
+
+ InfoHash m_info;
+};
+
+QDesignerMemberSheetPrivate::QDesignerMemberSheetPrivate(QObject *object, QObject *sheetParent) :
+ m_core(formEditorForObject(sheetParent)),
+ m_meta(m_core->introspection()->metaObject(object))
+{
+}
+
+QDesignerMemberSheetPrivate::Info &QDesignerMemberSheetPrivate::ensureInfo(int index)
+{
+ InfoHash::iterator it = m_info.find(index);
+ if (it == m_info.end()) {
+ it = m_info.insert(index, Info());
+ }
+ return it.value();
+}
+
+// --------- QDesignerMemberSheet
+
+QDesignerMemberSheet::QDesignerMemberSheet(QObject *object, QObject *parent) :
+ QObject(parent),
+ d(new QDesignerMemberSheetPrivate(object, parent))
+{
+}
+
+QDesignerMemberSheet::~QDesignerMemberSheet()
+{
+ delete d;
+}
+
+int QDesignerMemberSheet::count() const
+{
+ return d->m_meta->methodCount();
+}
+
+int QDesignerMemberSheet::indexOf(const QString &name) const
+{
+ return d->m_meta->indexOfMethod(name);
+}
+
+QString QDesignerMemberSheet::memberName(int index) const
+{
+ return d->m_meta->method(index)->tag();
+}
+
+QString QDesignerMemberSheet::declaredInClass(int index) const
+{
+ const QString member = d->m_meta->method(index)->signature();
+
+ // Find class whose superclass does not contain the method.
+ const QDesignerMetaObjectInterface *meta_obj = d->m_meta;
+
+ for (;;) {
+ const QDesignerMetaObjectInterface *tmp = meta_obj->superClass();
+ if (tmp == 0)
+ break;
+ if (tmp->indexOfMethod(member) == -1)
+ break;
+ meta_obj = tmp;
+ }
+ return meta_obj->className();
+}
+
+QString QDesignerMemberSheet::memberGroup(int index) const
+{
+ return d->m_info.value(index).group;
+}
+
+void QDesignerMemberSheet::setMemberGroup(int index, const QString &group)
+{
+ d->ensureInfo(index).group = group;
+}
+
+QString QDesignerMemberSheet::signature(int index) const
+{
+ return d->m_meta->method(index)->normalizedSignature();
+}
+
+bool QDesignerMemberSheet::isVisible(int index) const
+{
+ typedef QDesignerMemberSheetPrivate::InfoHash InfoHash;
+ const InfoHash::const_iterator it = d->m_info.constFind(index);
+ if (it != d->m_info.constEnd())
+ return it.value().visible;
+
+ return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Signal
+ || d->m_meta->method(index)->access() == QDesignerMetaMethodInterface::Public;
+}
+
+void QDesignerMemberSheet::setVisible(int index, bool visible)
+{
+ d->ensureInfo(index).visible = visible;
+}
+
+bool QDesignerMemberSheet::isSignal(int index) const
+{
+ return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Signal;
+}
+
+bool QDesignerMemberSheet::isSlot(int index) const
+{
+ return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Slot;
+}
+
+bool QDesignerMemberSheet::inheritedFromWidget(int index) const
+{
+ const QString name = d->m_meta->method(index)->signature();
+ return declaredInClass(index) == QLatin1String("QWidget") || declaredInClass(index) == QLatin1String("QObject");
+}
+
+
+QList<QByteArray> QDesignerMemberSheet::parameterTypes(int index) const
+{
+ return stringListToByteArray(d->m_meta->method(index)->parameterTypes());
+}
+
+QList<QByteArray> QDesignerMemberSheet::parameterNames(int index) const
+{
+ return stringListToByteArray(d->m_meta->method(index)->parameterNames());
+}
+
+bool QDesignerMemberSheet::signalMatchesSlot(const QString &signal, const QString &slot)
+{
+ bool result = true;
+
+ do {
+ int signal_idx = signal.indexOf(QLatin1Char('('));
+ int slot_idx = slot.indexOf(QLatin1Char('('));
+ if (signal_idx == -1 || slot_idx == -1)
+ break;
+
+ ++signal_idx; ++slot_idx;
+
+ if (slot.at(slot_idx) == QLatin1Char(')'))
+ break;
+
+ while (signal_idx < signal.size() && slot_idx < slot.size()) {
+ const QChar signal_c = signal.at(signal_idx);
+ const QChar slot_c = slot.at(slot_idx);
+
+ if (signal_c == QLatin1Char(',') && slot_c == QLatin1Char(')'))
+ break;
+
+ if (signal_c == QLatin1Char(')') && slot_c == QLatin1Char(')'))
+ break;
+
+ if (signal_c != slot_c) {
+ result = false;
+ break;
+ }
+
+ ++signal_idx; ++slot_idx;
+ }
+ } while (false);
+
+ return result;
+}
+
+bool QDesignerMemberSheet::isQt3Signal(int index) const
+{
+ if (!isSignal(index))
+ return false;
+
+ const QString className = declaredInClass(index);
+ const QString signalSignature = signature(index);
+
+ QMap<QString, QStringList> qt3signals = Qt3Members::instance()->getSignals();
+ QMap<QString, QStringList>::const_iterator it = qt3signals.constFind(className);
+ if (it != qt3signals.constEnd() && (*it).contains(signalSignature))
+ return true;
+
+ return false;
+}
+
+bool QDesignerMemberSheet::isQt3Slot(int index) const
+{
+ if (!isSlot(index))
+ return false;
+
+ const QString className = declaredInClass(index);
+ const QString slotSignature = signature(index);
+
+ QMap<QString, QStringList> qt3slots = Qt3Members::instance()->getSlots();
+ QMap<QString, QStringList>::const_iterator it = qt3slots.constFind(className);
+ if (it != qt3slots.constEnd() && (*it).contains(slotSignature))
+ return true;
+ return false;
+}
+
+// ------------ QDesignerMemberSheetFactory
+
+QDesignerMemberSheetFactory::QDesignerMemberSheetFactory(QExtensionManager *parent)
+ : QExtensionFactory(parent)
+{
+}
+
+QObject *QDesignerMemberSheetFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
+{
+ if (iid == Q_TYPEID(QDesignerMemberSheetExtension)) {
+ return new QDesignerMemberSheet(object, parent);
+ }
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_membersheet_p.h b/tools/designer/src/lib/shared/qdesigner_membersheet_p.h
new file mode 100644
index 0000000..695b808
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_membersheet_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_MEMBERSHEET_H
+#define QDESIGNER_MEMBERSHEET_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/membersheet.h>
+#include <QtDesigner/default_extensionfactory.h>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerMemberSheetPrivate;
+
+class QDESIGNER_SHARED_EXPORT QDesignerMemberSheet: public QObject, public QDesignerMemberSheetExtension
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerMemberSheetExtension)
+
+public:
+ explicit QDesignerMemberSheet(QObject *object, QObject *parent = 0);
+ virtual ~QDesignerMemberSheet();
+
+ virtual int indexOf(const QString &name) const;
+
+ virtual int count() const;
+ virtual QString memberName(int index) const;
+
+ virtual QString memberGroup(int index) const;
+ virtual void setMemberGroup(int index, const QString &group);
+
+ virtual bool isVisible(int index) const;
+ virtual void setVisible(int index, bool b);
+
+ virtual bool isSignal(int index) const;
+ virtual bool isSlot(int index) const;
+
+ virtual bool isQt3Signal(int index) const;
+ virtual bool isQt3Slot(int index) const;
+
+ virtual bool inheritedFromWidget(int index) const;
+
+ static bool signalMatchesSlot(const QString &signal, const QString &slot);
+
+ virtual QString declaredInClass(int index) const;
+
+ virtual QString signature(int index) const;
+ virtual QList<QByteArray> parameterTypes(int index) const;
+ virtual QList<QByteArray> parameterNames(int index) const;
+
+private:
+ QDesignerMemberSheetPrivate *d;
+};
+
+class QDESIGNER_SHARED_EXPORT QDesignerMemberSheetFactory: public QExtensionFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(QAbstractExtensionFactory)
+
+public:
+ QDesignerMemberSheetFactory(QExtensionManager *parent = 0);
+
+protected:
+ virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_MEMBERSHEET_H
diff --git a/tools/designer/src/lib/shared/qdesigner_menu.cpp b/tools/designer/src/lib/shared/qdesigner_menu.cpp
new file mode 100644
index 0000000..7aea52d
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_menu.cpp
@@ -0,0 +1,1355 @@
+/****************************************************************************
+**
+** 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_menu_p.h"
+#include "qdesigner_menubar_p.h"
+#include "qdesigner_toolbar_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "actionrepository_p.h"
+#include "actionprovider_p.h"
+#include "actioneditor_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_objectinspector_p.h"
+
+#include <QtCore/QTimer>
+#include <QtCore/qdebug.h>
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QDesignerMetaDataBaseInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QLineEdit>
+#include <QtGui/QPainter>
+#include <QtGui/QRubberBand>
+#include <QtGui/QToolTip>
+#include <QtGui/QToolBar>
+#include <QtGui/qevent.h>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+using namespace qdesigner_internal;
+
+QDesignerMenu::QDesignerMenu(QWidget *parent) :
+ QMenu(parent),
+ m_currentIndex(0),
+ m_addItem(new SpecialMenuAction(this)),
+ m_addSeparator(new SpecialMenuAction(this)),
+ m_showSubMenuTimer(new QTimer(this)),
+ m_deactivateWindowTimer(new QTimer(this)),
+ m_adjustSizeTimer(new QTimer(this)),
+ m_editor(new QLineEdit(this)),
+ m_dragging(false),
+ m_lastSubMenuIndex(-1)
+{
+ setContextMenuPolicy(Qt::DefaultContextMenu);
+ setAcceptDrops(true); // ### fake
+ setSeparatorsCollapsible(false);
+
+ connect(m_adjustSizeTimer, SIGNAL(timeout()), this, SLOT(slotAdjustSizeNow()));
+ m_addItem->setText(tr("Type Here"));
+ addAction(m_addItem);
+
+ m_addSeparator->setText(tr("Add Separator"));
+ addAction(m_addSeparator);
+
+ connect(m_showSubMenuTimer, SIGNAL(timeout()), this, SLOT(slotShowSubMenuNow()));
+
+ connect(m_deactivateWindowTimer, SIGNAL(timeout()), this, SLOT(slotDeactivateNow()));
+
+ m_editor->setObjectName(QLatin1String("__qt__passive_editor"));
+ m_editor->hide();
+
+ m_editor->installEventFilter(this);
+ installEventFilter(this);
+}
+
+QDesignerMenu::~QDesignerMenu()
+{
+}
+
+void QDesignerMenu::slotAdjustSizeNow()
+{
+ // Not using a single-shot, since we want to compress the timers if many items are being
+ // adjusted
+ m_adjustSizeTimer->stop();
+ adjustSize();
+}
+
+bool QDesignerMenu::handleEvent(QWidget *widget, QEvent *event)
+{
+ if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
+ update();
+
+ if (widget == m_editor)
+ return false;
+ }
+
+ switch (event->type()) {
+ default: break;
+
+ case QEvent::MouseButtonPress:
+ return handleMousePressEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseButtonRelease:
+ return handleMouseReleaseEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseButtonDblClick:
+ return handleMouseDoubleClickEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseMove:
+ return handleMouseMoveEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::ContextMenu:
+ return handleContextMenuEvent(widget, static_cast<QContextMenuEvent*>(event));
+ case QEvent::KeyPress:
+ return handleKeyPressEvent(widget, static_cast<QKeyEvent*>(event));
+ }
+
+ return true;
+}
+
+void QDesignerMenu::startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers)
+{
+ const int index = findAction(pos);
+ if (index >= realActionCount())
+ return;
+
+ QAction *action = safeActionAt(index);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction;
+ if (dropAction == Qt::MoveAction) {
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ cmd->init(this, action, actions().at(index + 1));
+ fw->commandHistory()->push(cmd);
+ }
+
+ QDrag *drag = new QDrag(this);
+ drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
+ drag->setMimeData(new ActionRepositoryMimeData(action, dropAction));
+
+ const int old_index = m_currentIndex;
+ m_currentIndex = -1;
+
+ if (drag->start(dropAction) == Qt::IgnoreAction) {
+ if (dropAction == Qt::MoveAction) {
+ QAction *previous = safeActionAt(index);
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, action, previous);
+ fw->commandHistory()->push(cmd);
+ }
+
+ m_currentIndex = old_index;
+ }
+}
+
+bool QDesignerMenu::handleKeyPressEvent(QWidget * /*widget*/, QKeyEvent *e)
+{
+ m_showSubMenuTimer->stop();
+
+ if (m_editor->isHidden() && hasFocus()) { // In navigation mode
+ switch (e->key()) {
+
+ case Qt::Key_Delete:
+ if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
+ break;
+ hideSubMenu();
+ deleteAction();
+ break;
+
+ case Qt::Key_Left:
+ e->accept();
+ moveLeft();
+ return true;
+
+ case Qt::Key_Right:
+ e->accept();
+ moveRight();
+ return true; // no update
+
+ case Qt::Key_Up:
+ e->accept();
+ moveUp(e->modifiers() & Qt::ControlModifier);
+ return true;
+
+ case Qt::Key_Down:
+ e->accept();
+ moveDown(e->modifiers() & Qt::ControlModifier);
+ return true;
+
+ case Qt::Key_PageUp:
+ m_currentIndex = 0;
+ break;
+
+ case Qt::Key_PageDown:
+ m_currentIndex = actions().count() - 1;
+ break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_F2:
+ e->accept();
+ enterEditMode();
+ return true; // no update
+
+ case Qt::Key_Escape:
+ e->ignore();
+ setFocus();
+ hide();
+ closeMenuChain();
+ return true;
+
+ case Qt::Key_Alt:
+ case Qt::Key_Shift:
+ case Qt::Key_Control:
+ e->ignore();
+ setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed
+ return true; // no update
+
+ default: {
+ QAction *action = currentAction();
+ if (!action || action->isSeparator() || action == m_addSeparator) {
+ e->ignore();
+ return true;
+ } else if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
+ showLineEdit();
+ QApplication::sendEvent(m_editor, e);
+ e->accept();
+ } else {
+ e->ignore();
+ }
+ }
+ return true;
+ }
+ } else if (m_editor->hasFocus()) { // In edit mode
+ switch (e->key()) {
+ default:
+ e->ignore();
+ return false;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (!m_editor->text().isEmpty()) {
+ leaveEditMode(ForceAccept);
+ m_editor->hide();
+ setFocus();
+ moveDown(false);
+ break;
+ }
+ // fall through
+
+ case Qt::Key_Escape:
+ m_editor->hide();
+ setFocus();
+ break;
+ }
+ }
+
+ e->accept();
+ update();
+
+ return true;
+}
+
+static void sendMouseEventTo(QWidget *target, const QPoint &targetPoint, const QMouseEvent *event)
+{
+ QMouseEvent e(event->type(), targetPoint, event->globalPos(), event->button(), event->buttons(), event->modifiers());
+ QApplication::sendEvent(target, &e);
+}
+
+bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
+{
+ event->accept();
+ m_startPosition = QPoint();
+
+ if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+ return true;
+
+ if (!rect().contains(event->pos())) {
+ // special case for menubar
+ QWidget *target = QApplication::widgetAt(event->globalPos());
+ QMenuBar *mb = qobject_cast<QMenuBar*>(target);
+ QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(target);
+ if (mb != 0 || menu != 0) {
+ const QPoint pt = target->mapFromGlobal(event->globalPos());
+ QAction *action = mb == 0 ? menu->actionAt(pt) : mb->actionAt(pt);
+ if (action)
+ sendMouseEventTo(target, pt, event);
+ }
+ return true;
+ }
+
+ m_currentIndex = findAction(event->pos());
+ QAction *action = safeActionAt(m_currentIndex);
+
+ QRect pm_rect;
+ if (action->menu() || hasSubMenuPixmap(action)) {
+ pm_rect = subMenuPixmapRect(action);
+ pm_rect.setLeft(pm_rect.left() - 20); // give the user a little more
+ // space to click
+ }
+
+ if (!pm_rect.contains(event->pos()) && m_currentIndex != -1)
+ enterEditMode();
+
+ return true;
+}
+
+bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *event)
+{
+ if (!rect().contains(event->pos())) {
+ QWidget *clickedWidget = QApplication::widgetAt(event->globalPos());
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(clickedWidget)) {
+ const QPoint pt = mb->mapFromGlobal(event->globalPos());
+ if (QAction *action = mb->actionAt(pt)) {
+ QMenu * menu = action->menu();
+ if (menu == findRootMenu()) {
+ // propagate the mouse press event (but don't close the popup)
+ sendMouseEventTo(mb, pt, event);
+ return true;
+ }
+ }
+ }
+
+ if (QDesignerMenu *m = qobject_cast<QDesignerMenu *>(clickedWidget)) {
+ m->hideSubMenu();
+ sendMouseEventTo(m, m->mapFromGlobal(event->globalPos()), event);
+ } else {
+ QDesignerMenu *root = findRootMenu();
+ root->hide();
+ root->hideSubMenu();
+ }
+ if (clickedWidget) {
+ if (QWidget *focusProxy = clickedWidget->focusProxy())
+ clickedWidget = focusProxy;
+ if (clickedWidget->focusPolicy() != Qt::NoFocus)
+ clickedWidget->setFocus(Qt::OtherFocusReason);
+ }
+ return true;
+ }
+
+ m_showSubMenuTimer->stop();
+ m_startPosition = QPoint();
+ event->accept();
+
+ if (event->button() != Qt::LeftButton)
+ return true;
+
+ m_startPosition = mapFromGlobal(event->globalPos());
+
+ const int index = findAction(m_startPosition);
+
+ QAction *action = safeActionAt(index);
+ QRect pm_rect = subMenuPixmapRect(action);
+ pm_rect.setLeft(pm_rect.left() - 20); // give the user a little more space to click
+
+ const int old_index = m_currentIndex;
+ m_currentIndex = index;
+ if ((hasSubMenuPixmap(action) || action->menu() != 0)
+ && pm_rect.contains(m_startPosition)) {
+ if (m_currentIndex == m_lastSubMenuIndex) {
+ hideSubMenu();
+ } else
+ slotShowSubMenuNow();
+ } else {
+ if (index == old_index) {
+ if (m_currentIndex == m_lastSubMenuIndex)
+ hideSubMenu();
+ } else {
+ hideSubMenu();
+ }
+ }
+
+ update();
+ if (index != old_index)
+ selectCurrentAction();
+
+ return true;
+}
+
+bool QDesignerMenu::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
+{
+ event->accept();
+ m_startPosition = QPoint();
+
+ return true;
+}
+
+bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
+{
+ if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+ return true;
+
+ if (!rect().contains(event->pos())) {
+
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::widgetAt(event->globalPos()))) {
+ const QPoint pt = mb->mapFromGlobal(event->globalPos());
+ QAction *action = mb->actionAt(pt);
+ if (action && action->menu() == findRootMenu()) {
+ // propagate the mouse press event (but don't close the popup)
+ sendMouseEventTo(mb, pt, event);
+ return true;
+ }
+ // hide the popup Qt will replay the event
+ slotDeactivateNow();
+ }
+ return true;
+ }
+
+ if (m_startPosition.isNull())
+ return true;
+
+ event->accept();
+
+ const QPoint pos = mapFromGlobal(event->globalPos());
+
+ if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
+ return true;
+
+ startDrag(m_startPosition, event->modifiers());
+ m_startPosition = QPoint();
+
+ return true;
+}
+
+bool QDesignerMenu::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
+{
+ event->accept();
+
+ const int index = findAction(mapFromGlobal(event->globalPos()));
+ QAction *action = safeActionAt(index);
+ if (qobject_cast<SpecialMenuAction*>(action))
+ return true;
+
+ QMenu menu;
+ QVariant itemData;
+ qVariantSetValue(itemData, action);
+
+ QAction *addSeparatorAction = menu.addAction(tr("Insert separator"));
+ addSeparatorAction->setData(itemData);
+
+ QAction *removeAction = 0;
+ if (action->isSeparator())
+ removeAction = menu.addAction(tr("Remove separator"));
+ else
+ removeAction = menu.addAction(tr("Remove action '%1'").arg(action->objectName()));
+ removeAction->setData(itemData);
+
+ connect(addSeparatorAction, SIGNAL(triggered(bool)), this, SLOT(slotAddSeparator()));
+ connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(slotRemoveSelectedAction()));
+ menu.exec(event->globalPos());
+
+ return true;
+}
+
+void QDesignerMenu::slotAddSeparator()
+{
+ QAction *action = qobject_cast<QAction *>(sender());
+ if (!action)
+ return;
+
+ QAction *a = qvariant_cast<QAction*>(action->data());
+ Q_ASSERT(a != 0);
+
+ const int pos = actions().indexOf(a);
+ QAction *action_before = 0;
+ if (pos != -1)
+ action_before = safeActionAt(pos);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ fw->beginCommand(tr("Add separator"));
+ QAction *sep = createAction(QString(), true);
+
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, sep, action_before);
+ fw->commandHistory()->push(cmd);
+
+ if (parentMenu()) {
+ QAction *parent_action = parentMenu()->currentAction();
+ if (parent_action->menu() == 0) {
+ CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
+ cmd->init(parentMenu(), parentMenu()->currentAction());
+ fw->commandHistory()->push(cmd);
+ }
+ }
+
+ fw->endCommand();
+}
+
+void QDesignerMenu::slotRemoveSelectedAction()
+{
+ if (QAction *action = qobject_cast<QAction *>(sender()))
+ if (QAction *a = qvariant_cast<QAction*>(action->data()))
+ deleteAction(a);
+}
+
+void QDesignerMenu::deleteAction(QAction *a)
+{
+ const int pos = actions().indexOf(a);
+ QAction *action_before = 0;
+ if (pos != -1)
+ action_before = safeActionAt(pos + 1);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ cmd->init(this, a, action_before);
+ fw->commandHistory()->push(cmd);
+}
+
+QRect QDesignerMenu::subMenuPixmapRect(QAction *action) const
+{
+ static const QPixmap pm(QLatin1String(":/trolltech/formeditor/images/submenu.png"));
+ const QRect g = actionGeometry(action);
+ const int x = g.right() - pm.width() - 2;
+ const int y = g.top() + (g.height() - pm.height())/2 + 1;
+ return QRect(x, y, pm.width(), pm.height());
+}
+
+bool QDesignerMenu::hasSubMenuPixmap(QAction *action) const
+{
+ return action != 0
+ && qobject_cast<SpecialMenuAction*>(action) == 0
+ && !action->isSeparator()
+ && !action->menu()
+ && canCreateSubMenu(action);
+}
+
+void QDesignerMenu::showEvent ( QShowEvent * event )
+{
+ selectCurrentAction();
+ QMenu::showEvent (event);
+}
+
+void QDesignerMenu::paintEvent(QPaintEvent *event)
+{
+ QMenu::paintEvent(event);
+
+ QPainter p(this);
+
+ QAction *current = currentAction();
+
+ foreach (QAction *a, actions()) {
+ const QRect g = actionGeometry(a);
+
+ if (qobject_cast<SpecialMenuAction*>(a)) {
+ QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
+ lg.setColorAt(0.0, Qt::transparent);
+ lg.setColorAt(0.7, QColor(0, 0, 0, 32));
+ lg.setColorAt(1.0, Qt::transparent);
+
+ p.fillRect(g, lg);
+ } else if (hasSubMenuPixmap(a)) {
+ static const QPixmap pm(QLatin1String(":/trolltech/formeditor/images/submenu.png"));
+ p.drawPixmap(subMenuPixmapRect(a).topLeft(), pm);
+ }
+ }
+
+ if (!hasFocus() || !current || m_dragging)
+ return;
+
+ if (QDesignerMenu *menu = parentMenu()) {
+ if (menu->dragging())
+ return;
+ }
+
+ if (QDesignerMenuBar *menubar = qobject_cast<QDesignerMenuBar*>(parentWidget())) {
+ if (menubar->dragging())
+ return;
+ }
+
+ const QRect g = actionGeometry(current);
+ drawSelection(&p, g.adjusted(1, 1, -3, -3));
+}
+
+bool QDesignerMenu::dragging() const
+{
+ return m_dragging;
+}
+
+QDesignerMenu *QDesignerMenu::findRootMenu() const
+{
+ if (parentMenu())
+ return parentMenu()->findRootMenu();
+
+ return const_cast<QDesignerMenu*>(this);
+}
+
+QDesignerMenu *QDesignerMenu::findActivatedMenu() const
+{
+ QList<QDesignerMenu*> candidates;
+ candidates.append(const_cast<QDesignerMenu*>(this));
+ candidates += qFindChildren<QDesignerMenu*>(this);
+
+ foreach (QDesignerMenu *m, candidates) {
+ if (m == qApp->activeWindow())
+ return m;
+ }
+
+ return 0;
+}
+
+bool QDesignerMenu::eventFilter(QObject *object, QEvent *event)
+{
+ if (object != this && object != m_editor) {
+ return false;
+ }
+
+ if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) {
+ leaveEditMode(Default);
+ m_editor->hide();
+ update();
+ return false;
+ }
+
+ bool dispatch = true;
+
+ switch (event->type()) {
+ default: break;
+
+ case QEvent::WindowDeactivate:
+ deactivateMenu();
+ break;
+ case QEvent::ContextMenu:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+
+ while (QApplication::activePopupWidget() && !qobject_cast<QDesignerMenu*>(QApplication::activePopupWidget())) {
+ QApplication::activePopupWidget()->close();
+ }
+
+ // fall through
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::MouseMove:
+ dispatch = (object != m_editor);
+ // no break
+
+ case QEvent::Enter:
+ case QEvent::Leave:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ if (dispatch)
+ if (QWidget *widget = qobject_cast<QWidget*>(object))
+ if (widget == this || isAncestorOf(widget))
+ return handleEvent(widget, event);
+ break;
+ }
+
+ return false;
+};
+
+int QDesignerMenu::findAction(const QPoint &pos) const
+{
+ const int index = actionIndexAt(this, pos, Qt::Vertical);
+ if (index == -1)
+ return realActionCount();
+
+ return index;
+}
+
+void QDesignerMenu::adjustIndicator(const QPoint &pos)
+{
+ if (QDesignerActionProviderExtension *a = actionProvider()) {
+ a->adjustIndicator(pos);
+ }
+}
+
+QDesignerMenu::ActionDragCheck QDesignerMenu::checkAction(QAction *action) const
+{
+ if (!action || (action->menu() && action->menu()->parentWidget() != const_cast<QDesignerMenu*>(this)))
+ return NoActionDrag; // menu action!! nothing to do
+
+ if (!Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
+ return NoActionDrag; // the action belongs to another form window
+
+ if (actions().contains(action))
+ return ActionDragOnSubMenu; // we already have the action in the menu
+
+ return AcceptActionDrag;
+}
+
+void QDesignerMenu::dragEnterEvent(QDragEnterEvent *event)
+{
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d || d->actionList().empty()) {
+ event->ignore();
+ return;
+ }
+
+ QAction *action = d->actionList().first();
+
+ switch (checkAction(action)) {
+ case NoActionDrag:
+ event->ignore();
+ break;
+ case ActionDragOnSubMenu:
+ d->accept(event);
+ m_dragging = true;
+ break;
+ case AcceptActionDrag:
+ d->accept(event);
+ m_dragging = true;
+ adjustIndicator(event->pos());
+ break;
+ }
+}
+
+void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event)
+{
+ if (actionGeometry(m_addSeparator).contains(event->pos())) {
+ event->ignore();
+ adjustIndicator(QPoint(-1, -1));
+ return;
+ }
+
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d || d->actionList().empty()) {
+ event->ignore();
+ return;
+ }
+
+ QAction *action = d->actionList().first();
+ const ActionDragCheck dc = checkAction(action);
+ switch (dc) {
+ case NoActionDrag:
+ event->ignore();
+ break;
+ case ActionDragOnSubMenu:
+ case AcceptActionDrag: { // Do not pop up submenu of action being dragged
+ const int newIndex = findAction(event->pos());
+ if (safeActionAt(newIndex) != action) {
+ m_currentIndex = newIndex;
+ if (m_lastSubMenuIndex != m_currentIndex)
+ m_showSubMenuTimer->start(300);
+ }
+ if (dc == AcceptActionDrag) {
+ adjustIndicator(event->pos());
+ d->accept(event);
+ } else {
+ event->ignore();
+ }
+ }
+ break;
+ }
+}
+
+void QDesignerMenu::dragLeaveEvent(QDragLeaveEvent *)
+{
+ m_dragging = false;
+ adjustIndicator(QPoint(-1, -1));
+ m_showSubMenuTimer->stop();
+}
+
+void QDesignerMenu::dropEvent(QDropEvent *event)
+{
+ m_showSubMenuTimer->stop();
+ hideSubMenu();
+ m_dragging = false;
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d || d->actionList().empty()) {
+ event->ignore();
+ return;
+ }
+ QAction *action = d->actionList().first();
+ if (action && checkAction(action) == AcceptActionDrag) {
+ event->acceptProposedAction();
+ int index = findAction(event->pos());
+ index = qMin(index, actions().count() - 1);
+
+ fw->beginCommand(tr("Insert action"));
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, action, safeActionAt(index));
+ fw->commandHistory()->push(cmd);
+
+ m_currentIndex = index;
+
+ if (parentMenu()) {
+ QAction *parent_action = parentMenu()->currentAction();
+ if (parent_action->menu() == 0) {
+ CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
+ cmd->init(parentMenu(), parentMenu()->currentAction(), action);
+ fw->commandHistory()->push(cmd);
+ }
+ }
+ update();
+ fw->endCommand();
+ } else {
+ event->ignore();
+ }
+ adjustIndicator(QPoint(-1, -1));
+}
+
+void QDesignerMenu::actionEvent(QActionEvent *event)
+{
+ QMenu::actionEvent(event);
+ m_adjustSizeTimer->start(0);
+}
+
+QDesignerFormWindowInterface *QDesignerMenu::formWindow() const
+{
+ if (parentMenu())
+ return parentMenu()->formWindow();
+
+ return QDesignerFormWindowInterface::findFormWindow(parentWidget());
+}
+
+QDesignerActionProviderExtension *QDesignerMenu::actionProvider()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QDesignerFormEditorInterface *core = fw->core();
+ return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), this);
+ }
+
+ return 0;
+}
+
+void QDesignerMenu::closeMenuChain()
+{
+ m_showSubMenuTimer->stop();
+
+ QWidget *w = this;
+ while (w && qobject_cast<QMenu*>(w))
+ w = w->parentWidget();
+
+ if (w) {
+ foreach (QMenu *subMenu, qFindChildren<QMenu*>(w)) {
+ subMenu->hide();
+ }
+ }
+
+ m_lastSubMenuIndex = -1;
+}
+
+void QDesignerMenu::moveLeft()
+{
+ if (parentMenu()) {
+ hide();
+ } else {
+ closeMenuChain();
+ if (QDesignerMenuBar *mb = parentMenuBar()) {
+ if (QApplication::layoutDirection() == Qt::LeftToRight)
+ mb->moveLeft();
+ else
+ mb->moveRight();
+ }
+ }
+ update();
+}
+
+void QDesignerMenu::moveRight()
+{
+ QAction *action = currentAction();
+
+ if (qobject_cast<SpecialMenuAction*>(action) || action->isSeparator()) {
+ closeMenuChain();
+ if (QDesignerMenuBar *mb = parentMenuBar()) {
+ if (QApplication::layoutDirection() == Qt::LeftToRight)
+ mb->moveRight();
+ else
+ mb->moveLeft();
+ }
+ } else {
+ m_lastSubMenuIndex = -1; // force a refresh
+ slotShowSubMenuNow();
+ }
+}
+
+void QDesignerMenu::moveUp(bool ctrl)
+{
+ if (m_currentIndex == 0) {
+ hide();
+ return;
+ }
+
+ if (ctrl)
+ (void) swap(m_currentIndex, m_currentIndex - 1);
+
+ m_currentIndex = qMax(0, --m_currentIndex);
+ // Always re-select, swapping destroys order
+ update();
+ selectCurrentAction();
+}
+
+void QDesignerMenu::moveDown(bool ctrl)
+{
+ if (m_currentIndex == actions().count() - 1) {
+ return;
+ }
+
+ if (ctrl)
+ (void) swap(m_currentIndex + 1, m_currentIndex);
+
+ m_currentIndex = qMin(actions().count() - 1, ++m_currentIndex);
+ update();
+ if (!ctrl)
+ selectCurrentAction();
+}
+
+QAction *QDesignerMenu::currentAction() const
+{
+ if (m_currentIndex < 0 || m_currentIndex >= actions().count())
+ return 0;
+
+ return safeActionAt(m_currentIndex);
+}
+
+int QDesignerMenu::realActionCount() const
+{
+ return actions().count() - 2; // 2 fake actions
+}
+
+void QDesignerMenu::selectCurrentAction()
+{
+ QAction *action = currentAction();
+ if (!action || action == m_addSeparator || action == m_addItem)
+ return;
+
+ QDesignerObjectInspector *oi = 0;
+ if (QDesignerFormWindowInterface *fw = formWindow())
+ oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
+
+ if (!oi)
+ return;
+
+ oi->clearSelection();
+ if (QMenu *menu = action->menu())
+ oi->selectObject(menu);
+ else
+ oi->selectObject(action);
+}
+
+void QDesignerMenu::createRealMenuAction(QAction *action)
+{
+ if (action->menu())
+ return; // nothing to do
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ QDesignerFormEditorInterface *core = formWindow()->core();
+
+ QDesignerMenu *menu = findOrCreateSubMenu(action);
+ m_subMenus.remove(action);
+
+ action->setMenu(menu);
+ menu->setTitle(action->text());
+
+ Q_ASSERT(fw);
+
+ core->widgetFactory()->initialize(menu);
+
+ const QString niceObjectName = ActionEditor::actionTextToName(menu->title(), QLatin1String("menu"));
+ menu->setObjectName(niceObjectName);
+
+ core->metaDataBase()->add(menu);
+ fw->ensureUniqueObjectName(menu);
+
+ QAction *menuAction = menu->menuAction();
+ core->metaDataBase()->add(menuAction);
+}
+
+void QDesignerMenu::removeRealMenu(QAction *action)
+{
+ QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu());
+ if (menu == 0)
+ return;
+ action->setMenu(0);
+ m_subMenus.insert(action, menu);
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ core->metaDataBase()->remove(menu);
+}
+
+QDesignerMenu *QDesignerMenu::findOrCreateSubMenu(QAction *action)
+{
+ if (action->menu())
+ return qobject_cast<QDesignerMenu*>(action->menu());
+
+ QDesignerMenu *menu = m_subMenus.value(action);
+ if (!menu) {
+ menu = new QDesignerMenu(this);
+ m_subMenus.insert(action, menu);
+ }
+
+ return menu;
+}
+
+bool QDesignerMenu::canCreateSubMenu(QAction *action) const // ### improve it's a bit too slow
+{
+ foreach (const QWidget *aw, action->associatedWidgets())
+ if (aw != this) {
+ if (const QMenu *m = qobject_cast<const QMenu *>(aw)) {
+ if (m->actions().contains(action))
+ return false; // sorry
+ } else {
+ if (const QToolBar *tb = qobject_cast<const QToolBar *>(aw))
+ if (tb->actions().contains(action))
+ return false; // sorry
+ }
+ }
+ return true;
+}
+
+void QDesignerMenu::slotShowSubMenuNow()
+{
+ m_showSubMenuTimer->stop();
+
+ if (m_lastSubMenuIndex == m_currentIndex)
+ return;
+
+ if (m_lastSubMenuIndex != -1)
+ hideSubMenu();
+
+ if (m_currentIndex >= realActionCount())
+ return;
+
+ QAction *action = currentAction();
+
+ if (action->isSeparator() || !canCreateSubMenu(action))
+ return;
+
+ if (QMenu *menu = findOrCreateSubMenu(action)) {
+ if (!menu->isVisible()) {
+ if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
+ menu->setWindowFlags(Qt::Popup);
+ const QRect g = actionGeometry(action);
+ menu->move(mapToGlobal(g.topRight()));
+ menu->show();
+ menu->setFocus();
+ } else {
+ menu->raise();
+ }
+ menu->setFocus();
+
+ m_lastSubMenuIndex = m_currentIndex;
+ }
+}
+
+void QDesignerMenu::showSubMenu(QAction *action)
+{
+ m_showSubMenuTimer->stop();
+
+ if (m_editor->isVisible() || !action || qobject_cast<SpecialMenuAction*>(action)
+ || action->isSeparator() || !isVisible())
+ return;
+
+ m_showSubMenuTimer->start(300);
+}
+
+QDesignerMenu *QDesignerMenu::parentMenu() const
+{
+ return qobject_cast<QDesignerMenu*>(parentWidget());
+}
+
+QDesignerMenuBar *QDesignerMenu::parentMenuBar() const
+{
+ if (QDesignerMenuBar *mb = qobject_cast<QDesignerMenuBar*>(parentWidget())) {
+ return mb;
+ } else if (QDesignerMenu *m = parentMenu()) {
+ return m->parentMenuBar();
+ }
+
+ return 0;
+}
+
+void QDesignerMenu::setVisible(bool visible)
+{
+ if (visible)
+ m_currentIndex = 0;
+ else
+ m_lastSubMenuIndex = -1;
+
+ QMenu::setVisible(visible);
+
+}
+
+void QDesignerMenu::adjustSpecialActions()
+{
+ removeAction(m_addItem);
+ removeAction(m_addSeparator);
+ addAction(m_addItem);
+ addAction(m_addSeparator);
+}
+
+bool QDesignerMenu::interactive(bool i)
+{
+ const bool old = m_interactive;
+ m_interactive = i;
+ return old;
+}
+
+void QDesignerMenu::enterEditMode()
+{
+ if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
+ showLineEdit();
+ } else {
+ hideSubMenu();
+ QDesignerFormWindowInterface *fw = formWindow();
+ fw->beginCommand(tr("Add separator"));
+ QAction *sep = createAction(QString(), true);
+
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, sep, safeActionAt(realActionCount()));
+ fw->commandHistory()->push(cmd);
+
+ if (parentMenu()) {
+ QAction *parent_action = parentMenu()->currentAction();
+ if (parent_action->menu() == 0) {
+ CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
+ cmd->init(parentMenu(), parentMenu()->currentAction());
+ fw->commandHistory()->push(cmd);
+ }
+ }
+
+ fw->endCommand();
+
+ m_currentIndex = actions().indexOf(m_addItem);
+ update();
+ }
+}
+
+void QDesignerMenu::leaveEditMode(LeaveEditMode mode)
+{
+ if (mode == Default)
+ return;
+
+ QAction *action = 0;
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (m_currentIndex < realActionCount()) {
+ action = safeActionAt(m_currentIndex);
+ fw->beginCommand(QApplication::translate("Command", "Set action text"));
+ } else {
+ Q_ASSERT(fw != 0);
+ fw->beginCommand(QApplication::translate("Command", "Insert action"));
+ action = createAction(ActionEditor::actionTextToName(m_editor->text()));
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, action, currentAction());
+ fw->commandHistory()->push(cmd);
+ }
+
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(action, QLatin1String("text"), m_editor->text());
+ fw->commandHistory()->push(cmd);
+
+ if (parentMenu()) {
+ QAction *parent_action = parentMenu()->currentAction();
+ if (parent_action->menu() == 0) {
+ CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
+ cmd->init(parentMenu(), parentMenu()->currentAction(), action);
+ fw->commandHistory()->push(cmd);
+ }
+ }
+
+ update();
+ fw->endCommand();
+}
+
+QAction *QDesignerMenu::safeMenuAction(QDesignerMenu *menu) const
+{
+ QAction *action = menu->menuAction();
+
+ if (!action)
+ action = m_subMenus.key(menu);
+
+ return action;
+}
+
+void QDesignerMenu::showLineEdit()
+{
+ m_showSubMenuTimer->stop();
+
+ QAction *action = 0;
+
+ if (m_currentIndex < realActionCount())
+ action = safeActionAt(m_currentIndex);
+ else
+ action = m_addItem;
+
+ if (action->isSeparator())
+ return;
+
+ hideSubMenu();
+
+ // open edit field for item name
+ setFocus();
+
+ const QString text = action != m_addItem ? action->text() : QString();
+ m_editor->setText(text);
+ m_editor->selectAll();
+ m_editor->setGeometry(actionGeometry(action).adjusted(1, 1, -2, -2));
+ m_editor->show();
+ m_editor->setFocus();
+}
+
+QAction *QDesignerMenu::createAction(const QString &objectName, bool separator)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ Q_ASSERT(fw);
+ return ToolBarEventFilter::createAction(fw, objectName, separator);
+}
+
+// ### share with QDesignerMenu::swap
+bool QDesignerMenu::swap(int a, int b)
+{
+ const int left = qMin(a, b);
+ int right = qMax(a, b);
+
+ QAction *action_a = safeActionAt(left);
+ QAction *action_b = safeActionAt(right);
+
+ if (action_a == action_b
+ || !action_a
+ || !action_b
+ || qobject_cast<SpecialMenuAction*>(action_a)
+ || qobject_cast<SpecialMenuAction*>(action_b))
+ return false; // nothing to do
+
+ right = qMin(right, realActionCount());
+ if (right < 0)
+ return false; // nothing to do
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ fw->beginCommand(QApplication::translate("Command", "Move action"));
+
+ QAction *action_b_before = safeActionAt(right + 1);
+
+ RemoveActionFromCommand *cmd1 = new RemoveActionFromCommand(fw);
+ cmd1->init(this, action_b, action_b_before, false);
+ fw->commandHistory()->push(cmd1);
+
+ QAction *action_a_before = safeActionAt(left + 1);
+
+ InsertActionIntoCommand *cmd2 = new InsertActionIntoCommand(fw);
+ cmd2->init(this, action_b, action_a_before, false);
+ fw->commandHistory()->push(cmd2);
+
+ RemoveActionFromCommand *cmd3 = new RemoveActionFromCommand(fw);
+ cmd3->init(this, action_a, action_b, false);
+ fw->commandHistory()->push(cmd3);
+
+ InsertActionIntoCommand *cmd4 = new InsertActionIntoCommand(fw);
+ cmd4->init(this, action_a, action_b_before, true);
+ fw->commandHistory()->push(cmd4);
+
+ fw->endCommand();
+
+ return true;
+}
+
+QAction *QDesignerMenu::safeActionAt(int index) const
+{
+ if (index < 0 || index >= actions().count())
+ return 0;
+
+ return actions().at(index);
+}
+
+void QDesignerMenu::hideSubMenu()
+{
+ m_lastSubMenuIndex = -1;
+ foreach (QMenu *subMenu, qFindChildren<QMenu*>(this)) {
+ subMenu->hide();
+ }
+}
+
+void QDesignerMenu::deleteAction()
+{
+ QAction *action = currentAction();
+ const int pos = actions().indexOf(action);
+ QAction *action_before = 0;
+ if (pos != -1)
+ action_before = safeActionAt(pos + 1);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ cmd->init(this, action, action_before);
+ fw->commandHistory()->push(cmd);
+
+ update();
+}
+
+void QDesignerMenu::deactivateMenu()
+{
+ m_deactivateWindowTimer->start(10);
+}
+
+void QDesignerMenu::slotDeactivateNow()
+{
+ m_deactivateWindowTimer->stop();
+
+ if (m_dragging)
+ return;
+
+ QDesignerMenu *root = findRootMenu();
+
+ if (! root->findActivatedMenu()) {
+ root->hide();
+ root->hideSubMenu();
+ }
+}
+
+void QDesignerMenu::drawSelection(QPainter *p, const QRect &r)
+{
+ p->save();
+
+ QColor c = Qt::blue;
+ p->setPen(QPen(c, 1));
+ c.setAlpha(32);
+ p->setBrush(c);
+ p->drawRect(r);
+
+ p->restore();
+}
+
+void QDesignerMenu::keyPressEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QDesignerMenu::keyReleaseEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_menu_p.h b/tools/designer/src/lib/shared/qdesigner_menu_p.h
new file mode 100644
index 0000000..ac3ec03
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_menu_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_MENU_H
+#define QDESIGNER_MENU_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+class QLineEdit;
+
+class QDesignerFormWindowInterface;
+class QDesignerActionProviderExtension;
+class QDesignerMenu;
+class QDesignerMenuBar;
+class QPainter;
+class QMimeData;
+
+namespace qdesigner_internal {
+ class CreateSubmenuCommand;
+ class ActionInsertionCommand;
+}
+
+class QDESIGNER_SHARED_EXPORT QDesignerMenu: public QMenu
+{
+ Q_OBJECT
+public:
+ QDesignerMenu(QWidget *parent = 0);
+ virtual ~QDesignerMenu();
+
+ bool eventFilter(QObject *object, QEvent *event);
+
+ QDesignerFormWindowInterface *formWindow() const;
+ QDesignerActionProviderExtension *actionProvider();
+
+ QDesignerMenu *parentMenu() const;
+ QDesignerMenuBar *parentMenuBar() const;
+
+ virtual void setVisible(bool visible);
+
+ void adjustSpecialActions();
+
+ bool interactive(bool i);
+ void createRealMenuAction(QAction *action);
+ void removeRealMenu(QAction *action);
+
+ static void drawSelection(QPainter *p, const QRect &r);
+
+ bool dragging() const;
+
+ void closeMenuChain();
+
+ void moveLeft();
+ void moveRight();
+ void moveUp(bool ctrl);
+ void moveDown(bool ctrl);
+
+ // Helper for MenuTaskMenu extension
+ void deleteAction(QAction *a);
+
+private slots:
+ void slotAddSeparator();
+ void slotRemoveSelectedAction();
+ void slotShowSubMenuNow();
+ void slotDeactivateNow();
+ void slotAdjustSizeNow();
+
+protected:
+ virtual void actionEvent(QActionEvent *event);
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dragLeaveEvent(QDragLeaveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void showEvent(QShowEvent *event);
+
+ bool handleEvent(QWidget *widget, QEvent *event);
+ bool handleMouseDoubleClickEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMousePressEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMouseReleaseEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMouseMoveEvent(QWidget *widget, QMouseEvent *event);
+ bool handleContextMenuEvent(QWidget *widget, QContextMenuEvent *event);
+ bool handleKeyPressEvent(QWidget *widget, QKeyEvent *event);
+
+ void startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers);
+
+ void adjustIndicator(const QPoint &pos);
+ int findAction(const QPoint &pos) const;
+
+ QAction *currentAction() const;
+ int realActionCount() const;
+ enum ActionDragCheck { NoActionDrag, ActionDragOnSubMenu, AcceptActionDrag };
+ ActionDragCheck checkAction(QAction *action) const;
+
+ void showSubMenu(QAction *action);
+
+ enum LeaveEditMode {
+ Default = 0,
+ ForceAccept
+ };
+
+ void enterEditMode();
+ void leaveEditMode(LeaveEditMode mode);
+ void showLineEdit();
+
+ QAction *createAction(const QString &text, bool separator = false);
+ QDesignerMenu *findOrCreateSubMenu(QAction *action);
+
+ QAction *safeActionAt(int index) const;
+ QAction *safeMenuAction(QDesignerMenu *menu) const;
+ bool swap(int a, int b);
+
+ void hideSubMenu();
+ void deleteAction();
+ void deactivateMenu();
+
+ bool canCreateSubMenu(QAction *action) const;
+ QDesignerMenu *findRootMenu() const;
+ QDesignerMenu *findActivatedMenu() const;
+
+ QRect subMenuPixmapRect(QAction *action) const;
+ bool hasSubMenuPixmap(QAction *action) const;
+
+ void selectCurrentAction();
+
+private:
+ QPoint m_startPosition;
+ int m_currentIndex;
+ QAction *m_addItem;
+ QAction *m_addSeparator;
+ QHash<QAction*, QDesignerMenu*> m_subMenus;
+ QTimer *m_showSubMenuTimer;
+ QTimer *m_deactivateWindowTimer;
+ QTimer *m_adjustSizeTimer;
+ bool m_interactive;
+ QLineEdit *m_editor;
+ bool m_dragging;
+ int m_lastSubMenuIndex;
+
+ friend class qdesigner_internal::CreateSubmenuCommand;
+ friend class qdesigner_internal::ActionInsertionCommand;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_MENU_H
diff --git a/tools/designer/src/lib/shared/qdesigner_menubar.cpp b/tools/designer/src/lib/shared/qdesigner_menubar.cpp
new file mode 100644
index 0000000..97f1734
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_menubar.cpp
@@ -0,0 +1,955 @@
+/****************************************************************************
+**
+** 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_menubar_p.h"
+#include "qdesigner_menu_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "actionrepository_p.h"
+#include "actionprovider_p.h"
+#include "actioneditor_p.h"
+#include "qdesigner_utils_p.h"
+#include "promotiontaskmenu_p.h"
+#include "qdesigner_objectinspector_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QMimeData>
+
+#include <QtCore/qdebug.h>
+
+#include <QtGui/QApplication>
+#include <QtGui/QDrag>
+#include <QtGui/QLineEdit>
+#include <QtGui/QPainter>
+#include <QtGui/qevent.h>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+typedef QList<QAction *> ActionList;
+
+using namespace qdesigner_internal;
+
+namespace qdesigner_internal
+{
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+SpecialMenuAction::SpecialMenuAction(QObject *parent)
+ : QAction(parent)
+{
+}
+
+SpecialMenuAction::~SpecialMenuAction()
+{
+}
+
+
+} // namespace qdesigner_internal
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) :
+ QMenuBar(parent),
+ m_addMenu(new SpecialMenuAction(this)),
+ m_currentIndex(0),
+ m_interactive(true),
+ m_editor(new QLineEdit(this)),
+ m_dragging(false),
+ m_lastMenuActionIndex( -1),
+ m_promotionTaskMenu(new PromotionTaskMenu(this, PromotionTaskMenu::ModeSingleWidget, this))
+{
+ setContextMenuPolicy(Qt::DefaultContextMenu);
+
+ setAcceptDrops(true); // ### fake
+
+ m_addMenu->setText(tr("Type Here"));
+ addAction(m_addMenu);
+
+ QFont italic;
+ italic.setItalic(true);
+ m_addMenu->setFont(italic);
+
+ m_editor->setObjectName(QLatin1String("__qt__passive_editor"));
+ m_editor->hide();
+ m_editor->installEventFilter(this);
+ installEventFilter(this);
+}
+
+QDesignerMenuBar::~QDesignerMenuBar()
+{
+}
+
+void QDesignerMenuBar::paintEvent(QPaintEvent *event)
+{
+ QMenuBar::paintEvent(event);
+
+ QPainter p(this);
+
+ foreach (QAction *a, actions()) {
+ if (qobject_cast<SpecialMenuAction*>(a)) {
+ const QRect g = actionGeometry(a);
+ QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
+ lg.setColorAt(0.0, Qt::transparent);
+ lg.setColorAt(0.7, QColor(0, 0, 0, 32));
+ lg.setColorAt(1.0, Qt::transparent);
+
+ p.fillRect(g, lg);
+ }
+ }
+
+ QAction *action = currentAction();
+
+ if (m_dragging || !action)
+ return;
+
+ if (hasFocus()) {
+ const QRect g = actionGeometry(action);
+ QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1));
+ } else if (action->menu() && action->menu()->isVisible()) {
+ const QRect g = actionGeometry(action);
+ p.drawRect(g.adjusted(1, 1, -1, -1));
+ }
+}
+
+bool QDesignerMenuBar::handleEvent(QWidget *widget, QEvent *event)
+{
+ if (!formWindow())
+ return false;
+
+ if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
+ update();
+
+ switch (event->type()) {
+ default: break;
+
+ case QEvent::MouseButtonDblClick:
+ return handleMouseDoubleClickEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseButtonPress:
+ return handleMousePressEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseButtonRelease:
+ return handleMouseReleaseEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::MouseMove:
+ return handleMouseMoveEvent(widget, static_cast<QMouseEvent*>(event));
+ case QEvent::ContextMenu:
+ return handleContextMenuEvent(widget, static_cast<QContextMenuEvent*>(event));
+ case QEvent::KeyPress:
+ return handleKeyPressEvent(widget, static_cast<QKeyEvent*>(event));
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ return widget != m_editor;
+ }
+
+ return true;
+}
+
+bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
+{
+ if (!rect().contains(event->pos()))
+ return true;
+
+ if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+ return true;
+
+ event->accept();
+
+ m_startPosition = QPoint();
+
+ m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal);
+ if (m_currentIndex != -1) {
+ showLineEdit();
+ }
+
+ return true;
+}
+
+bool QDesignerMenuBar::handleKeyPressEvent(QWidget *, QKeyEvent *e)
+{
+ if (m_editor->isHidden()) { // In navigation mode
+ switch (e->key()) {
+
+ case Qt::Key_Delete:
+ if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
+ break;
+ hideMenu();
+ deleteMenu();
+ break;
+
+ case Qt::Key_Left:
+ e->accept();
+ if (QApplication::layoutDirection() == Qt::LeftToRight)
+ moveLeft(e->modifiers() & Qt::ControlModifier);
+ else
+ moveRight(e->modifiers() & Qt::ControlModifier);
+ return true;
+
+ case Qt::Key_Right:
+ e->accept();
+ if (QApplication::layoutDirection() == Qt::LeftToRight)
+ moveRight(e->modifiers() & Qt::ControlModifier);
+ else
+ moveLeft(e->modifiers() & Qt::ControlModifier);
+ return true; // no update
+
+ case Qt::Key_Up:
+ e->accept();
+ moveUp();
+ return true;
+
+ case Qt::Key_Down:
+ e->accept();
+ moveDown();
+ return true;
+
+ case Qt::Key_PageUp:
+ m_currentIndex = 0;
+ break;
+
+ case Qt::Key_PageDown:
+ m_currentIndex = actions().count() - 1;
+ break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ e->accept();
+ enterEditMode();
+ return true; // no update
+
+ case Qt::Key_Alt:
+ case Qt::Key_Shift:
+ case Qt::Key_Control:
+ case Qt::Key_Escape:
+ e->ignore();
+ setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed
+ return true; // no update
+
+ default:
+ if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
+ showLineEdit();
+ QApplication::sendEvent(m_editor, e);
+ e->accept();
+ } else {
+ e->ignore();
+ }
+ return true;
+ }
+ } else { // In edit mode
+ switch (e->key()) {
+ default:
+ return false;
+
+ case Qt::Key_Control:
+ e->ignore();
+ return true;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (!m_editor->text().isEmpty()) {
+ leaveEditMode(ForceAccept);
+ if (m_lastFocusWidget)
+ m_lastFocusWidget->setFocus();
+
+ m_editor->hide();
+ showMenu();
+ break;
+ }
+ // fall through
+
+ case Qt::Key_Escape:
+ update();
+ setFocus();
+ break;
+ }
+ }
+
+ e->accept();
+ update();
+
+ return true;
+}
+
+void QDesignerMenuBar::startDrag(const QPoint &pos)
+{
+ const int index = findAction(pos);
+ if (m_currentIndex == -1 || index >= realActionCount())
+ return;
+
+ QAction *action = safeActionAt(index);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ cmd->init(this, action, actions().at(index + 1));
+ fw->commandHistory()->push(cmd);
+
+ adjustSize();
+
+ hideMenu(index);
+
+ QDrag *drag = new QDrag(this);
+ drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
+ drag->setMimeData(new ActionRepositoryMimeData(action, Qt::MoveAction));
+
+ const int old_index = m_currentIndex;
+ m_currentIndex = -1;
+
+ if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) {
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, action, safeActionAt(index));
+ fw->commandHistory()->push(cmd);
+
+ m_currentIndex = old_index;
+ adjustSize();
+ }
+}
+
+bool QDesignerMenuBar::handleMousePressEvent(QWidget *, QMouseEvent *event)
+{
+ m_startPosition = QPoint();
+ event->accept();
+
+ if (event->button() != Qt::LeftButton)
+ return true;
+
+ m_startPosition = event->pos();
+ const int newIndex = actionIndexAt(this, m_startPosition, Qt::Horizontal);
+ const bool changed = newIndex != m_currentIndex;
+ m_currentIndex = newIndex;
+ updateCurrentAction(changed);
+
+ return true;
+}
+
+bool QDesignerMenuBar::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
+{
+ m_startPosition = QPoint();
+
+ if (event->button() != Qt::LeftButton)
+ return true;
+
+ event->accept();
+ m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal);
+ if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount())
+ showMenu();
+
+ return true;
+}
+
+bool QDesignerMenuBar::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
+{
+ if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+ return true;
+
+ if (m_startPosition.isNull())
+ return true;
+
+ const QPoint pos = mapFromGlobal(event->globalPos());
+
+ if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
+ return true;
+
+ const int index = actionIndexAt(this, m_startPosition, Qt::Horizontal);
+ if (index < actions().count()) {
+ hideMenu(index);
+ update();
+ }
+
+ startDrag(m_startPosition);
+ m_startPosition = QPoint();
+
+ return true;
+}
+
+ActionList QDesignerMenuBar::contextMenuActions()
+{
+ ActionList rc;
+ if (QAction *action = safeActionAt(m_currentIndex)) {
+ if (!qobject_cast<SpecialMenuAction*>(action)) {
+ QVariant itemData;
+ qVariantSetValue(itemData, action);
+
+ QAction *remove_action = new QAction(tr("Remove Menu '%1'").arg(action->menu()->objectName()), 0);
+ remove_action->setData(itemData);
+ connect(remove_action, SIGNAL(triggered()), this, SLOT(deleteMenu()));
+ rc.push_back(remove_action);
+ QAction *sep = new QAction(0);
+ sep->setSeparator(true);
+ rc.push_back(sep);
+ }
+ }
+
+ m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc);
+
+ QAction *remove_menubar = new QAction(tr("Remove Menu Bar"), 0);
+ connect(remove_menubar, SIGNAL(triggered()), this, SLOT(slotRemoveMenuBar()));
+ rc.push_back(remove_menubar);
+ return rc;
+}
+
+bool QDesignerMenuBar::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
+{
+ event->accept();
+
+ m_currentIndex = actionIndexAt(this, mapFromGlobal(event->globalPos()), Qt::Horizontal);
+
+ update();
+
+ QMenu menu;
+ const ActionList al = contextMenuActions();
+ const ActionList::const_iterator acend = al.constEnd();
+ for (ActionList::const_iterator it = al.constBegin(); it != acend; ++it)
+ menu.addAction(*it);
+ menu.exec(event->globalPos());
+ return true;
+}
+
+void QDesignerMenuBar::slotRemoveMenuBar()
+{
+ Q_ASSERT(formWindow() != 0);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+
+ DeleteMenuBarCommand *cmd = new DeleteMenuBarCommand(fw);
+ cmd->init(this);
+ fw->commandHistory()->push(cmd);
+}
+
+void QDesignerMenuBar::focusOutEvent(QFocusEvent *event)
+{
+ QMenuBar::focusOutEvent(event);
+}
+
+void QDesignerMenuBar::enterEditMode()
+{
+ if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
+ showLineEdit();
+ }
+}
+
+void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode)
+{
+ m_editor->releaseKeyboard();
+
+ if (mode == Default)
+ return;
+
+ if (m_editor->text().isEmpty())
+ return;
+
+ QAction *action = 0;
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ Q_ASSERT(fw);
+
+ if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) {
+ action = safeActionAt(m_currentIndex);
+ fw->beginCommand(QApplication::translate("Command", "Change Title"));
+ } else {
+ fw->beginCommand(QApplication::translate("Command", "Insert Menu"));
+ const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), QLatin1String("menu"));
+ QMenu *menu = qobject_cast<QMenu*>(fw->core()->widgetFactory()->createWidget(QLatin1String("QMenu"), this));
+ fw->core()->widgetFactory()->initialize(menu);
+ menu->setObjectName(niceObjectName);
+ menu->setTitle(tr("Menu"));
+ fw->ensureUniqueObjectName(menu);
+ action = menu->menuAction();
+ AddMenuActionCommand *cmd = new AddMenuActionCommand(fw);
+ cmd->init(action, m_addMenu, this, this);
+ fw->commandHistory()->push(cmd);
+ }
+
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(action, QLatin1String("text"), m_editor->text());
+ fw->commandHistory()->push(cmd);
+ fw->endCommand();
+}
+
+void QDesignerMenuBar::showLineEdit()
+{
+ QAction *action = 0;
+
+ if (m_currentIndex >= 0 && m_currentIndex < realActionCount())
+ action = safeActionAt(m_currentIndex);
+ else
+ action = m_addMenu;
+
+ if (action->isSeparator())
+ return;
+
+ // hideMenu();
+
+ m_lastFocusWidget = qApp->focusWidget();
+
+ // open edit field for item name
+ const QString text = action != m_addMenu ? action->text() : QString();
+
+ m_editor->setText(text);
+ m_editor->selectAll();
+ m_editor->setGeometry(actionGeometry(action));
+ m_editor->show();
+ qApp->setActiveWindow(m_editor);
+ m_editor->setFocus();
+ m_editor->grabKeyboard();
+}
+
+bool QDesignerMenuBar::eventFilter(QObject *object, QEvent *event)
+{
+ if (object != this && object != m_editor)
+ return false;
+
+ if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) {
+ leaveEditMode(Default);
+ m_editor->hide();
+ update();
+ return true;
+ }
+
+ bool dispatch = true;
+
+ switch (event->type()) {
+ default: break;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::ContextMenu:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ dispatch = (object != m_editor);
+ // no break
+
+ case QEvent::Enter:
+ case QEvent::Leave:
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ {
+ QWidget *widget = qobject_cast<QWidget*>(object);
+
+ if (dispatch && widget && (widget == this || isAncestorOf(widget)))
+ return handleEvent(widget, event);
+ } break;
+
+ case QEvent::Shortcut:
+ event->accept();
+ return true;
+ }
+
+ return false;
+};
+
+int QDesignerMenuBar::findAction(const QPoint &pos) const
+{
+ const int index = actionIndexAt(this, pos, Qt::Horizontal);
+ if (index == -1)
+ return realActionCount();
+
+ return index;
+}
+
+void QDesignerMenuBar::adjustIndicator(const QPoint &pos)
+{
+ const int index = findAction(pos);
+ QAction *action = safeActionAt(index);
+ Q_ASSERT(action != 0);
+
+ if (pos != QPoint(-1, -1)) {
+ QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
+ if (!m || m->parentMenu()) {
+ m_currentIndex = index;
+ showMenu(index);
+ }
+ }
+
+ if (QDesignerActionProviderExtension *a = actionProvider()) {
+ a->adjustIndicator(pos);
+ }
+}
+
+QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action) const
+{
+ // action belongs to another form
+ if (!action || !Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
+ return NoActionDrag;
+
+ if (!action->menu())
+ return ActionDragOnSubMenu; // simple action only on sub menus
+
+ QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
+ if (m && m->parentMenu())
+ return ActionDragOnSubMenu; // it looks like a submenu
+
+ if (actions().contains(action))
+ return ActionDragOnSubMenu; // we already have the action in the menubar
+
+ return AcceptActionDrag;
+}
+
+void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event)
+{
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d || d->actionList().empty()) {
+ event->ignore();
+ return;
+ }
+
+ QAction *action = d->actionList().first();
+ switch (checkAction(action)) {
+ case NoActionDrag:
+ event->ignore();
+ break;
+ case ActionDragOnSubMenu:
+ m_dragging = true;
+ d->accept(event);
+ break;
+ case AcceptActionDrag:
+ m_dragging = true;
+ d->accept(event);
+ adjustIndicator(event->pos());
+ break;
+ }
+}
+
+void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event)
+{
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d || d->actionList().empty()) {
+ event->ignore();
+ return;
+ }
+ QAction *action = d->actionList().first();
+
+ switch (checkAction(action)) {
+ case NoActionDrag:
+ event->ignore();
+ break;
+ case ActionDragOnSubMenu:
+ event->ignore();
+ showMenu(findAction(event->pos()));
+ break;
+ case AcceptActionDrag:
+ d->accept(event);
+ adjustIndicator(event->pos());
+ break;
+ }
+}
+
+void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *)
+{
+ m_dragging = false;
+
+ adjustIndicator(QPoint(-1, -1));
+}
+
+void QDesignerMenuBar::dropEvent(QDropEvent *event)
+{
+ m_dragging = false;
+
+ if (const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData())) {
+
+ QAction *action = d->actionList().first();
+ if (checkAction(action) == AcceptActionDrag) {
+ event->acceptProposedAction();
+ int index = findAction(event->pos());
+ index = qMin(index, actions().count() - 1);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(this, action, safeActionAt(index));
+ fw->commandHistory()->push(cmd);
+
+ m_currentIndex = index;
+ update();
+ adjustIndicator(QPoint(-1, -1));
+ return;
+ }
+ }
+ event->ignore();
+}
+
+void QDesignerMenuBar::actionEvent(QActionEvent *event)
+{
+ QMenuBar::actionEvent(event);
+}
+
+QDesignerFormWindowInterface *QDesignerMenuBar::formWindow() const
+{
+ return QDesignerFormWindowInterface::findFormWindow(const_cast<QDesignerMenuBar*>(this));
+}
+
+QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QDesignerFormEditorInterface *core = fw->core();
+ return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), this);
+ }
+
+ return 0;
+}
+
+QAction *QDesignerMenuBar::currentAction() const
+{
+ if (m_currentIndex < 0 || m_currentIndex >= actions().count())
+ return 0;
+
+ return safeActionAt(m_currentIndex);
+}
+
+int QDesignerMenuBar::realActionCount() const
+{
+ return actions().count() - 1; // 1 fake actions
+}
+
+void QDesignerMenuBar::moveLeft(bool ctrl)
+{
+ if (ctrl)
+ (void) swap(m_currentIndex, m_currentIndex - 1);
+
+ m_currentIndex = qMax(0, --m_currentIndex);
+ // Always re-select, swapping destroys order
+ updateCurrentAction(true);
+}
+
+bool QDesignerMenuBar::dragging() const
+{
+ return m_dragging;
+}
+
+void QDesignerMenuBar::moveRight(bool ctrl)
+{
+ if (ctrl)
+ (void) swap(m_currentIndex + 1, m_currentIndex);
+
+ m_currentIndex = qMin(actions().count() - 1, ++m_currentIndex);
+ updateCurrentAction(!ctrl);
+}
+
+void QDesignerMenuBar::moveUp()
+{
+ update();
+}
+
+void QDesignerMenuBar::moveDown()
+{
+ showMenu();
+}
+
+void QDesignerMenuBar::adjustSpecialActions()
+{
+ removeAction(m_addMenu);
+ addAction(m_addMenu);
+}
+
+bool QDesignerMenuBar::interactive(bool i)
+{
+ const bool old = m_interactive;
+ m_interactive = i;
+ return old;
+}
+
+void QDesignerMenuBar::hideMenu(int index)
+{
+ if (index < 0 && m_currentIndex >= 0)
+ index = m_currentIndex;
+
+ if (index < 0 || index >= realActionCount())
+ return;
+
+ QAction *action = safeActionAt(index);
+
+ if (action && action->menu()) {
+ action->menu()->hide();
+
+ if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu())) {
+ menu->closeMenuChain();
+ }
+ }
+}
+
+void QDesignerMenuBar::deleteMenu()
+{
+ deleteMenuAction(currentAction());
+}
+
+void QDesignerMenuBar::deleteMenuAction(QAction *action)
+{
+ if (action && !qobject_cast<SpecialMenuAction*>(action)) {
+ const int pos = actions().indexOf(action);
+ QAction *action_before = 0;
+ if (pos != -1)
+ action_before = safeActionAt(pos + 1);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ RemoveMenuActionCommand *cmd = new RemoveMenuActionCommand(fw);
+ cmd->init(action, action_before, this, this);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QDesignerMenuBar::showMenu(int index)
+{
+ if (index < 0 && m_currentIndex >= 0)
+ index = m_currentIndex;
+
+ if (index < 0 || index >= realActionCount())
+ return;
+
+ m_currentIndex = index;
+ QAction *action = currentAction();
+
+ if (action && action->menu()) {
+ if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) {
+ hideMenu(m_lastMenuActionIndex);
+ }
+
+ m_lastMenuActionIndex = index;
+ QMenu *menu = action->menu();
+ const QRect g = actionGeometry(action);
+
+ if (!menu->isVisible()) {
+ if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
+ menu->setWindowFlags(Qt::Popup);
+ menu->adjustSize();
+ menu->move(mapToGlobal(g.bottomLeft()));
+ menu->setFocus(Qt::MouseFocusReason);
+ menu->raise();
+ menu->show();
+ } else {
+ menu->raise();
+ }
+ }
+}
+
+QAction *QDesignerMenuBar::safeActionAt(int index) const
+{
+ if (index < 0 || index >= actions().count())
+ return 0;
+
+ return actions().at(index);
+}
+
+bool QDesignerMenuBar::swap(int a, int b)
+{
+ const int left = qMin(a, b);
+ int right = qMax(a, b);
+
+ QAction *action_a = safeActionAt(left);
+ QAction *action_b = safeActionAt(right);
+
+ if (action_a == action_b
+ || !action_a
+ || !action_b
+ || qobject_cast<SpecialMenuAction*>(action_a)
+ || qobject_cast<SpecialMenuAction*>(action_b))
+ return false; // nothing to do
+
+ right = qMin(right, realActionCount());
+ if (right < 0)
+ return false; // nothing to do
+
+ formWindow()->beginCommand(QApplication::translate("Command", "Move action"));
+
+ QAction *action_b_before = safeActionAt(right + 1);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ RemoveActionFromCommand *cmd1 = new RemoveActionFromCommand(fw);
+ cmd1->init(this, action_b, action_b_before, false);
+ fw->commandHistory()->push(cmd1);
+
+ QAction *action_a_before = safeActionAt(left + 1);
+
+ InsertActionIntoCommand *cmd2 = new InsertActionIntoCommand(fw);
+ cmd2->init(this, action_b, action_a_before, false);
+ fw->commandHistory()->push(cmd2);
+
+ RemoveActionFromCommand *cmd3 = new RemoveActionFromCommand(fw);
+ cmd3->init(this, action_a, action_b, false);
+ fw->commandHistory()->push(cmd3);
+
+ InsertActionIntoCommand *cmd4 = new InsertActionIntoCommand(fw);
+ cmd4->init(this, action_a, action_b_before, true);
+ fw->commandHistory()->push(cmd4);
+
+ fw->endCommand();
+
+ return true;
+}
+
+void QDesignerMenuBar::keyPressEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QDesignerMenuBar::updateCurrentAction(bool selectAction)
+{
+ update();
+
+ if (!selectAction)
+ return;
+
+ QAction *action = currentAction();
+ if (!action || action == m_addMenu)
+ return;
+
+ QMenu *menu = action->menu();
+ if (!menu)
+ return;
+
+ QDesignerObjectInspector *oi = 0;
+ if (QDesignerFormWindowInterface *fw = formWindow())
+ oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
+
+ if (!oi)
+ return;
+
+ oi->clearSelection();
+ oi->selectObject(menu);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_menubar_p.h b/tools/designer/src/lib/shared/qdesigner_menubar_p.h
new file mode 100644
index 0000000..7c8be4c
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_menubar_p.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_MENUBAR_H
+#define QDESIGNER_MENUBAR_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QAction>
+#include <QtGui/QMenuBar>
+
+#include <QtCore/QPointer>
+#include <QtCore/QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerActionProviderExtension;
+
+class QLineEdit;
+class QMimeData;
+
+namespace qdesigner_internal {
+class PromotionTaskMenu;
+
+class SpecialMenuAction: public QAction
+{
+ Q_OBJECT
+public:
+ SpecialMenuAction(QObject *parent = 0);
+ virtual ~SpecialMenuAction();
+};
+
+} // namespace qdesigner_internal
+
+class QDESIGNER_SHARED_EXPORT QDesignerMenuBar: public QMenuBar
+{
+ Q_OBJECT
+public:
+ QDesignerMenuBar(QWidget *parent = 0);
+ virtual ~QDesignerMenuBar();
+
+ bool eventFilter(QObject *object, QEvent *event);
+
+ QDesignerFormWindowInterface *formWindow() const;
+ QDesignerActionProviderExtension *actionProvider();
+
+ void adjustSpecialActions();
+ bool interactive(bool i);
+ bool dragging() const;
+
+ void moveLeft(bool ctrl = false);
+ void moveRight(bool ctrl = false);
+ void moveUp();
+ void moveDown();
+
+ // Helpers for MenuTaskMenu/MenuBarTaskMenu extensions
+ QList<QAction *> contextMenuActions();
+ void deleteMenuAction(QAction *action);
+
+private slots:
+ void deleteMenu();
+ void slotRemoveMenuBar();
+
+protected:
+ virtual void actionEvent(QActionEvent *event);
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dragLeaveEvent(QDragLeaveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void focusOutEvent(QFocusEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+
+ bool handleEvent(QWidget *widget, QEvent *event);
+ bool handleMouseDoubleClickEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMousePressEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMouseReleaseEvent(QWidget *widget, QMouseEvent *event);
+ bool handleMouseMoveEvent(QWidget *widget, QMouseEvent *event);
+ bool handleContextMenuEvent(QWidget *widget, QContextMenuEvent *event);
+ bool handleKeyPressEvent(QWidget *widget, QKeyEvent *event);
+
+ void startDrag(const QPoint &pos);
+
+ enum ActionDragCheck { NoActionDrag, ActionDragOnSubMenu, AcceptActionDrag };
+ ActionDragCheck checkAction(QAction *action) const;
+
+ void adjustIndicator(const QPoint &pos);
+ int findAction(const QPoint &pos) const;
+
+ QAction *currentAction() const;
+ int realActionCount() const;
+
+ enum LeaveEditMode {
+ Default = 0,
+ ForceAccept
+ };
+
+ void enterEditMode();
+ void leaveEditMode(LeaveEditMode mode);
+ void showLineEdit();
+
+ void showMenu(int index = -1);
+ void hideMenu(int index = -1);
+
+ QAction *safeActionAt(int index) const;
+
+ bool swap(int a, int b);
+
+private:
+ void updateCurrentAction(bool selectAction);
+
+ QAction *m_addMenu;
+ QPointer<QMenu> m_activeMenu;
+ QPoint m_startPosition;
+ int m_currentIndex;
+ bool m_interactive;
+ QLineEdit *m_editor;
+ bool m_dragging;
+ int m_lastMenuActionIndex;
+ QPointer<QWidget> m_lastFocusWidget;
+ qdesigner_internal::PromotionTaskMenu* m_promotionTaskMenu;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_MENUBAR_H
diff --git a/tools/designer/src/lib/shared/qdesigner_objectinspector.cpp b/tools/designer/src/lib/shared/qdesigner_objectinspector.cpp
new file mode 100644
index 0000000..9cef55b
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_objectinspector.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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_objectinspector_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+QDesignerObjectInspector::QDesignerObjectInspector(QWidget *parent, Qt::WindowFlags flags) :
+ QDesignerObjectInspectorInterface(parent, flags)
+{
+}
+
+void QDesignerObjectInspector::mainContainerChanged()
+{
+}
+
+void Selection::clear()
+{
+ managed.clear();
+ unmanaged.clear();
+ objects.clear();
+}
+
+bool Selection::empty() const
+{
+ return managed.empty() && unmanaged.empty() && objects.empty();
+}
+
+QObjectList Selection::selection() const
+{
+ QObjectList rc(objects);
+ foreach (QObject* o, managed)
+ rc.push_back(o);
+ foreach (QObject* o, unmanaged)
+ rc.push_back(o);
+ return rc;
+}
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_objectinspector_p.h b/tools/designer/src/lib/shared/qdesigner_objectinspector_p.h
new file mode 100644
index 0000000..5a4a163
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_objectinspector_p.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$
+**
+****************************************************************************/
+
+//
+// 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 DESIGNEROBJECTINSPECTOR_H
+#define DESIGNEROBJECTINSPECTOR_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/QDesignerObjectInspectorInterface>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerDnDItemInterface;
+
+namespace qdesigner_internal {
+
+struct QDESIGNER_SHARED_EXPORT Selection {
+ bool empty() const;
+ void clear();
+
+ // Merge all lists
+ QObjectList selection() const;
+
+ // Selection in cursor (managed widgets)
+ QWidgetList managed;
+ // Unmanaged widgets
+ QWidgetList unmanaged;
+ // Remaining selected objects (non-widgets)
+ QObjectList objects;
+};
+
+// Extends the QDesignerObjectInspectorInterface by functionality
+// to access the selection
+
+class QDESIGNER_SHARED_EXPORT QDesignerObjectInspector: public QDesignerObjectInspectorInterface
+{
+ Q_OBJECT
+public:
+ QDesignerObjectInspector(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+
+ // Select a qobject unmanaged by form window
+ virtual bool selectObject(QObject *o) = 0;
+ virtual void getSelection(Selection &s) const = 0;
+ virtual void clearSelection() = 0;
+
+public slots:
+ virtual void mainContainerChanged();
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // DESIGNEROBJECTINSPECTOR_H
diff --git a/tools/designer/src/lib/shared/qdesigner_promotion.cpp b/tools/designer/src/lib/shared/qdesigner_promotion.cpp
new file mode 100644
index 0000000..526b521
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_promotion.cpp
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** 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_promotion_p.h"
+#include "widgetdatabase_p.h"
+#include "metadatabase_p.h"
+#include "widgetdatabase_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+#include <QtDesigner/QDesignerObjectInspectorInterface>
+#include <QtDesigner/QDesignerWidgetBoxInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtCore/QMap>
+#include <QtCore/QCoreApplication>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ // Return a set of on-promotable classes
+ const QSet<QString> &nonPromotableClasses() {
+ static QSet<QString> rc;
+ if (rc.empty()) {
+ rc.insert(QLatin1String("Line"));
+ rc.insert(QLatin1String("QAction"));
+ rc.insert(QLatin1String("Spacer"));
+ rc.insert(QLatin1String("QMainWindow"));
+ rc.insert(QLatin1String("QDialog"));
+ rc.insert(QLatin1String("QWorkspace"));
+ rc.insert(QLatin1String("QMdiArea"));
+ rc.insert(QLatin1String("QMdiSubWindow"));
+ }
+ return rc;
+ }
+
+ // Return widget database index of a promoted class or -1 with error message
+ int promotedWidgetDataBaseIndex(const QDesignerWidgetDataBaseInterface *widgetDataBase,
+ const QString &className,
+ QString *errorMessage) {
+ const int index = widgetDataBase->indexOfClassName(className);
+ if (index == -1 || !widgetDataBase->item(index)->isPromoted()) {
+ *errorMessage = QCoreApplication::tr("%1 is not a promoted class.").arg(className);
+ return -1;
+ }
+ return index;
+ }
+
+ // Return widget database item of a promoted class or 0 with error message
+ QDesignerWidgetDataBaseItemInterface *promotedWidgetDataBaseItem(const QDesignerWidgetDataBaseInterface *widgetDataBase,
+ const QString &className,
+ QString *errorMessage) {
+
+ const int index = promotedWidgetDataBaseIndex(widgetDataBase, className, errorMessage);
+ if (index == -1)
+ return 0;
+ return widgetDataBase->item(index);
+ }
+
+ // extract class name from xml "<widget class="QWidget" ...>". Quite a hack.
+ QString classNameFromXml(QString xml) {
+ static const QString tag = QLatin1String("class=\"");
+ const int pos = xml.indexOf(tag);
+ if (pos == -1)
+ return QString();
+ xml.remove(0, pos + tag.size());
+ const int closingPos = xml.indexOf(QLatin1Char('"'));
+ if (closingPos == -1)
+ return QString();
+ xml.remove(closingPos, xml.size() - closingPos);
+ return xml;
+ }
+
+ // return a list of class names in the scratch pad
+ QStringList getScratchPadClasses(const QDesignerWidgetBoxInterface *wb) {
+ QStringList rc;
+ const int catCount = wb->categoryCount();
+ for (int c = 0; c < catCount; c++) {
+ const QDesignerWidgetBoxInterface::Category category = wb->category(c);
+ if (category.type() == QDesignerWidgetBoxInterface::Category::Scratchpad) {
+ const int widgetCount = category.widgetCount();
+ for (int w = 0; w < widgetCount; w++) {
+ const QString className = classNameFromXml( category.widget(w).domXml());
+ if (!className.isEmpty())
+ rc += className;
+ }
+ }
+ }
+ return rc;
+ }
+}
+
+namespace qdesigner_internal {
+
+ QDesignerPromotion::QDesignerPromotion(QDesignerFormEditorInterface *core) :
+ m_core(core) {
+ }
+
+ bool QDesignerPromotion::addPromotedClass(const QString &baseClass,
+ const QString &className,
+ const QString &includeFile,
+ QString *errorMessage)
+ {
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+ const int baseClassIndex = widgetDataBase->indexOfClassName(baseClass);
+
+ if (baseClassIndex == -1) {
+ *errorMessage = QCoreApplication::tr("The base class %1 is invalid.").arg(baseClass);
+ return false;
+ }
+
+ const int existingClassIndex = widgetDataBase->indexOfClassName(className);
+
+ if (existingClassIndex != -1) {
+ *errorMessage = QCoreApplication::tr("The class %1 already exists.").arg(className);
+ return false;
+ }
+ // Clone derived item.
+ QDesignerWidgetDataBaseItemInterface *promotedItem = WidgetDataBaseItem::clone(widgetDataBase->item(baseClassIndex));
+ // Also inherit the container flag in case of QWidget-derived classes
+ // as it is most likely intended for stacked pages.
+ // set new props
+ promotedItem->setName(className);
+ promotedItem->setGroup(QCoreApplication::tr("Promoted Widgets"));
+ promotedItem->setCustom(true);
+ promotedItem->setPromoted(true);
+ promotedItem->setExtends(baseClass);
+ promotedItem->setIncludeFile(includeFile);
+ widgetDataBase->append(promotedItem);
+ return true;
+ }
+
+ QList<QDesignerWidgetDataBaseItemInterface *> QDesignerPromotion::promotionBaseClasses() const
+ {
+ typedef QMap<QString, QDesignerWidgetDataBaseItemInterface *> SortedDatabaseItemMap;
+ SortedDatabaseItemMap sortedDatabaseItemMap;
+
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+
+ const int cnt = widgetDataBase->count();
+ for (int i = 0; i < cnt; i++) {
+ QDesignerWidgetDataBaseItemInterface *dbItem = widgetDataBase->item(i);
+ if (canBePromoted(dbItem)) {
+ sortedDatabaseItemMap.insert(dbItem->name(), dbItem);
+ }
+ }
+
+ return sortedDatabaseItemMap.values();
+ }
+
+
+ bool QDesignerPromotion::canBePromoted(const QDesignerWidgetDataBaseItemInterface *dbItem) const
+ {
+ if (dbItem->isPromoted() || !dbItem->extends().isEmpty())
+ return false;
+
+ const QString name = dbItem->name();
+
+ if (nonPromotableClasses().contains(name))
+ return false;
+
+ if (name.startsWith(QLatin1String("QDesigner")) ||
+ name.startsWith(QLatin1String("QLayout")))
+ return false;
+
+ return true;
+ }
+
+ QDesignerPromotion::PromotedClasses QDesignerPromotion::promotedClasses() const
+ {
+ typedef QMap<QString, QDesignerWidgetDataBaseItemInterface *> ClassNameItemMap;
+ // A map containing base classes and their promoted classes.
+ typedef QMap<QString, ClassNameItemMap> BaseClassPromotedMap;
+
+ BaseClassPromotedMap baseClassPromotedMap;
+
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+ // Look for promoted classes and insert into map according to base class.
+ const int cnt = widgetDataBase->count();
+ for (int i = 0; i < cnt; i++) {
+ QDesignerWidgetDataBaseItemInterface *dbItem = widgetDataBase->item(i);
+ if (dbItem->isPromoted()) {
+ const QString baseClassName = dbItem->extends();
+ BaseClassPromotedMap::iterator it = baseClassPromotedMap.find(baseClassName);
+ if (it == baseClassPromotedMap.end()) {
+ it = baseClassPromotedMap.insert(baseClassName, ClassNameItemMap());
+ }
+ it.value().insert(dbItem->name(), dbItem);
+ }
+ }
+ // convert map into list.
+ PromotedClasses rc;
+
+ if (baseClassPromotedMap.empty())
+ return rc;
+
+ const BaseClassPromotedMap::const_iterator bcend = baseClassPromotedMap.constEnd();
+ for (BaseClassPromotedMap::const_iterator bit = baseClassPromotedMap.constBegin(); bit != bcend; ++bit) {
+ const int baseIndex = widgetDataBase->indexOfClassName(bit.key());
+ Q_ASSERT(baseIndex >= 0);
+ QDesignerWidgetDataBaseItemInterface *baseItem = widgetDataBase->item(baseIndex);
+ // promoted
+ const ClassNameItemMap::const_iterator pcend = bit.value().constEnd();
+ for (ClassNameItemMap::const_iterator pit = bit.value().constBegin(); pit != pcend; ++pit) {
+ PromotedClass item;
+ item.baseItem = baseItem;
+ item.promotedItem = pit.value();
+ rc.push_back(item);
+ }
+ }
+
+ return rc;
+ }
+
+ QSet<QString> QDesignerPromotion::referencedPromotedClassNames() const {
+ QSet<QString> rc;
+ const MetaDataBase *metaDataBase = qobject_cast<const MetaDataBase*>(m_core->metaDataBase());
+ if (!metaDataBase)
+ return rc;
+
+ const QList<QObject*> objs = metaDataBase->objects();
+ const QList<QObject*>::const_iterator cend = objs.constEnd();
+ for ( QList<QObject*>::const_iterator it = objs.constBegin(); it != cend; ++it) {
+ const QString customClass = metaDataBase->metaDataBaseItem(*it)->customClassName();
+ if (!customClass.isEmpty())
+ rc.insert(customClass);
+
+ }
+ // check the scratchpad of the widget box
+ if (QDesignerWidgetBoxInterface *widgetBox = m_core->widgetBox()) {
+ const QStringList scratchPadClasses = getScratchPadClasses(widgetBox);
+ if (!scratchPadClasses.empty()) {
+ // Check whether these are actually promoted
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+ QStringList::const_iterator cend = scratchPadClasses.constEnd();
+ for (QStringList::const_iterator it = scratchPadClasses.constBegin(); it != cend; ++it ) {
+ const int index = widgetDataBase->indexOfClassName(*it);
+ if (index != -1 && widgetDataBase->item(index)->isPromoted())
+ rc += *it;
+ }
+ }
+ }
+ return rc;
+ }
+
+ bool QDesignerPromotion::removePromotedClass(const QString &className, QString *errorMessage) {
+ // check if it exists and is promoted
+ WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase *>(m_core->widgetDataBase());
+ if (!widgetDataBase) {
+ *errorMessage = QCoreApplication::tr("The class %1 cannot be removed").arg(className);
+ return false;
+ }
+
+ const int index = promotedWidgetDataBaseIndex(widgetDataBase, className, errorMessage);
+ if (index == -1)
+ return false;
+
+ if (referencedPromotedClassNames().contains(className)) {
+ *errorMessage = QCoreApplication::tr("The class %1 cannot be removed because it is still referenced.").arg(className);
+ return false;
+ }
+ widgetDataBase->remove(index);
+ return true;
+ }
+
+ bool QDesignerPromotion::changePromotedClassName(const QString &oldclassName, const QString &newClassName, QString *errorMessage) {
+ const MetaDataBase *metaDataBase = qobject_cast<const MetaDataBase*>(m_core->metaDataBase());
+ if (!metaDataBase) {
+ *errorMessage = QCoreApplication::tr("The class %1 cannot be renamed").arg(oldclassName);
+ return false;
+ }
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+
+ // check the new name
+ if (newClassName.isEmpty()) {
+ *errorMessage = QCoreApplication::tr("The class %1 cannot be renamed to an empty name.").arg(oldclassName);
+ return false;
+ }
+ const int existingIndex = widgetDataBase->indexOfClassName(newClassName);
+ if (existingIndex != -1) {
+ *errorMessage = QCoreApplication::tr("There is already a class named %1.").arg(newClassName);
+ return false;
+ }
+ // Check old class
+ QDesignerWidgetDataBaseItemInterface *dbItem = promotedWidgetDataBaseItem(widgetDataBase, oldclassName, errorMessage);
+ if (!dbItem)
+ return false;
+
+ // Change the name in the data base and change all referencing objects in the meta database
+ dbItem->setName(newClassName);
+ bool foundReferences = false;
+ foreach (QObject* object, metaDataBase->objects()) {
+ MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(object);
+ Q_ASSERT(item);
+ if (item->customClassName() == oldclassName) {
+ item->setCustomClassName(newClassName);
+ foundReferences = true;
+ }
+ }
+ // set state
+ if (foundReferences)
+ refreshObjectInspector();
+
+ return true;
+ }
+
+ bool QDesignerPromotion::setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage) {
+ // check file
+ if (includeFile.isEmpty()) {
+ *errorMessage = QCoreApplication::tr("Cannot set an empty include file.");
+ return false;
+ }
+ // check item
+ QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
+ QDesignerWidgetDataBaseItemInterface *dbItem = promotedWidgetDataBaseItem(widgetDataBase, className, errorMessage);
+ if (!dbItem)
+ return false;
+
+ dbItem->setIncludeFile(includeFile);
+ return true;
+ }
+
+ void QDesignerPromotion::refreshObjectInspector() {
+ if (QDesignerFormWindowManagerInterface *fwm = m_core->formWindowManager()) {
+ if (QDesignerFormWindowInterface *fw = fwm->activeFormWindow())
+ if ( QDesignerObjectInspectorInterface *oi = m_core->objectInspector()) {
+ oi->setFormWindow(fw);
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_promotion_p.h b/tools/designer/src/lib/shared/qdesigner_promotion_p.h
new file mode 100644
index 0000000..6806b4c
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_promotion_p.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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNERPROMOTION_H
+#define QDESIGNERPROMOTION_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerPromotionInterface>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+ class QDESIGNER_SHARED_EXPORT QDesignerPromotion : public QDesignerPromotionInterface
+ {
+ public:
+ explicit QDesignerPromotion(QDesignerFormEditorInterface *core);
+
+ virtual PromotedClasses promotedClasses() const;
+
+ virtual QSet<QString> referencedPromotedClassNames() const;
+
+ virtual bool addPromotedClass(const QString &baseClass,
+ const QString &className,
+ const QString &includeFile,
+ QString *errorMessage);
+
+ virtual bool removePromotedClass(const QString &className, QString *errorMessage);
+
+ virtual bool changePromotedClassName(const QString &oldclassName, const QString &newClassName, QString *errorMessage);
+
+ virtual bool setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage);
+
+ virtual QList<QDesignerWidgetDataBaseItemInterface *> promotionBaseClasses() const;
+
+ private:
+ bool canBePromoted(const QDesignerWidgetDataBaseItemInterface *) const;
+ void refreshObjectInspector();
+
+ QDesignerFormEditorInterface *m_core;
+ };
+}
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNERPROMOTION_H
diff --git a/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp b/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp
new file mode 100644
index 0000000..8453c16
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** 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::QDesignerPromotionDialog
+*/
+
+#include "qdesigner_promotiondialog_p.h"
+#include "promotionmodel_p.h"
+#include "iconloader_p.h"
+#include "widgetdatabase_p.h"
+#include "signalslotdialog_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerPromotionInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseItemInterface>
+#include <abstractdialoggui_p.h>
+
+#include <QtCore/QTimer>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QTreeView>
+#include <QtGui/QHeaderView>
+#include <QtGui/QPushButton>
+#include <QtGui/QItemSelectionModel>
+#include <QtGui/QItemSelection>
+#include <QtGui/QComboBox>
+#include <QtGui/QLineEdit>
+#include <QtGui/QCheckBox>
+#include <QtGui/QRegExpValidator>
+#include <QtGui/QLabel>
+#include <QtGui/QSpacerItem>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+ // PromotionParameters
+ struct PromotionParameters {
+ QString m_baseClass;
+ QString m_className;
+ QString m_includeFile;
+ };
+
+ // NewPromotedClassPanel
+ NewPromotedClassPanel::NewPromotedClassPanel(const QStringList &baseClasses,
+ int selectedBaseClass,
+ QWidget *parent) :
+ QGroupBox(parent),
+ m_baseClassCombo(new QComboBox),
+ m_classNameEdit(new QLineEdit),
+ m_includeFileEdit(new QLineEdit),
+ m_globalIncludeCheckBox(new QCheckBox),
+ m_addButton(new QPushButton(tr("Add")))
+ {
+ setTitle(tr("New Promoted Class"));
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
+ QHBoxLayout *hboxLayout = new QHBoxLayout(this);
+
+ m_classNameEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("[_a-zA-Z:][:_a-zA-Z0-9]*")), m_classNameEdit));
+ connect(m_classNameEdit, SIGNAL(textChanged(QString)), this, SLOT(slotNameChanged(QString)));
+ connect(m_includeFileEdit, SIGNAL(textChanged(QString)), this, SLOT(slotIncludeFileChanged(QString)));
+
+ m_baseClassCombo->setEditable(false);
+ m_baseClassCombo->addItems(baseClasses);
+ if (selectedBaseClass != -1)
+ m_baseClassCombo->setCurrentIndex(selectedBaseClass);
+
+ // Grid
+ QFormLayout *formLayout = new QFormLayout();
+ formLayout->addRow(tr("Base class name:"), m_baseClassCombo);
+ formLayout->addRow(tr("Promoted class name:"), m_classNameEdit);
+ formLayout->addRow(tr("Header file:"), m_includeFileEdit);
+ formLayout->addRow(tr("Global include"), m_globalIncludeCheckBox);
+ hboxLayout->addLayout(formLayout);
+ hboxLayout->addItem(new QSpacerItem(15, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
+ // Button box
+ QVBoxLayout *buttonLayout = new QVBoxLayout();
+
+ m_addButton->setAutoDefault(false);
+ connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAdd()));
+ m_addButton->setEnabled(false);
+ buttonLayout->addWidget(m_addButton);
+
+ QPushButton *resetButton = new QPushButton(tr("Reset"));
+ resetButton->setAutoDefault(false);
+ connect(resetButton, SIGNAL(clicked()), this, SLOT(slotReset()));
+
+ buttonLayout->addWidget(resetButton);
+ buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding));
+ hboxLayout->addLayout(buttonLayout);
+
+ enableButtons();
+ }
+
+ void NewPromotedClassPanel::slotAdd() {
+ bool ok = false;
+ emit newPromotedClass(promotionParameters(), &ok);
+ if (ok)
+ slotReset();
+ }
+
+ void NewPromotedClassPanel::slotReset() {
+ const QString empty;
+ m_classNameEdit->setText(empty);
+ m_includeFileEdit->setText(empty);
+ m_globalIncludeCheckBox->setCheckState(Qt::Unchecked);
+ }
+
+ void NewPromotedClassPanel::grabFocus() {
+ m_classNameEdit->setFocus(Qt::OtherFocusReason);
+ }
+
+ void NewPromotedClassPanel::slotNameChanged(const QString &className) {
+ // Suggest a name
+ if (!className.isEmpty()) {
+ QString suggestedHeader = className.toLower().replace(QLatin1String("::"), QString(QLatin1Char('_')));
+ suggestedHeader += QLatin1String(".h");
+
+ const bool blocked = m_includeFileEdit->blockSignals(true);
+ m_includeFileEdit->setText(suggestedHeader);
+ m_includeFileEdit->blockSignals(blocked);
+ }
+ enableButtons();
+ }
+
+ void NewPromotedClassPanel::slotIncludeFileChanged(const QString &){
+ enableButtons();
+ }
+
+ void NewPromotedClassPanel::enableButtons() {
+ const bool enabled = !m_classNameEdit->text().isEmpty() && !m_includeFileEdit->text().isEmpty();
+ m_addButton->setEnabled(enabled);
+ m_addButton->setDefault(enabled);
+ }
+
+ PromotionParameters NewPromotedClassPanel::promotionParameters() const {
+ PromotionParameters rc;
+ rc.m_baseClass = m_baseClassCombo->currentText();
+ rc.m_className = m_classNameEdit->text();
+ rc.m_includeFile = buildIncludeFile(m_includeFileEdit->text(),
+ m_globalIncludeCheckBox->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal);
+ return rc;
+ }
+
+ void NewPromotedClassPanel::chooseBaseClass(const QString &baseClass) {
+ const int index = m_baseClassCombo->findText (baseClass);
+ if (index != -1)
+ m_baseClassCombo->setCurrentIndex (index);
+ }
+
+ // --------------- QDesignerPromotionDialog
+ QDesignerPromotionDialog::QDesignerPromotionDialog(QDesignerFormEditorInterface *core,
+ QWidget *parent,
+ const QString &promotableWidgetClassName,
+ QString *promoteTo) :
+ QDialog(parent),
+ m_mode(promotableWidgetClassName.isEmpty() || promoteTo == 0 ? ModeEdit : ModeEditChooseClass),
+ m_promotableWidgetClassName(promotableWidgetClassName),
+ m_core(core),
+ m_promoteTo(promoteTo),
+ m_promotion(core->promotion()),
+ m_model(new PromotionModel(core)),
+ m_treeView(new QTreeView),
+ m_buttonBox(0),
+ m_removeButton(new QPushButton(createIconSet(QString::fromUtf8("minus.png")), QString()))
+ {
+ m_buttonBox = createButtonBox();
+ setModal(true);
+ setWindowTitle(tr("Promoted Widgets"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+
+ // tree view group
+ QGroupBox *treeViewGroup = new QGroupBox();
+ treeViewGroup->setTitle(tr("Promoted Classes"));
+ QVBoxLayout *treeViewVBoxLayout = new QVBoxLayout(treeViewGroup);
+ // tree view
+ m_treeView->setModel (m_model);
+ m_treeView->setMinimumWidth(450);
+ m_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
+ this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
+
+ connect(m_treeView, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(slotTreeViewContextMenu(QPoint)));
+
+ QHeaderView *headerView = m_treeView->header();
+ headerView->setResizeMode(QHeaderView::ResizeToContents);
+ treeViewVBoxLayout->addWidget(m_treeView);
+ // remove button
+ QHBoxLayout *hboxLayout = new QHBoxLayout();
+ hboxLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
+
+ m_removeButton->setAutoDefault(false);
+ connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove()));
+ m_removeButton->setEnabled(false);
+ hboxLayout->addWidget(m_removeButton);
+ treeViewVBoxLayout->addLayout(hboxLayout);
+ vboxLayout->addWidget(treeViewGroup);
+ // Create new panel: Try to be smart and preselect a base class. Default to QFrame
+ const QStringList &baseClassNameList = baseClassNames(m_promotion);
+ int preselectedBaseClass = -1;
+ if (m_mode == ModeEditChooseClass) {
+ preselectedBaseClass = baseClassNameList.indexOf(m_promotableWidgetClassName);
+ }
+ if (preselectedBaseClass == -1)
+ preselectedBaseClass = baseClassNameList.indexOf(QLatin1String("QFrame"));
+
+ NewPromotedClassPanel *newPromotedClassPanel = new NewPromotedClassPanel(baseClassNameList, preselectedBaseClass);
+ connect(newPromotedClassPanel, SIGNAL(newPromotedClass(PromotionParameters, bool *)), this, SLOT(slotNewPromotedClass(PromotionParameters, bool *)));
+ connect(this, SIGNAL(selectedBaseClassChanged(QString)),
+ newPromotedClassPanel, SLOT(chooseBaseClass(QString)));
+ vboxLayout->addWidget(newPromotedClassPanel);
+ // button box
+ vboxLayout->addWidget(m_buttonBox);
+ // connect model
+ connect(m_model, SIGNAL(includeFileChanged(QDesignerWidgetDataBaseItemInterface*, QString)),
+ this, SLOT(slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface*, QString)));
+
+ connect(m_model, SIGNAL(classNameChanged(QDesignerWidgetDataBaseItemInterface*, QString)),
+ this, SLOT(slotClassNameChanged(QDesignerWidgetDataBaseItemInterface*, QString)));
+
+ // focus
+ if (m_mode == ModeEditChooseClass)
+ newPromotedClassPanel->grabFocus();
+
+ slotUpdateFromWidgetDatabase();
+ }
+
+ QDialogButtonBox *QDesignerPromotionDialog::createButtonBox() {
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Close);
+
+ connect(buttonBox , SIGNAL(accepted()), this, SLOT(slotAcceptPromoteTo()));
+ buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Promote"));
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+
+ connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
+ return buttonBox;
+ }
+
+ void QDesignerPromotionDialog::slotUpdateFromWidgetDatabase() {
+ m_model->updateFromWidgetDatabase();
+ m_treeView->expandAll();
+ m_removeButton->setEnabled(false);
+ }
+
+ void QDesignerPromotionDialog::delayedUpdateFromWidgetDatabase() {
+ QTimer::singleShot(0, this, SLOT(slotUpdateFromWidgetDatabase()));
+ }
+
+ const QStringList &QDesignerPromotionDialog::baseClassNames(const QDesignerPromotionInterface *promotion) {
+ typedef QList<QDesignerWidgetDataBaseItemInterface *> WidgetDataBaseItemList;
+ static QStringList rc;
+ if (rc.empty()) {
+ // Convert the item list into a string list.
+ const WidgetDataBaseItemList dbItems = promotion->promotionBaseClasses();
+ const WidgetDataBaseItemList::const_iterator cend = dbItems.constEnd();
+ for (WidgetDataBaseItemList::const_iterator it = dbItems.constBegin() ; it != cend; ++it) {
+ rc.push_back( (*it)->name());
+ }
+ }
+ return rc;
+ }
+
+ void QDesignerPromotionDialog::slotAcceptPromoteTo() {
+ Q_ASSERT(m_mode == ModeEditChooseClass);
+ unsigned flags;
+ // Ok pressed: Promote to selected class
+ if (QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags)) {
+ if (flags & CanPromote) {
+ *m_promoteTo = dbItem ->name();
+ accept();
+ }
+ }
+ }
+
+ void QDesignerPromotionDialog::slotRemove() {
+ unsigned flags;
+ QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
+ if (!dbItem || (flags & Referenced))
+ return;
+
+ QString errorMessage;
+ if (m_promotion->removePromotedClass(dbItem->name(), &errorMessage)) {
+ slotUpdateFromWidgetDatabase();
+ } else {
+ displayError(errorMessage);
+ }
+ }
+
+ void QDesignerPromotionDialog::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &) {
+ // Enable deleting non-referenced items
+ unsigned flags;
+ const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(selected, flags);
+ m_removeButton->setEnabled(dbItem && !(flags & Referenced));
+ // In choose mode, can we promote to the class?
+ if (m_mode == ModeEditChooseClass) {
+ const bool enablePromoted = flags & CanPromote;
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enablePromoted);
+ m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(enablePromoted);
+ }
+ // different base?
+ if (dbItem) {
+ const QString baseClass = dbItem->extends();
+ if (baseClass != m_lastSelectedBaseClass) {
+ m_lastSelectedBaseClass = baseClass;
+ emit selectedBaseClassChanged(m_lastSelectedBaseClass);
+ }
+ }
+ }
+
+ QDesignerWidgetDataBaseItemInterface *QDesignerPromotionDialog::databaseItemAt(const QItemSelection &selected, unsigned &flags) const {
+ flags = 0;
+ const QModelIndexList indexes = selected.indexes();
+ if (indexes.empty())
+ return 0;
+
+ bool referenced;
+ QDesignerWidgetDataBaseItemInterface *dbItem = m_model->databaseItemAt(indexes.front(), &referenced);
+
+ if (dbItem) {
+ if (referenced)
+ flags |= Referenced;
+ // In choose mode, can we promote to the class?
+ if (m_mode == ModeEditChooseClass && dbItem && dbItem->isPromoted() && dbItem->extends() == m_promotableWidgetClassName)
+ flags |= CanPromote;
+
+ }
+ return dbItem;
+ }
+
+ void QDesignerPromotionDialog::slotNewPromotedClass(const PromotionParameters &p, bool *ok) {
+ QString errorMessage;
+ *ok = m_promotion->addPromotedClass(p.m_baseClass, p.m_className, p.m_includeFile, &errorMessage);
+ if (*ok) {
+ // update and select
+ slotUpdateFromWidgetDatabase();
+ const QModelIndex newClassIndex = m_model->indexOfClass(p.m_className);
+ if (newClassIndex.isValid()) {
+ m_treeView->selectionModel()->select(newClassIndex, QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
+ }
+ } else {
+ displayError(errorMessage);
+ }
+ }
+
+ void QDesignerPromotionDialog::slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &includeFile) {
+ if (includeFile.isEmpty()) {
+ delayedUpdateFromWidgetDatabase();
+ return;
+ }
+
+ if (dbItem->includeFile() == includeFile)
+ return;
+
+ QString errorMessage;
+ if (!m_promotion->setPromotedClassIncludeFile(dbItem->name(), includeFile, &errorMessage)) {
+ displayError(errorMessage);
+ delayedUpdateFromWidgetDatabase();
+ }
+ }
+
+ void QDesignerPromotionDialog::slotClassNameChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &newName) {
+ if (newName.isEmpty()) {
+ delayedUpdateFromWidgetDatabase();
+ return;
+ }
+ const QString oldName = dbItem->name();
+ if (newName == oldName)
+ return;
+
+ QString errorMessage;
+ if (!m_promotion->changePromotedClassName(oldName , newName, &errorMessage)) {
+ displayError(errorMessage);
+ delayedUpdateFromWidgetDatabase();
+ }
+ }
+
+ void QDesignerPromotionDialog::slotTreeViewContextMenu(const QPoint &pos) {
+ unsigned flags;
+ const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
+ if (!dbItem)
+ return;
+
+ QMenu menu;
+ QAction *signalSlotAction = menu.addAction(tr("Change signals/slots..."));
+ connect(signalSlotAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots()));
+
+ menu.exec(m_treeView->viewport()->mapToGlobal(pos));
+ }
+
+ void QDesignerPromotionDialog::slotEditSignalsSlots() {
+ unsigned flags;
+ const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
+ if (!dbItem)
+ return;
+
+ SignalSlotDialog::editPromotedClass(m_core, dbItem->name(), this);
+ }
+
+ void QDesignerPromotionDialog::displayError(const QString &message) {
+ m_core->dialogGui()->message(this, QDesignerDialogGuiInterface::PromotionErrorMessage, QMessageBox::Warning,
+ tr("%1 - Error").arg(windowTitle()), message, QMessageBox::Close);
+ }
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_promotiondialog_p.h b/tools/designer/src/lib/shared/qdesigner_promotiondialog_p.h
new file mode 100644
index 0000000..d371df8
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_promotiondialog_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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 PROMOTIONEDITORDIALOG_H
+#define PROMOTIONEDITORDIALOG_H
+
+#include <QtGui/QDialog>
+#include <QtGui/QGroupBox>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+class QDesignerPromotionInterface;
+class QDesignerWidgetDataBaseItemInterface;
+
+class QTreeView;
+class QPushButton;
+class QItemSelection;
+class QDialogButtonBox;
+class QComboBox;
+class QLineEdit;
+class QCheckBox;
+
+namespace qdesigner_internal {
+ struct PromotionParameters;
+ class PromotionModel;
+
+
+ // Panel for adding a new promoted class. Separate class for code cleanliness.
+ class NewPromotedClassPanel : public QGroupBox {
+ Q_OBJECT
+ public:
+ NewPromotedClassPanel(const QStringList &baseClasses,
+ int selectedBaseClass = -1,
+ QWidget *parent = 0);
+
+ signals:
+ void newPromotedClass(const PromotionParameters &, bool *ok);
+
+ public slots:
+ void grabFocus();
+ void chooseBaseClass(const QString &);
+ private slots:
+ void slotNameChanged(const QString &);
+ void slotIncludeFileChanged(const QString &);
+ void slotAdd();
+ void slotReset();
+
+ private:
+ PromotionParameters promotionParameters() const;
+ void enableButtons();
+
+ QComboBox *m_baseClassCombo;
+ QLineEdit *m_classNameEdit;
+ QLineEdit *m_includeFileEdit;
+ QCheckBox *m_globalIncludeCheckBox;
+ QPushButton *m_addButton;
+ };
+
+ // Dialog for editing promoted classes.
+ class QDesignerPromotionDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ enum Mode { ModeEdit, ModeEditChooseClass };
+
+ QDesignerPromotionDialog(QDesignerFormEditorInterface *core,
+ QWidget *parent = 0,
+ const QString &promotableWidgetClassName = QString(),
+ QString *promoteTo = 0);
+ // Return an alphabetically ordered list of base class names for adding new classes.
+ static const QStringList &baseClassNames(const QDesignerPromotionInterface *promotion);
+
+ signals:
+ void selectedBaseClassChanged(const QString &);
+ private slots:
+ void slotRemove();
+ void slotAcceptPromoteTo();
+ void slotSelectionChanged(const QItemSelection &, const QItemSelection &);
+ void slotNewPromotedClass(const PromotionParameters &, bool *ok);
+
+ void slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface *, const QString &includeFile);
+ void slotClassNameChanged(QDesignerWidgetDataBaseItemInterface *, const QString &newName);
+ void slotUpdateFromWidgetDatabase();
+ void slotTreeViewContextMenu(const QPoint &);
+ void slotEditSignalsSlots();
+
+ private:
+ QDialogButtonBox *createButtonBox();
+ void delayedUpdateFromWidgetDatabase();
+ // Return item at model index and a combination of flags or 0.
+ enum { Referenced = 1, CanPromote = 2 };
+ QDesignerWidgetDataBaseItemInterface *databaseItemAt(const QItemSelection &, unsigned &flags) const;
+ void displayError(const QString &message);
+
+ const Mode m_mode;
+ const QString m_promotableWidgetClassName;
+ QDesignerFormEditorInterface *m_core;
+ QString *m_promoteTo;
+ QDesignerPromotionInterface *m_promotion;
+ PromotionModel *m_model;
+ QTreeView *m_treeView;
+ QDialogButtonBox *m_buttonBox;
+ QPushButton *m_removeButton;
+ QString m_lastSelectedBaseClass;
+ };
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // PROMOTIONEDITORDIALOG_H
diff --git a/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp b/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp
new file mode 100644
index 0000000..ff3b50b
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp
@@ -0,0 +1,1479 @@
+/****************************************************************************
+**
+** 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_propertycommand_p.h"
+#include "qdesigner_utils_p.h"
+#include "dynamicpropertysheet.h"
+#include "qdesigner_propertyeditor_p.h"
+#include "qdesigner_integration_p.h"
+#include "spacer_widget_p.h"
+#include "qdesigner_propertysheet_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtDesigner/QDesignerDynamicPropertySheetExtension>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QDesignerObjectInspectorInterface>
+#include <QtDesigner/QDesignerIntegrationInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QSize>
+#include <QtCore/QTextStream>
+#include <QtGui/QWidget>
+#include <QtGui/QApplication>
+#include <QtGui/QAction>
+#include <QtGui/QDialog>
+#include <QtGui/QPushButton>
+#include <QtGui/QLayout>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+enum { debugPropertyCommands = 0 };
+
+// Debug resolve mask of font
+QString fontMask(unsigned m)
+{
+ QString rc;
+ if (m & QFont::FamilyResolved)
+ rc += QLatin1String("Family");
+ if (m & QFont::SizeResolved)
+ rc += QLatin1String("Size ");
+ if (m & QFont::WeightResolved)
+ rc += QLatin1String("Bold ");
+ if (m & QFont::StyleResolved)
+ rc += QLatin1String("Style ");
+ if (m & QFont::UnderlineResolved)
+ rc += QLatin1String("Underline ");
+ if (m & QFont::StrikeOutResolved)
+ rc += QLatin1String("StrikeOut ");
+ if (m & QFont::KerningResolved)
+ rc += QLatin1String("Kerning ");
+ if (m & QFont::StyleStrategyResolved)
+ rc += QLatin1String("StyleStrategy");
+ return rc;
+}
+
+// Debug font
+QString fontString(const QFont &f)
+{
+ QString rc; {
+ const QChar comma = QLatin1Char(',');
+ QTextStream str(&rc);
+ str << QLatin1String("QFont(\"") << f.family() << comma <<
+ f.pointSize();
+ if (f.bold())
+ str << comma << QLatin1String("bold");
+ if (f.italic())
+ str << comma << QLatin1String("italic");
+ if (f.underline())
+ str << comma << QLatin1String("underline");
+ if (f.strikeOut())
+ str << comma << QLatin1String("strikeOut");
+ if (f.kerning())
+ str << comma << QLatin1String("kerning");
+ str << comma << f.styleStrategy() << QLatin1String(" resolve: ")
+ << fontMask(f.resolve()) << QLatin1Char(')');
+ }
+ return rc;
+}
+QSize checkSize(const QSize &size)
+{
+ return size.boundedTo(QSize(0xFFFFFF, 0xFFFFFF));
+}
+
+QSize diffSize(QDesignerFormWindowInterface *fw)
+{
+ const QWidget *container = fw->core()->integration()->containerWindow(fw);
+ if (!container)
+ return QSize();
+
+ const QSize diff = container->size() - fw->size(); // decoration offset of container window
+ return diff;
+}
+
+void checkSizes(QDesignerFormWindowInterface *fw, const QSize &size, QSize *formSize, QSize *containerSize)
+{
+ const QWidget *container = fw->core()->integration()->containerWindow(fw);
+ if (!container)
+ return;
+
+ const QSize diff = diffSize(fw); // decoration offset of container window
+
+ QSize newFormSize = checkSize(size).expandedTo(fw->mainContainer()->minimumSizeHint()); // don't try to resize to smaller size than minimumSizeHint
+ QSize newContainerSize = newFormSize + diff;
+
+ newContainerSize = newContainerSize.expandedTo(container->minimumSizeHint());
+ newContainerSize = newContainerSize.expandedTo(container->minimumSize());
+
+ newFormSize = newContainerSize - diff;
+
+ newContainerSize = checkSize(newContainerSize);
+
+ if (formSize)
+ *formSize = newFormSize;
+ if (containerSize)
+ *containerSize = newContainerSize;
+}
+
+/* SubProperties: When applying a changed property to a multiselection, it sometimes makes
+ * sense to apply only parts (subproperties) of the property.
+ * For example, if someone changes the x-value of a geometry in the property editor
+ * and applies it to a multi-selection, y should not be applied as this would cause all
+ * the widgets to overlap.
+ * The following routines can be used to find out the changed subproperties of a property,
+ * which are represented as a mask, and to apply them while leaving the others intact. */
+
+enum RectSubPropertyMask { SubPropertyX=1, SubPropertyY = 2, SubPropertyWidth = 4, SubPropertyHeight = 8 };
+enum SizePolicySubPropertyMask { SubPropertyHSizePolicy = 1, SubPropertyHStretch = 2, SubPropertyVSizePolicy = 4, SubPropertyVStretch = 8 };
+enum AlignmentSubPropertyMask { SubPropertyHorizontalAlignment = 1, SubPropertyVerticalAlignment = 2 };
+enum StringSubPropertyMask { SubPropertyStringValue = 1, SubPropertyStringComment = 2, SubPropertyStringTranslatable = 4, SubPropertyStringDisambiguation = 8 };
+enum KeySequenceSubPropertyMask { SubPropertyKeySequenceValue = 1, SubPropertyKeySequenceComment = 2, SubPropertyKeySequenceTranslatable = 4, SubPropertyKeySequenceDisambiguation = 8 };
+
+enum CommonSubPropertyMask { SubPropertyAll = 0xFFFFFFFF };
+
+// Set the mask flag in mask if the properties do not match.
+#define COMPARE_SUBPROPERTY(object1, object2, getter, mask, maskFlag) if (object1.getter() != object2.getter()) mask |= maskFlag;
+
+// find changed subproperties of a rectangle
+unsigned compareSubProperties(const QRect & r1, const QRect & r2)
+{
+ unsigned rc = 0;
+ COMPARE_SUBPROPERTY(r1, r2, x, rc, SubPropertyX)
+ COMPARE_SUBPROPERTY(r1, r2, y, rc, SubPropertyY)
+ COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth)
+ COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
+ return rc;
+}
+
+// find changed subproperties of a QSize
+unsigned compareSubProperties(const QSize & r1, const QSize & r2)
+{
+ unsigned rc = 0;
+ COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth)
+ COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight)
+ return rc;
+}
+// find changed subproperties of a QSizePolicy
+unsigned compareSubProperties(const QSizePolicy & sp1, const QSizePolicy & sp2)
+{
+ unsigned rc = 0;
+ COMPARE_SUBPROPERTY(sp1, sp2, horizontalPolicy, rc, SubPropertyHSizePolicy)
+ COMPARE_SUBPROPERTY(sp1, sp2, horizontalStretch, rc, SubPropertyHStretch)
+ COMPARE_SUBPROPERTY(sp1, sp2, verticalPolicy, rc, SubPropertyVSizePolicy)
+ COMPARE_SUBPROPERTY(sp1, sp2, verticalStretch, rc, SubPropertyVStretch)
+ return rc;
+}
+// find changed subproperties of qdesigner_internal::PropertySheetStringValue
+unsigned compareSubProperties(const qdesigner_internal::PropertySheetStringValue & str1, const qdesigner_internal::PropertySheetStringValue & str2)
+{
+ unsigned rc = 0;
+ COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyStringValue)
+ COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyStringComment)
+ COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyStringTranslatable)
+ COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyStringDisambiguation)
+ return rc;
+}
+// find changed subproperties of qdesigner_internal::PropertySheetKeySequenceValue
+unsigned compareSubProperties(const qdesigner_internal::PropertySheetKeySequenceValue & str1, const qdesigner_internal::PropertySheetKeySequenceValue & str2)
+{
+ unsigned rc = 0;
+ COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyKeySequenceValue)
+ COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyKeySequenceComment)
+ COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyKeySequenceTranslatable)
+ COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyKeySequenceDisambiguation)
+ return rc;
+}
+
+// Compare font-subproperties taking the [undocumented]
+// resolve flag into account
+template <class Property>
+void compareFontSubProperty(const QFont & f1,
+ const QFont & f2,
+ Property (QFont::*getter) () const,
+ unsigned maskBit,
+ unsigned &mask)
+{
+ const bool f1Changed = f1.resolve() & maskBit;
+ const bool f2Changed = f2.resolve() & maskBit;
+ // Role has been set/reset in editor
+ if (f1Changed != f2Changed) {
+ mask |= maskBit;
+ } else {
+ // Was modified in both palettes: Compare values.
+ if (f1Changed && f2Changed && (f1.*getter)() != (f2.*getter)())
+ mask |= maskBit;
+ }
+}
+// find changed subproperties of a QFont
+unsigned compareSubProperties(const QFont & f1, const QFont & f2)
+{
+ unsigned rc = 0;
+ compareFontSubProperty(f1, f2, &QFont::family, QFont::FamilyResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::pointSize, QFont::SizeResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::bold, QFont::WeightResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::italic, QFont::StyleResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::underline, QFont::UnderlineResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::strikeOut, QFont::StrikeOutResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::kerning, QFont::KerningResolved, rc);
+ compareFontSubProperty(f1, f2, &QFont::styleStrategy, QFont::StyleStrategyResolved, rc);
+ if (debugPropertyCommands)
+ qDebug() << "compareSubProperties " << fontString(f1) << fontString(f2) << "\n\treturns " << fontMask(rc);
+ return rc;
+}
+
+// Compare colors of a role
+bool roleColorChanged(const QPalette & p1, const QPalette & p2, QPalette::ColorRole role)
+{
+ for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) {
+ const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
+ if (p1.color(pgroup, role) != p2.color(pgroup, role))
+ return true;
+ }
+ return false;
+}
+// find changed subproperties of a QPalette taking the [undocumented] resolve flags into account
+unsigned compareSubProperties(const QPalette & p1, const QPalette & p2)
+{
+ unsigned rc = 0;
+ unsigned maskBit = 1u;
+ // generate a mask for each role
+ const unsigned p1Changed = p1.resolve();
+ const unsigned p2Changed = p2.resolve();
+ for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
+ const bool p1RoleChanged = p1Changed & maskBit;
+ const bool p2RoleChanged = p2Changed & maskBit;
+ // Role has been set/reset in editor
+ if (p1RoleChanged != p2RoleChanged) {
+ rc |= maskBit;
+ } else {
+ // Was modified in both palettes: Compare values.
+ if (p1RoleChanged && p2RoleChanged && roleColorChanged(p1, p2, static_cast<QPalette::ColorRole>(role)))
+ rc |= maskBit;
+ }
+ }
+ return rc;
+}
+
+// find changed subproperties of a QAlignment which is a flag combination of vertical and horizontal
+
+unsigned compareSubProperties(Qt::Alignment a1, Qt::Alignment a2)
+{
+ unsigned rc = 0;
+ if ((a1 & Qt::AlignHorizontal_Mask) != (a2 & Qt::AlignHorizontal_Mask))
+ rc |= SubPropertyHorizontalAlignment;
+ if ((a1 & Qt::AlignVertical_Mask) != (a2 & Qt::AlignVertical_Mask))
+ rc |= SubPropertyVerticalAlignment;
+ return rc;
+}
+
+Qt::Alignment variantToAlignment(const QVariant & q)
+{
+ return Qt::Alignment(qdesigner_internal::Utils::valueOf(q));
+}
+// find changed subproperties of a variant
+unsigned compareSubProperties(const QVariant & q1, const QVariant & q2, qdesigner_internal::SpecialProperty specialProperty)
+{
+ switch (q1.type()) {
+ case QVariant::Rect:
+ return compareSubProperties(q1.toRect(), q2.toRect());
+ case QVariant::Size:
+ return compareSubProperties(q1.toSize(), q2.toSize());
+ case QVariant::SizePolicy:
+ return compareSubProperties(qvariant_cast<QSizePolicy>(q1), qvariant_cast<QSizePolicy>(q2));
+ case QVariant::Font:
+ return compareSubProperties(qvariant_cast<QFont>(q1), qvariant_cast<QFont>(q2));
+ case QVariant::Palette:
+ return compareSubProperties(qvariant_cast<QPalette>(q1), qvariant_cast<QPalette>(q2));
+ default:
+ if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>())
+ return qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q1).compare(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(q2));
+ else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>())
+ return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetStringValue>(q2));
+ else if (q1.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>())
+ return compareSubProperties(qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q1), qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(q2));
+ // Enumerations, flags
+ switch (specialProperty) {
+ case qdesigner_internal::SP_Alignment:
+ return compareSubProperties(variantToAlignment(q1), variantToAlignment(q2));
+ default:
+ break;
+ }
+ break;
+ }
+ return SubPropertyAll;
+}
+
+// Apply the sub property if mask flag is set in mask
+#define SET_SUBPROPERTY(rc, newValue, getter, setter, mask, maskFlag) if (mask & maskFlag) rc.setter(newValue.getter());
+
+// apply changed subproperties to a rectangle
+QRect applyRectSubProperty(const QRect &oldValue, const QRect &newValue, unsigned mask)
+{
+ QRect rc = oldValue;
+ SET_SUBPROPERTY(rc, newValue, x, moveLeft, mask, SubPropertyX)
+ SET_SUBPROPERTY(rc, newValue, y, moveTop, mask, SubPropertyY)
+ SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth)
+ SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
+ return rc;
+}
+
+
+// apply changed subproperties to a rectangle QSize
+QSize applySizeSubProperty(const QSize &oldValue, const QSize &newValue, unsigned mask)
+{
+ QSize rc = oldValue;
+ SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth)
+ SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight)
+ return rc;
+}
+
+
+// apply changed subproperties to a SizePolicy
+QSizePolicy applySizePolicySubProperty(const QSizePolicy &oldValue, const QSizePolicy &newValue, unsigned mask)
+{
+ QSizePolicy rc = oldValue;
+ SET_SUBPROPERTY(rc, newValue, horizontalPolicy, setHorizontalPolicy, mask, SubPropertyHSizePolicy)
+ SET_SUBPROPERTY(rc, newValue, horizontalStretch, setHorizontalStretch, mask, SubPropertyHStretch)
+ SET_SUBPROPERTY(rc, newValue, verticalPolicy, setVerticalPolicy, mask, SubPropertyVSizePolicy)
+ SET_SUBPROPERTY(rc, newValue, verticalStretch, setVerticalStretch, mask, SubPropertyVStretch)
+ return rc;
+}
+
+// apply changed subproperties to a qdesigner_internal::PropertySheetStringValue
+qdesigner_internal::PropertySheetStringValue applyStringSubProperty(const qdesigner_internal::PropertySheetStringValue &oldValue,
+ const qdesigner_internal::PropertySheetStringValue &newValue, unsigned mask)
+{
+ qdesigner_internal::PropertySheetStringValue rc = oldValue;
+ SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyStringValue)
+ SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyStringComment)
+ SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyStringTranslatable)
+ SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyStringDisambiguation)
+ return rc;
+}
+
+// apply changed subproperties to a qdesigner_internal::PropertySheetKeySequenceValue
+qdesigner_internal::PropertySheetKeySequenceValue applyKeySequenceSubProperty(const qdesigner_internal::PropertySheetKeySequenceValue &oldValue,
+ const qdesigner_internal::PropertySheetKeySequenceValue &newValue, unsigned mask)
+{
+ qdesigner_internal::PropertySheetKeySequenceValue rc = oldValue;
+ SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyKeySequenceValue)
+ SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyKeySequenceComment)
+ SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyKeySequenceTranslatable)
+ SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyKeySequenceDisambiguation)
+ return rc;
+}
+
+// Apply the font-subproperties keeping the [undocumented]
+// resolve flag in sync (note that PropertySetterType might be something like const T&).
+template <class PropertyReturnType, class PropertySetterType>
+inline void setFontSubProperty(unsigned mask,
+ const QFont &newValue,
+ unsigned maskBit,
+ PropertyReturnType (QFont::*getter) () const,
+ void (QFont::*setter) (PropertySetterType),
+ QFont &value)
+{
+ if (mask & maskBit) {
+ (value.*setter)((newValue.*getter)());
+ // Set the resolve bit from NewValue in return value
+ uint r = value.resolve();
+ const bool origFlag = newValue.resolve() & maskBit;
+ if (origFlag)
+ r |= maskBit;
+ else
+ r &= ~maskBit;
+ value.resolve(r);
+ if (debugPropertyCommands)
+ qDebug() << "setFontSubProperty " << fontMask(maskBit) << " resolve=" << origFlag;
+ }
+}
+// apply changed subproperties to a QFont
+QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigned mask)
+{
+ QFont rc = oldValue;
+ setFontSubProperty(mask, newValue, QFont::FamilyResolved, &QFont::family, &QFont::setFamily, rc);
+ setFontSubProperty(mask, newValue, QFont::SizeResolved, &QFont::pointSize, &QFont::setPointSize, rc);
+ setFontSubProperty(mask, newValue, QFont::WeightResolved, &QFont::bold, &QFont::setBold, rc);
+ setFontSubProperty(mask, newValue, QFont::StyleResolved, &QFont::italic, &QFont::setItalic, rc);
+ setFontSubProperty(mask, newValue, QFont::UnderlineResolved, &QFont::underline, &QFont::setUnderline, rc);
+ setFontSubProperty(mask, newValue, QFont::StrikeOutResolved, &QFont::strikeOut, &QFont::setStrikeOut, rc);
+ setFontSubProperty(mask, newValue, QFont::KerningResolved, &QFont::kerning, &QFont::setKerning, rc);
+ setFontSubProperty(mask, newValue, QFont::StyleStrategyResolved, &QFont::styleStrategy, &QFont::setStyleStrategy, rc);
+ if (debugPropertyCommands)
+ qDebug() << "applyFontSubProperty old " << fontMask(oldValue.resolve()) << " new " << fontMask(newValue.resolve()) << " return: " << fontMask(rc.resolve());
+ return rc;
+}
+
+// apply changed subproperties to a QPalette
+QPalette applyPaletteSubProperty(const QPalette &oldValue, const QPalette &newValue, unsigned mask)
+{
+ QPalette rc = oldValue;
+ // apply a mask for each role
+ unsigned maskBit = 1u;
+ for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) {
+ if (mask & maskBit) {
+ for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) {
+ const QPalette::ColorGroup pgroup = static_cast<QPalette::ColorGroup>(group);
+ const QPalette::ColorRole prole = static_cast<QPalette::ColorRole>(role);
+ rc.setColor(pgroup, prole, newValue.color(pgroup, prole));
+ }
+ // Set the resolve bit from NewValue in return value
+ uint r = rc.resolve();
+ const bool origFlag = newValue.resolve() & maskBit;
+ if (origFlag)
+ r |= maskBit;
+ else
+ r &= ~maskBit;
+ rc.resolve(r);
+ }
+ }
+ return rc;
+}
+
+// apply changed subproperties to a QAlignment which is a flag combination of vertical and horizontal
+Qt::Alignment applyAlignmentSubProperty(Qt::Alignment oldValue, Qt::Alignment newValue, unsigned mask)
+{
+ // easy: both changed.
+ if (mask == (SubPropertyHorizontalAlignment|SubPropertyVerticalAlignment))
+ return newValue;
+ // Change subprop
+ const Qt::Alignment changeMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask;
+ const Qt::Alignment takeOverMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignVertical_Mask : Qt::AlignHorizontal_Mask;
+ return (oldValue & takeOverMask) | (newValue & changeMask);
+}
+
+}
+
+namespace qdesigner_internal {
+
+// apply changed subproperties to a variant
+PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant &newValue, qdesigner_internal::SpecialProperty specialProperty, unsigned mask, bool changed)
+{
+ if (mask == SubPropertyAll)
+ return PropertyHelper::Value(newValue, changed);
+
+ switch (oldValue.type()) {
+ case QVariant::Rect:
+ return PropertyHelper::Value(applyRectSubProperty(oldValue.toRect(), newValue.toRect(), mask), changed);
+ case QVariant::Size:
+ return PropertyHelper::Value(applySizeSubProperty(oldValue.toSize(), newValue.toSize(), mask), changed);
+ case QVariant::SizePolicy:
+ return PropertyHelper::Value(qVariantFromValue(applySizePolicySubProperty(qvariant_cast<QSizePolicy>(oldValue), qvariant_cast<QSizePolicy>(newValue), mask)), changed);
+ case QVariant::Font: {
+ // Changed flag in case of font and palette depends on resolve mask only, not on the passed "changed" value.
+
+ // The first case: the user changed bold subproperty and then pressed reset button for this subproperty (not for
+ // the whole font property). We instantiate SetPropertyCommand passing changed=true. But in this case no
+ // subproperty is changed and the whole property should be marked an unchanged.
+
+ // The second case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
+ // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
+ // He press reset next to bold subproperty. In result the 2nd widget should have the whole
+ // font property marked as unchanged and the 1st widget should have the font property
+ // marked as changed and only italic subproperty should be marked as changed (the bold should be reset).
+
+ // The third case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties,
+ // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one.
+ // He press reset button for the whole font property. In result whole font properties for both
+ // widgets should be marked as unchanged.
+ QFont font = applyFontSubProperty(qvariant_cast<QFont>(oldValue), qvariant_cast<QFont>(newValue), mask);
+ return PropertyHelper::Value(qVariantFromValue(font), font.resolve());
+ }
+ case QVariant::Palette: {
+ QPalette palette = applyPaletteSubProperty(qvariant_cast<QPalette>(oldValue), qvariant_cast<QPalette>(newValue), mask);
+ return PropertyHelper::Value(qVariantFromValue(palette), palette.resolve());
+ }
+ default:
+ if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetIconValue>()) {
+ PropertySheetIconValue icon = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(oldValue);
+ icon.assign(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(newValue), mask);
+ return PropertyHelper::Value(qVariantFromValue(icon), icon.mask());
+ } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetStringValue>()) {
+ qdesigner_internal::PropertySheetStringValue str = applyStringSubProperty(
+ qvariant_cast<qdesigner_internal::PropertySheetStringValue>(oldValue),
+ qvariant_cast<qdesigner_internal::PropertySheetStringValue>(newValue), mask);
+ return PropertyHelper::Value(qVariantFromValue(str), changed);
+ } else if (oldValue.userType() == qMetaTypeId<qdesigner_internal::PropertySheetKeySequenceValue>()) {
+ qdesigner_internal::PropertySheetKeySequenceValue key = applyKeySequenceSubProperty(
+ qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(oldValue),
+ qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(newValue), mask);
+ return PropertyHelper::Value(qVariantFromValue(key), changed);
+ }
+ // Enumerations, flags
+ switch (specialProperty) {
+ case qdesigner_internal::SP_Alignment: {
+ qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(oldValue);
+ f.value = applyAlignmentSubProperty(variantToAlignment(oldValue), variantToAlignment(newValue), mask);
+ QVariant v;
+ qVariantSetValue(v, f);
+ return PropertyHelper::Value(v, changed);
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ return PropertyHelper::Value(newValue, changed);
+
+}
+// figure out special property
+enum SpecialProperty getSpecialProperty(const QString& propertyName)
+{
+ if (propertyName == QLatin1String("objectName"))
+ return SP_ObjectName;
+ if (propertyName == QLatin1String("layoutName"))
+ return SP_LayoutName;
+ if (propertyName == QLatin1String("spacerName"))
+ return SP_SpacerName;
+ if (propertyName == QLatin1String("icon"))
+ return SP_Icon;
+ if (propertyName == QLatin1String("currentTabName"))
+ return SP_CurrentTabName;
+ if (propertyName == QLatin1String("currentItemName"))
+ return SP_CurrentItemName;
+ if (propertyName == QLatin1String("currentPageName"))
+ return SP_CurrentPageName;
+ if (propertyName == QLatin1String("geometry"))
+ return SP_Geometry;
+ if (propertyName == QLatin1String("windowTitle"))
+ return SP_WindowTitle;
+ if (propertyName == QLatin1String("minimumSize"))
+ return SP_MinimumSize;
+ if (propertyName == QLatin1String("maximumSize"))
+ return SP_MaximumSize;
+ if (propertyName == QLatin1String("alignment"))
+ return SP_Alignment;
+ if (propertyName == QLatin1String("autoDefault"))
+ return SP_AutoDefault;
+ if (propertyName == QLatin1String("shortcut"))
+ return SP_Shortcut;
+ if (propertyName == QLatin1String("orientation"))
+ return SP_Orientation;
+ return SP_None;
+}
+
+
+PropertyHelper::PropertyHelper(QObject* object,
+ SpecialProperty specialProperty,
+ QDesignerPropertySheetExtension *sheet,
+ int index) :
+ m_specialProperty(specialProperty),
+ m_object(object),
+ m_objectType(OT_Object),
+ m_propertySheet(sheet), m_index(index),
+ m_oldValue(m_propertySheet->property(m_index), m_propertySheet->isChanged(m_index))
+{
+ if (object->isWidgetType()) {
+ m_parentWidget = (qobject_cast<QWidget*>(object))->parentWidget();
+ m_objectType = OT_Widget;
+ } else {
+ if (const QAction *action = qobject_cast<const QAction *>(m_object))
+ m_objectType = action->associatedWidgets().empty() ? OT_FreeAction : OT_AssociatedAction;
+ }
+
+ if(debugPropertyCommands)
+ qDebug() << "PropertyHelper on " << m_object->objectName() << " index= " << m_index << " type = " << m_objectType;
+}
+
+QDesignerIntegration *PropertyHelper::integration(QDesignerFormWindowInterface *fw) const
+{
+ return qobject_cast<QDesignerIntegration *>(fw->core()->integration());
+}
+
+// Set widget value, apply corrections and checks in case of main window.
+void PropertyHelper::checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w,
+ SpecialProperty specialProperty, QVariant &value)
+{
+
+ bool isMainContainer = false;
+ if (QDesignerFormWindowCursorInterface *cursor = fw->cursor()) {
+ if (cursor->isWidgetSelected(w)) {
+ if (cursor->isWidgetSelected(fw->mainContainer())) {
+ isMainContainer = true;
+ }
+ }
+ }
+ if (!isMainContainer)
+ return;
+
+ QWidget *container = fw->core()->integration()->containerWindow(fw);
+ if (!container)
+ return;
+
+
+ switch (specialProperty) {
+ case SP_MinimumSize: {
+ const QSize size = checkSize(value.toSize());
+ qVariantSetValue(value, size);
+ }
+
+ break;
+ case SP_MaximumSize: {
+ QSize fs, cs;
+ checkSizes(fw, value.toSize(), &fs, &cs);
+ container->setMaximumSize(cs);
+ fw->mainContainer()->setMaximumSize(fs);
+ qVariantSetValue(value, fs);
+
+ }
+ break;
+ case SP_Geometry: {
+ QRect r = value.toRect();
+ QSize fs, cs;
+ checkSizes(fw, r.size(), &fs, &cs);
+ container->resize(cs);
+ r.setSize(fs);
+ qVariantSetValue(value, r);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+unsigned PropertyHelper::updateMask() const
+{
+ unsigned rc = 0;
+ switch (m_specialProperty) {
+ case SP_ObjectName:
+ case SP_LayoutName:
+ case SP_SpacerName:
+ case SP_CurrentTabName:
+ case SP_CurrentItemName:
+ case SP_CurrentPageName:
+ if (m_objectType != OT_FreeAction)
+ rc |= UpdateObjectInspector;
+ break;
+ case SP_Icon:
+ if (m_objectType == OT_AssociatedAction)
+ rc |= UpdateObjectInspector;
+ break;
+ case SP_Orientation: // for updating splitter icon
+ rc |= UpdateObjectInspector;
+ break;
+ default:
+ break;
+
+ }
+ return rc;
+}
+
+
+bool PropertyHelper::canMerge(const PropertyHelper &other) const
+{
+ return m_object == other.m_object && m_index == other.m_index;
+}
+
+void PropertyHelper::triggerActionChanged(QAction *a)
+{
+ a->setData(QVariant(true)); // this triggers signal "changed" in QAction
+ a->setData(QVariant(false));
+}
+
+// Update the object to reflect the changes
+void PropertyHelper::updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue)
+{
+ if(debugPropertyCommands){
+ qDebug() << "PropertyHelper::updateObject(" << m_object->objectName() << ") " << oldValue << " -> " << newValue;
+ }
+ switch (m_objectType) {
+ case OT_Widget: {
+ switch (m_specialProperty) {
+ case SP_ObjectName: {
+ const QString oldName = qVariantValue<PropertySheetStringValue>(oldValue).value();
+ const QString newName = qVariantValue<PropertySheetStringValue>(newValue).value();
+ QDesignerFormWindowCommand::updateBuddies(fw, oldName, newName);
+ }
+ break;
+ default:
+ break;
+ }
+ } break;
+ case OT_AssociatedAction:
+ case OT_FreeAction:
+ // SP_Shortcut is a fake property, so, QAction::changed does not trigger.
+ if (m_specialProperty == SP_ObjectName || m_specialProperty == SP_Shortcut)
+ triggerActionChanged(qobject_cast<QAction *>(m_object));
+ break;
+ default:
+ break;
+ }
+
+ switch (m_specialProperty) {
+ case SP_ObjectName:
+ case SP_LayoutName:
+ case SP_SpacerName:
+ if (QDesignerIntegration *integr = integration(fw)) {
+ const QString oldName = qVariantValue<PropertySheetStringValue>(oldValue).value();
+ const QString newName = qVariantValue<PropertySheetStringValue>(newValue).value();
+ integr->emitObjectNameChanged(fw, m_object, newName, oldName);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void PropertyHelper::ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const
+{
+ switch (m_specialProperty) {
+ case SP_SpacerName:
+ if (object->isWidgetType()) {
+ if (Spacer *sp = qobject_cast<Spacer *>(object)) {
+ fw->ensureUniqueObjectName(sp);
+ return;
+ }
+ }
+ fw->ensureUniqueObjectName(object);
+ break;
+ case SP_LayoutName: // Layout name is invoked on the parent widget.
+ if (object->isWidgetType()) {
+ const QWidget * w = qobject_cast<const QWidget *>(object);
+ if (QLayout *wlayout = w->layout()) {
+ fw->ensureUniqueObjectName(wlayout);
+ return;
+ }
+ }
+ fw->ensureUniqueObjectName(object);
+ break;
+ case SP_ObjectName:
+ fw->ensureUniqueObjectName(object);
+ break;
+ default:
+ break;
+ }
+}
+
+PropertyHelper::Value PropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask)
+{
+ // Set new whole value
+ if (subPropertyMask == SubPropertyAll)
+ return applyValue(fw, m_oldValue.first, Value(value, changed));
+
+ // apply subproperties
+ const PropertyHelper::Value maskedNewValue = applySubProperty(m_oldValue.first, value, m_specialProperty, subPropertyMask, changed);
+ return applyValue(fw, m_oldValue.first, maskedNewValue);
+}
+
+// Apply the value and update. Returns corrected value
+PropertyHelper::Value PropertyHelper::applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue)
+{
+ if(debugPropertyCommands){
+ qDebug() << "PropertyHelper::applyValue(" << m_object << ") " << oldValue << " -> " << newValue.first << " changed=" << newValue.second;
+ }
+
+ if (m_objectType == OT_Widget) {
+ checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, newValue.first);
+ }
+
+ m_propertySheet->setProperty(m_index, newValue.first);
+ m_propertySheet->setChanged(m_index, newValue.second);
+
+ switch (m_specialProperty) {
+ case SP_LayoutName:
+ case SP_ObjectName:
+ case SP_SpacerName:
+ ensureUniqueObjectName(fw, m_object);
+ newValue.first = m_propertySheet->property(m_index);
+ break;
+ default:
+ break;
+ }
+
+ updateObject(fw, oldValue, newValue.first);
+ return newValue;
+}
+
+PropertyHelper::Value PropertyHelper::restoreOldValue(QDesignerFormWindowInterface *fw)
+{
+ return applyValue(fw, m_propertySheet->property(m_index), m_oldValue);
+}
+
+// find the default value in widget DB in case PropertySheet::reset fails
+QVariant PropertyHelper::findDefaultValue(QDesignerFormWindowInterface *fw) const
+{
+ if (m_specialProperty == SP_AutoDefault && qobject_cast<const QPushButton*>(m_object)) {
+ // AutoDefault defaults to true on dialogs
+ const bool isDialog = qobject_cast<const QDialog *>(fw->mainContainer());
+ return QVariant(isDialog);
+ }
+
+ const int item_idx = fw->core()->widgetDataBase()->indexOfObject(m_object);
+ if (item_idx == -1)
+ return m_oldValue.first; // We simply don't know the value in this case
+
+ const QDesignerWidgetDataBaseItemInterface *item = fw->core()->widgetDataBase()->item(item_idx);
+ const QList<QVariant> default_prop_values = item->defaultPropertyValues();
+ if (m_index < default_prop_values.size())
+ return default_prop_values.at(m_index);
+
+ if (m_oldValue.first.type() == QVariant::Color)
+ return QColor();
+
+ return m_oldValue.first; // Again, we just don't know
+}
+
+PropertyHelper::Value PropertyHelper::restoreDefaultValue(QDesignerFormWindowInterface *fw)
+{
+
+ Value defaultValue = qMakePair(QVariant(), false);
+ const QVariant currentValue = m_propertySheet->property(m_index);
+ // try to reset sheet, else try to find default
+ if (m_propertySheet->reset(m_index)) {
+ defaultValue.first = m_propertySheet->property(m_index);
+ } else {
+ defaultValue.first = findDefaultValue(fw);
+ m_propertySheet->setProperty(m_index, defaultValue.first);
+ }
+
+ m_propertySheet->setChanged(m_index, defaultValue.second);
+
+ if (m_objectType == OT_Widget) {
+ checkApplyWidgetValue(fw, qobject_cast<QWidget *>(m_object), m_specialProperty, defaultValue.first);
+ }
+
+ switch (m_specialProperty) {
+ case SP_LayoutName:
+ case SP_ObjectName:
+ case SP_SpacerName:
+ ensureUniqueObjectName(fw, m_object);
+ defaultValue.first = m_propertySheet->property(m_index);
+ break;
+ default:
+ break;
+ }
+
+ updateObject(fw, currentValue, defaultValue.first);
+ return defaultValue;
+}
+
+// ---- PropertyListCommand::PropertyDescription(
+
+
+PropertyListCommand::PropertyDescription::PropertyDescription(const QString &propertyName,
+ QDesignerPropertySheetExtension *propertySheet,
+ int index) :
+ m_propertyName(propertyName),
+ m_propertyGroup(propertySheet->propertyGroup(index)),
+ m_propertyType(propertySheet->property(index).type()),
+ m_specialProperty(getSpecialProperty(propertyName))
+{
+}
+
+PropertyListCommand::PropertyDescription::PropertyDescription() :
+ m_propertyType(QVariant::Invalid),
+ m_specialProperty(SP_None)
+{
+}
+
+void PropertyListCommand::PropertyDescription::debug() const
+{
+ qDebug() << m_propertyName << m_propertyGroup << m_propertyType << m_specialProperty;
+}
+
+bool PropertyListCommand::PropertyDescription::equals(const PropertyDescription &p) const
+{
+ return m_propertyType == p.m_propertyType && m_specialProperty == p.m_specialProperty &&
+ m_propertyName == p.m_propertyName && m_propertyGroup == p.m_propertyGroup;
+}
+
+
+// ---- PropertyListCommand
+PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QString(), formWindow)
+{
+}
+
+const QString PropertyListCommand::propertyName() const
+{
+ return m_propertyDescription.m_propertyName;
+}
+
+SpecialProperty PropertyListCommand::specialProperty() const
+{
+ return m_propertyDescription.m_specialProperty;
+}
+
+// add an object
+bool PropertyListCommand::add(QObject *object, const QString &propertyName)
+{
+ QDesignerPropertySheetExtension* sheet = propertySheet(object);
+ Q_ASSERT(sheet);
+
+ const int index = sheet->indexOf(propertyName);
+ if (index == -1)
+ return false;
+
+ if (QDesignerPropertySheet *exSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))))
+ if (!exSheet->isEnabled(index))
+ return false;
+
+ const PropertyDescription description(propertyName, sheet, index);
+
+ if (m_propertyHelperList.empty()) {
+ // first entry
+ m_propertyDescription = description;
+ } else {
+ // checks: mismatch or only one object in case of name
+ const bool match = m_propertyDescription.equals(description);
+ if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName)
+ return false;
+ }
+ m_propertyHelperList.push_back(PropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index));
+ return true;
+}
+
+
+// Init from a list and make sure referenceObject is added first to obtain the right property group
+bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
+{
+ propertyHelperList().clear();
+
+ // Ensure the referenceObject (property editor) is first, so the right property group is chosen.
+ if (referenceObject) {
+ if (!add(referenceObject, apropertyName))
+ return false;
+ }
+ foreach (QObject *o, list) {
+ if (o != referenceObject)
+ add(o, apropertyName);
+ }
+
+ return !propertyHelperList().empty();
+}
+
+
+QObject* PropertyListCommand::object(int index) const
+{
+ Q_ASSERT(index < m_propertyHelperList.size());
+ return m_propertyHelperList[index].object();
+}
+
+QVariant PropertyListCommand::oldValue(int index) const
+{
+ Q_ASSERT(index < m_propertyHelperList.size());
+ return m_propertyHelperList[index].oldValue();
+}
+
+void PropertyListCommand::setOldValue(const QVariant &oldValue, int index)
+{
+ Q_ASSERT(index < m_propertyHelperList.size());
+ m_propertyHelperList[index].setOldValue(oldValue);
+}
+// ----- SetValueFunction: Set a new value when applied to a PropertyHelper.
+class SetValueFunction {
+public:
+ SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask);
+
+ PropertyHelper::Value operator()(PropertyHelper&);
+private:
+ QDesignerFormWindowInterface *m_formWindow;
+ const PropertyHelper::Value m_newValue;
+ const unsigned m_subPropertyMask;
+};
+
+
+SetValueFunction::SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask) :
+ m_formWindow(formWindow),
+ m_newValue(newValue),
+ m_subPropertyMask(subPropertyMask)
+{
+}
+
+PropertyHelper::Value SetValueFunction::operator()(PropertyHelper &ph) {
+ return ph.setValue(m_formWindow, m_newValue.first, m_newValue.second, m_subPropertyMask);
+}
+
+// ----- UndoSetValueFunction: Restore old value when applied to a PropertyHelper.
+class UndoSetValueFunction {
+public:
+ UndoSetValueFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
+ PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreOldValue(m_formWindow); }
+private:
+ QDesignerFormWindowInterface *m_formWindow;
+};
+
+// ----- RestoreDefaultFunction: Restore default value when applied to a PropertyHelper.
+class RestoreDefaultFunction {
+public:
+ RestoreDefaultFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {}
+ PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreDefaultValue(m_formWindow); }
+private:
+ QDesignerFormWindowInterface *m_formWindow;
+};
+
+// ----- changePropertyList: Iterates over a sequence of PropertyHelpers and
+// applies a function to them.
+// The function returns the corrected value which is then set in the property editor.
+// Returns a combination of update flags.
+template <class PropertyListIterator, class Function>
+ unsigned changePropertyList(QDesignerFormEditorInterface *core,
+ const QString &propertyName,
+ PropertyListIterator begin,
+ PropertyListIterator end,
+ Function function)
+{
+ unsigned updateMask = 0;
+ QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor();
+ bool updatedPropertyEditor = false;
+
+ for (PropertyListIterator it = begin; it != end; ++it) {
+ if (QObject* object = it->object()) { // Might have been deleted in the meantime
+ const PropertyHelper::Value newValue = function(*it);
+ updateMask |= it->updateMask();
+ // Update property editor if it is the current object
+ if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) {
+ propertyEditor->setPropertyValue(propertyName, newValue.first, newValue.second);
+ updatedPropertyEditor = true;
+ }
+ }
+ }
+ if (!updatedPropertyEditor) updateMask |= PropertyHelper::UpdatePropertyEditor;
+ return updateMask;
+}
+
+
+// set a new value, return update mask
+unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask)
+{
+ if(debugPropertyCommands)
+ qDebug() << "PropertyListCommand::setValue(" << value << changed << subPropertyMask << ')';
+ return changePropertyList(formWindow()->core(),
+ m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
+ SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask));
+}
+
+// restore old value, return update mask
+unsigned PropertyListCommand::restoreOldValue()
+{
+ if(debugPropertyCommands)
+ qDebug() << "PropertyListCommand::restoreOldValue()";
+
+ return changePropertyList(formWindow()->core(),
+ m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
+ UndoSetValueFunction(formWindow()));
+}
+// set default value, return update mask
+unsigned PropertyListCommand::restoreDefaultValue()
+{
+ if(debugPropertyCommands)
+ qDebug() << "PropertyListCommand::restoreDefaultValue()";
+
+ return changePropertyList(formWindow()->core(),
+ m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(),
+ RestoreDefaultFunction(formWindow()));
+}
+
+// update
+void PropertyListCommand::update(unsigned updateMask)
+{
+ if(debugPropertyCommands)
+ qDebug() << "PropertyListCommand::update(" << updateMask << ')';
+
+ if (updateMask & PropertyHelper::UpdateObjectInspector) {
+ if (QDesignerObjectInspectorInterface *oi = formWindow()->core()->objectInspector())
+ oi->setFormWindow(formWindow());
+ }
+
+ if (updateMask & PropertyHelper::UpdatePropertyEditor) {
+ // this is needed when f.ex. undo, changes parent's palette, but
+ // the child is the active widget,
+ // TODO: current object?
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ propertyEditor->setObject(propertyEditor->object());
+ }
+ }
+}
+
+void PropertyListCommand::undo()
+{
+ update(restoreOldValue());
+ QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
+ if (designerPropertyEditor)
+ designerPropertyEditor->updatePropertySheet();
+}
+
+// check if lists are aequivalent for command merging (same widgets and props)
+bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const
+{
+ if (m_propertyHelperList.size() != other.size())
+ return false;
+ for (int i = 0; i < m_propertyHelperList.size(); i++) {
+ if (!m_propertyHelperList[i].canMerge(other[i]))
+ return false;
+ }
+ return true;
+}
+
+// ---- SetPropertyCommand ----
+SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow)
+ : PropertyListCommand(formWindow),
+ m_subPropertyMask(SubPropertyAll)
+{
+}
+
+bool SetPropertyCommand::init(QObject *object, const QString &apropertyName, const QVariant &newValue)
+{
+ Q_ASSERT(object);
+
+ m_newValue = newValue;
+
+ propertyHelperList().clear();
+ if (!add(object, apropertyName))
+ return false;
+
+ setDescription();
+ return true;
+}
+
+bool SetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, const QVariant &newValue,
+ QObject *referenceObject, bool enableSubPropertyHandling)
+{
+ if (!initList(list, apropertyName, referenceObject))
+ return false;
+
+ m_newValue = newValue;
+
+ if(debugPropertyCommands)
+ qDebug() << "SetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size() << " reference " << referenceObject;
+
+ setDescription();
+
+ if (enableSubPropertyHandling)
+ m_subPropertyMask = subPropertyMask(newValue, referenceObject);
+ return true;
+}
+
+unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject *referenceObject)
+{
+ // figure out the mask of changed sub properties when comparing newValue to the current value of the reference object.
+ if (!referenceObject)
+ return SubPropertyAll;
+
+ QDesignerPropertySheetExtension* sheet = propertySheet(referenceObject);
+ Q_ASSERT(sheet);
+
+ const int index = sheet->indexOf(propertyName());
+ if (index == -1 || !sheet->isVisible(index))
+ return SubPropertyAll;
+
+ return compareSubProperties(sheet->property(index), newValue, specialProperty());
+}
+
+void SetPropertyCommand::setDescription()
+{
+ if (propertyHelperList().size() == 1) {
+ setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
+ } else {
+ int count = propertyHelperList().size();
+ setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
+ }
+}
+
+void SetPropertyCommand::redo()
+{
+ update(setValue(m_newValue, true, m_subPropertyMask));
+ QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
+ if (designerPropertyEditor)
+ designerPropertyEditor->updatePropertySheet();
+}
+
+
+int SetPropertyCommand::id() const
+{
+ return 1976;
+}
+
+bool SetPropertyCommand::mergeWith(const QUndoCommand *other)
+{
+ if (id() != other->id() || !formWindow()->isDirty())
+ return false;
+
+ // Merging: When for example when the user types ahead in an inplace-editor,
+ // it makes sense to merge all the generated commands containing the one-character changes.
+ // In the case of subproperties, if the user changes the font size from 10 to 30 via 20
+ // and then changes to bold, it makes sense to merge the font size commands only.
+ // This is why the m_subPropertyMask is checked.
+
+ const SetPropertyCommand *cmd = static_cast<const SetPropertyCommand*>(other);
+ if (!propertyDescription().equals(cmd->propertyDescription()) ||
+ m_subPropertyMask != cmd->m_subPropertyMask ||
+ !canMergeLists(cmd->propertyHelperList()))
+ return false;
+
+ m_newValue = cmd->newValue();
+ m_subPropertyMask |= cmd->m_subPropertyMask;
+ if(debugPropertyCommands)
+ qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName();
+
+ return true;
+}
+
+// ---- ResetPropertyCommand ----
+ResetPropertyCommand::ResetPropertyCommand(QDesignerFormWindowInterface *formWindow)
+ : PropertyListCommand(formWindow)
+{
+}
+
+bool ResetPropertyCommand::init(QObject *object, const QString &apropertyName)
+{
+ Q_ASSERT(object);
+
+ propertyHelperList().clear();
+ if (!add(object, apropertyName))
+ return false;
+
+ setDescription();
+ return true;
+}
+
+bool ResetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, QObject *referenceObject)
+{
+ if (!initList(list, apropertyName, referenceObject))
+ return false;
+
+ if(debugPropertyCommands)
+ qDebug() << "ResetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size();
+
+ setDescription();
+ return true;
+}
+
+void ResetPropertyCommand::setDescription()
+{
+ if (propertyHelperList().size() == 1) {
+ setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName()));
+ } else {
+ int count = propertyHelperList().size();
+ setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName()));
+ }
+}
+
+void ResetPropertyCommand::redo()
+{
+ update(restoreDefaultValue());
+ QDesignerPropertyEditor *designerPropertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor());
+ if (designerPropertyEditor)
+ designerPropertyEditor->updatePropertySheet();
+}
+
+AddDynamicPropertyCommand::AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow)
+{
+
+}
+
+bool AddDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
+ const QString &propertyName, const QVariant &value)
+{
+ Q_ASSERT(current);
+ m_propertyName = propertyName;
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
+ Q_ASSERT(dynamicSheet);
+
+ m_selection.clear();
+
+ if (!value.isValid())
+ return false;
+
+ if (!dynamicSheet->canAddDynamicProperty(m_propertyName))
+ return false;
+
+ m_selection.append(current);
+
+ m_value = value;
+
+ QListIterator<QObject *> it(selection);
+ while (it.hasNext()) {
+ QObject *obj = it.next();
+ if (m_selection.contains(obj))
+ continue;
+ dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ Q_ASSERT(dynamicSheet);
+ if (dynamicSheet->canAddDynamicProperty(m_propertyName))
+ m_selection.append(obj);
+ }
+
+ setDescription();
+ return true;
+}
+
+void AddDynamicPropertyCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QListIterator<QObject *> it(m_selection);
+ while (it.hasNext()) {
+ QObject *obj = it.next();
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ dynamicSheet->addDynamicProperty(m_propertyName, m_value);
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ if (propertyEditor->object() == obj)
+ propertyEditor->setObject(obj);
+ }
+ }
+}
+
+void AddDynamicPropertyCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QListIterator<QObject *> it(m_selection);
+ while (it.hasNext()) {
+ QObject *obj = it.next();
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ if (propertyEditor->object() == obj)
+ propertyEditor->setObject(obj);
+ }
+ }
+}
+
+void AddDynamicPropertyCommand::setDescription()
+{
+ if (m_selection.size() == 1) {
+ setText(QApplication::translate("Command", "Add dynamic property '%1' to '%2'").arg(m_propertyName).arg(m_selection.first()->objectName()));
+ } else {
+ int count = m_selection.size();
+ setText(QApplication::translate("Command", "Add dynamic property '%1' to %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
+ }
+}
+
+
+RemoveDynamicPropertyCommand::RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow)
+ : QDesignerFormWindowCommand(QString(), formWindow)
+{
+
+}
+
+bool RemoveDynamicPropertyCommand::init(const QList<QObject *> &selection, QObject *current,
+ const QString &propertyName)
+{
+ Q_ASSERT(current);
+ m_propertyName = propertyName;
+
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), current);
+ Q_ASSERT(propertySheet);
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), current);
+ Q_ASSERT(dynamicSheet);
+
+ m_objectToValueAndChanged.clear();
+
+ const int index = propertySheet->indexOf(m_propertyName);
+ if (!dynamicSheet->isDynamicProperty(index))
+ return false;
+
+ m_objectToValueAndChanged[current] = qMakePair(propertySheet->property(index), propertySheet->isChanged(index));
+
+ QListIterator<QObject *> it(selection);
+ while (it.hasNext()) {
+ QObject *obj = it.next();
+ if (m_objectToValueAndChanged.contains(obj))
+ continue;
+
+ propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
+ dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ const int idx = propertySheet->indexOf(m_propertyName);
+ if (dynamicSheet->isDynamicProperty(idx))
+ m_objectToValueAndChanged[obj] = qMakePair(propertySheet->property(idx), propertySheet->isChanged(idx));
+ }
+
+ setDescription();
+ return true;
+}
+
+void RemoveDynamicPropertyCommand::redo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
+ while (it != m_objectToValueAndChanged.constEnd()) {
+ QObject *obj = it.key();
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
+ dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName));
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ if (propertyEditor->object() == obj)
+ propertyEditor->setObject(obj);
+ }
+ ++it;
+ }
+}
+
+void RemoveDynamicPropertyCommand::undo()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ QMap<QObject *, QPair<QVariant, bool> >::ConstIterator it = m_objectToValueAndChanged.constBegin();
+ while (it != m_objectToValueAndChanged.constEnd()) {
+ QObject *obj = it.key();
+ QDesignerPropertySheetExtension *propertySheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), obj);
+ QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core->extensionManager(), obj);
+ const int index = dynamicSheet->addDynamicProperty(m_propertyName, it.value().first);
+ propertySheet->setChanged(index, it.value().second);
+ if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) {
+ if (propertyEditor->object() == obj)
+ propertyEditor->setObject(obj);
+ }
+ ++it;
+ }
+}
+
+void RemoveDynamicPropertyCommand::setDescription()
+{
+ if (m_objectToValueAndChanged.size() == 1) {
+ setText(QApplication::translate("Command", "Remove dynamic property '%1' from '%2'").arg(m_propertyName).arg(m_objectToValueAndChanged.constBegin().key()->objectName()));
+ } else {
+ int count = m_objectToValueAndChanged.size();
+ setText(QApplication::translate("Command", "Remove dynamic property '%1' from %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName));
+ }
+}
+
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h b/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h
new file mode 100644
index 0000000..6b9722f
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_PROPERTYCOMMAND_H
+#define QDESIGNER_PROPERTYCOMMAND_H
+
+#include "qdesigner_formwindowcommand_p.h"
+
+#include <QtCore/QVariant>
+#include <QtCore/QList>
+#include <QtCore/QPair>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerPropertySheetExtension;
+
+namespace qdesigner_internal {
+
+class QDesignerIntegration;
+
+enum SpecialProperty {
+ SP_None, SP_ObjectName, SP_LayoutName, SP_SpacerName,SP_WindowTitle,
+ SP_MinimumSize, SP_MaximumSize, SP_Geometry, SP_Icon, SP_CurrentTabName, SP_CurrentItemName, SP_CurrentPageName,
+ SP_AutoDefault, SP_Alignment, SP_Shortcut, SP_Orientation
+};
+
+//Determine special property
+enum SpecialProperty getSpecialProperty(const QString& propertyName);
+
+
+// A helper class for applying properties to objects.
+// Can be used for Set commands (setValue(), restoreOldValue()) or
+// Reset Commands restoreDefaultValue(), restoreOldValue()).
+class PropertyHelper {
+public:
+ // A pair of Value and changed flag
+ typedef QPair<QVariant, bool> Value;
+
+ enum ObjectType {OT_Object, OT_FreeAction, OT_AssociatedAction, OT_Widget};
+
+ PropertyHelper(QObject* object,
+ SpecialProperty specialProperty,
+ QDesignerPropertySheetExtension *sheet,
+ int index);
+
+ QObject *object() const { return m_object; }
+ SpecialProperty specialProperty() const { return m_specialProperty; }
+ // set a new value
+ Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask);
+
+ // restore old value
+ Value restoreOldValue(QDesignerFormWindowInterface *fw);
+ // set default value
+ Value restoreDefaultValue(QDesignerFormWindowInterface *fw);
+
+ inline QVariant oldValue() const
+ { return m_oldValue.first; }
+
+ inline void setOldValue(const QVariant &oldValue)
+ { m_oldValue.first = oldValue; }
+
+ // required updates for this property (bit mask)
+ enum UpdateMask { UpdatePropertyEditor=1, UpdateObjectInspector=2 };
+ unsigned updateMask() const;
+
+ // can be merged into one command (that is, object and name match)
+ bool canMerge(const PropertyHelper &other) const;
+ QDesignerIntegration *integration(QDesignerFormWindowInterface *fw) const;
+
+ static void triggerActionChanged(QAction *a);
+
+private:
+ // Apply the value and update. Returns corrected value
+ Value applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue);
+
+ static void checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w,
+ SpecialProperty specialProperty, QVariant &v);
+
+ void updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue);
+ QVariant findDefaultValue(QDesignerFormWindowInterface *fw) const;
+ void ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const;
+ SpecialProperty m_specialProperty;
+
+ QPointer<QObject> m_object;
+ ObjectType m_objectType;
+ QPointer<QWidget> m_parentWidget;
+
+ QDesignerPropertySheetExtension *m_propertySheet;
+ int m_index;
+
+ Value m_oldValue;
+};
+
+// Base class for commands that can be applied to several widgets
+
+class QDESIGNER_SHARED_EXPORT PropertyListCommand : public QDesignerFormWindowCommand {
+public:
+ typedef QList<QObject *> ObjectList;
+
+ explicit PropertyListCommand(QDesignerFormWindowInterface *formWindow);
+
+ QObject* object(int index = 0) const;
+
+ QVariant oldValue(int index = 0) const;
+
+ void setOldValue(const QVariant &oldValue, int index = 0);
+
+ // Calls restoreDefaultValue() and update()
+ virtual void undo();
+
+protected:
+ typedef QList<PropertyHelper> PropertyHelperList;
+
+
+ // add an object
+ bool add(QObject *object, const QString &propertyName);
+
+ // Init from a list and make sure referenceObject is added first to obtain the right property group
+ bool initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject = 0);
+
+ // set a new value, return update mask
+ unsigned setValue(QVariant value, bool changed, unsigned subPropertyMask);
+
+ // restore old value, return update mask
+ unsigned restoreOldValue();
+ // set default value, return update mask
+ unsigned restoreDefaultValue();
+
+ // update designer
+ void update(unsigned updateMask);
+
+ // check if lists are aequivalent for command merging (same widgets and props)
+ bool canMergeLists(const PropertyHelperList& other) const;
+
+ PropertyHelperList& propertyHelperList() { return m_propertyHelperList; }
+ const PropertyHelperList& propertyHelperList() const { return m_propertyHelperList; }
+
+ const QString propertyName() const;
+ SpecialProperty specialProperty() const;
+
+ // Helper struct describing a property used for checking whether
+ // properties of different widgets are equivalent
+ struct PropertyDescription {
+ public:
+ PropertyDescription();
+ PropertyDescription(const QString &propertyName, QDesignerPropertySheetExtension *propertySheet, int index);
+ bool equals(const PropertyDescription &p) const;
+ void debug() const;
+
+ QString m_propertyName;
+ QString m_propertyGroup;
+ QVariant::Type m_propertyType;
+ SpecialProperty m_specialProperty;
+ };
+ const PropertyDescription &propertyDescription() const { return m_propertyDescription; }
+
+private:
+ PropertyDescription m_propertyDescription;
+ PropertyHelperList m_propertyHelperList;
+};
+
+class QDESIGNER_SHARED_EXPORT SetPropertyCommand: public PropertyListCommand
+{
+
+public:
+ typedef QList<QObject *> ObjectList;
+
+ explicit SetPropertyCommand(QDesignerFormWindowInterface *formWindow);
+
+ bool init(QObject *object, const QString &propertyName, const QVariant &newValue);
+ bool init(const ObjectList &list, const QString &propertyName, const QVariant &newValue,
+ QObject *referenceObject = 0, bool enableSubPropertyHandling = true);
+
+
+ inline QVariant newValue() const
+ { return m_newValue; }
+
+ inline void setNewValue(const QVariant &newValue)
+ { m_newValue = newValue; }
+
+ int id() const;
+ bool mergeWith(const QUndoCommand *other);
+
+ virtual void redo();
+private:
+ unsigned subPropertyMask(const QVariant &newValue, QObject *referenceObject);
+ void setDescription();
+ QVariant m_newValue;
+ unsigned m_subPropertyMask;
+};
+
+class QDESIGNER_SHARED_EXPORT ResetPropertyCommand: public PropertyListCommand
+{
+
+public:
+ typedef QList<QObject *> ObjectList;
+
+ explicit ResetPropertyCommand(QDesignerFormWindowInterface *formWindow);
+
+ bool init(QObject *object, const QString &propertyName);
+ bool init(const ObjectList &list, const QString &propertyName, QObject *referenceObject = 0);
+
+ virtual void redo();
+
+protected:
+ virtual bool mergeWith(const QUndoCommand *) { return false; }
+
+private:
+ void setDescription();
+ QString m_propertyName;
+};
+
+
+class QDESIGNER_SHARED_EXPORT AddDynamicPropertyCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow);
+
+ bool init(const QList<QObject *> &selection, QObject *current, const QString &propertyName, const QVariant &value);
+
+ virtual void redo();
+ virtual void undo();
+private:
+ void setDescription();
+ QString m_propertyName;
+ QList<QObject *> m_selection;
+ QVariant m_value;
+};
+
+class QDESIGNER_SHARED_EXPORT RemoveDynamicPropertyCommand: public QDesignerFormWindowCommand
+{
+
+public:
+ explicit RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow);
+
+ bool init(const QList<QObject *> &selection, QObject *current, const QString &propertyName);
+
+ virtual void redo();
+ virtual void undo();
+private:
+ void setDescription();
+ QString m_propertyName;
+ QMap<QObject *, QPair<QVariant, bool> > m_objectToValueAndChanged;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_PROPERTYCOMMAND_H
diff --git a/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp
new file mode 100644
index 0000000..7c7d9d7
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qdesigner_propertyeditor_p.h"
+#ifdef Q_OS_WIN
+# include <widgetfactory_p.h>
+#endif
+#include <QAction>
+#include <QLineEdit>
+#include <QAbstractButton>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+QDesignerPropertyEditor::QDesignerPropertyEditor(QWidget *parent, Qt::WindowFlags flags) :
+ QDesignerPropertyEditorInterface(parent, flags)
+{
+ // Make old signal work for compatibility
+ connect(this, SIGNAL(propertyChanged(QString,QVariant)), this, SLOT(slotPropertyChanged(QString,QVariant)));
+}
+
+QDesignerPropertyEditor::StringPropertyParameters QDesignerPropertyEditor::textPropertyValidationMode(
+ QDesignerFormEditorInterface *core, const QObject *object,
+ const QString &propertyName, bool isMainContainer)
+{
+ // object name - no comment
+ if (propertyName == QLatin1String("objectName")) {
+ const TextPropertyValidationMode vm = isMainContainer ? ValidationObjectNameScope : ValidationObjectName;
+ return StringPropertyParameters(vm, false);
+ }
+
+ // Accessibility. Both are texts the narrator reads
+ if (propertyName == QLatin1String("accessibleDescription") || propertyName == QLatin1String("accessibleName"))
+ return StringPropertyParameters(ValidationRichText, true);
+
+ // Names
+ if (propertyName == QLatin1String("buddy")
+ || propertyName == QLatin1String("currentItemName")
+ || propertyName == QLatin1String("currentPageName")
+ || propertyName == QLatin1String("currentTabName")
+ || propertyName == QLatin1String("layoutName")
+ || propertyName == QLatin1String("spacerName"))
+ return StringPropertyParameters(ValidationObjectName, false);
+
+ if (propertyName.endsWith(QLatin1String("Name")))
+ return StringPropertyParameters(ValidationSingleLine, true);
+
+ // Multi line?
+ if (propertyName == QLatin1String("styleSheet"))
+ return StringPropertyParameters(ValidationStyleSheet, false);
+
+ if (propertyName == QLatin1String("description") || propertyName == QLatin1String("iconText")) // QCommandLinkButton
+ return StringPropertyParameters(ValidationMultiLine, true);
+
+ if (propertyName == QLatin1String("toolTip") || propertyName.endsWith(QLatin1String("ToolTip")) ||
+ propertyName == QLatin1String("whatsThis") ||
+ propertyName == QLatin1String("windowIconText") || propertyName == QLatin1String("html"))
+ return StringPropertyParameters(ValidationRichText, true);
+
+ // text: Check according to widget type.
+ if (propertyName == QLatin1String("text")) {
+ if (qobject_cast<const QAction *>(object) || qobject_cast<const QLineEdit *>(object))
+ return StringPropertyParameters(ValidationSingleLine, true);
+ if (qobject_cast<const QAbstractButton *>(object))
+ return StringPropertyParameters(ValidationMultiLine, true);
+ return StringPropertyParameters(ValidationRichText, true);
+ }
+ if (propertyName == QLatin1String("pageId")) // A QWizard page id
+ return StringPropertyParameters(ValidationSingleLine, false);
+
+ if (propertyName == QLatin1String("plainText")) // QPlainTextEdit
+ return StringPropertyParameters(ValidationMultiLine, true);
+
+#ifdef Q_OS_WIN // No translation for the active X "control" property
+ if (propertyName == QLatin1String("control") && WidgetFactory::classNameOf(core, object) == QLatin1String("QAxWidget"))
+ return StringPropertyParameters(ValidationSingleLine, false);
+#else
+ Q_UNUSED(core);
+#endif
+
+ // default to single
+ return StringPropertyParameters(ValidationSingleLine, true);
+}
+
+void QDesignerPropertyEditor::slotPropertyChanged(const QString &name, const QVariant &value)
+{
+ emit propertyValueChanged(name, value, true);
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h b/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h
new file mode 100644
index 0000000..a979fde
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.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$
+**
+****************************************************************************/
+
+//
+// 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 DESIGNERPROPERTYEDITOR_H
+#define DESIGNERPROPERTYEDITOR_H
+
+#include "shared_global_p.h"
+#include "shared_enums_p.h"
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+// Extends the QDesignerPropertyEditorInterface by property comment handling and
+// a signal for resetproperty.
+
+class QDESIGNER_SHARED_EXPORT QDesignerPropertyEditor: public QDesignerPropertyEditorInterface
+{
+ Q_OBJECT
+public:
+ QDesignerPropertyEditor(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+
+ // A pair <ValidationMode, bool isTranslatable>.
+ typedef QPair<TextPropertyValidationMode, bool> StringPropertyParameters;
+
+ // Return a pair of validation mode and flag indicating whether property is translatable
+ // for textual properties.
+ static StringPropertyParameters textPropertyValidationMode(QDesignerFormEditorInterface *core,
+ const QObject *object, const QString &propertyName, bool isMainContainer);
+
+
+Q_SIGNALS:
+ void propertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling);
+ void resetProperty(const QString &name);
+ void addDynamicProperty(const QString &name, const QVariant &value);
+ void removeDynamicProperty(const QString &name);
+ void editorOpened();
+ void editorClosed();
+
+public Q_SLOTS:
+ /* Quick update that assumes the actual count of properties has not changed
+ * (as opposed to setObject()). N/A when for example executing a
+ * layout command and margin properties appear. */
+ virtual void updatePropertySheet() = 0;
+ virtual void reloadResourceProperties() = 0;
+
+private Q_SLOTS:
+ void slotPropertyChanged(const QString &name, const QVariant &value);
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // DESIGNERPROPERTYEDITOR_H
diff --git a/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp
new file mode 100644
index 0000000..7abbde7
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp
@@ -0,0 +1,1601 @@
+/****************************************************************************
+**
+** 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_propertysheet_p.h"
+#include "qdesigner_utils_p.h"
+#include "formwindowbase_p.h"
+#include "layoutinfo_p.h"
+#include "qlayout_widget_p.h"
+#include "qdesigner_introspection_p.h"
+
+#include <formbuilderextra_p.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtCore/QDebug>
+
+#include <QtGui/QLayout>
+#include <QtGui/QDockWidget>
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QGroupBox>
+#include <QtGui/QStyle>
+#include <QtGui/QApplication>
+#include <QtGui/QToolBar>
+#include <QtGui/QMainWindow>
+
+QT_BEGIN_NAMESPACE
+
+#define USE_LAYOUT_SIZE_CONSTRAINT
+
+static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index)
+{
+ if (index >= meta->propertyOffset())
+ return meta;
+
+ if (meta->superClass())
+ return propertyIntroducedBy(meta->superClass(), index);
+
+ return 0;
+}
+
+// Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins'
+// that might be around. These are forwarded to the layout sheet (after name transformation).
+//
+// 'layoutObjectName' is new for 4.4. It is the name of the actual layout.
+// Up to 4.3, QLayoutWidget's name was displayed in the objectinspector.
+// This changes with 4.4; the layout name is displayed. This means that for
+// old forms, QLayoutWidget will show up as ''; however, the uic code will
+// still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names,
+// legacy forms will keep their empty names (unless someone types in a new name).
+static const char *layoutObjectNameC = "layoutName";
+static const char *layoutLeftMarginC = "layoutLeftMargin";
+static const char *layoutTopMarginC = "layoutTopMargin";
+static const char *layoutRightMarginC = "layoutRightMargin";
+static const char *layoutBottomMarginC = "layoutBottomMargin";
+static const char *layoutSpacingC = "layoutSpacing";
+static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing";
+static const char *layoutVerticalSpacingC = "layoutVerticalSpacing";
+static const char *layoutSizeConstraintC = "layoutSizeConstraint";
+// form layout
+static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy";
+static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy";
+static const char *layoutLabelAlignmentC = "layoutLabelAlignment";
+static const char *layoutFormAlignmentC = "layoutFormAlignment";
+// stretches
+static const char *layoutboxStretchPropertyC = "layoutStretch";
+static const char *layoutGridRowStretchPropertyC = "layoutRowStretch";
+static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch";
+static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight";
+static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth";
+
+// Find the form editor in the hierarchy.
+// We know that the parent of the sheet is the extension manager
+// whose parent is the core.
+
+static QDesignerFormEditorInterface *formEditorForObject(QObject *o) {
+ do {
+ if (QDesignerFormEditorInterface* core = qobject_cast<QDesignerFormEditorInterface*>(o))
+ return core;
+ o = o->parent();
+ } while(o);
+ Q_ASSERT(o);
+ return 0;
+}
+
+static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object)
+{
+ if (!object->isWidgetType())
+ return false;
+
+ QWidget *w = qobject_cast<QWidget *>(object);
+ if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) {
+ if (db->isContainer(w))
+ return true;
+ }
+ return false;
+}
+
+// Cache DesignerMetaEnum by scope/name of a QMetaEnum
+static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me)
+{
+ typedef QPair<QString, QString> ScopeNameKey;
+ typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaEnum> DesignerMetaEnumCache;
+ static DesignerMetaEnumCache cache;
+
+ const QString name = me->name();
+ const QString scope = me->scope();
+
+ const ScopeNameKey key = ScopeNameKey(scope, name);
+ DesignerMetaEnumCache::iterator it = cache.find(key);
+ if (it == cache.end()) {
+ qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator());
+ const int keyCount = me->keyCount();
+ for (int i=0; i < keyCount; ++i)
+ dme.addKey(me->value(i), me->key(i));
+ it = cache.insert(key, dme);
+ }
+ return it.value();
+}
+
+// Cache DesignerMetaFlags by scope/name of a QMetaEnum
+static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me)
+{
+ typedef QPair<QString, QString> ScopeNameKey;
+ typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaFlags> DesignerMetaFlagsCache;
+ static DesignerMetaFlagsCache cache;
+
+ const QString name = me->name();
+ const QString scope = me->scope();
+
+ const ScopeNameKey key = ScopeNameKey(scope, name);
+ DesignerMetaFlagsCache::iterator it = cache.find(key);
+ if (it == cache.end()) {
+ qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator());
+ const int keyCount = me->keyCount();
+ for (int i=0; i < keyCount; ++i)
+ dme.addKey(me->value(i), me->key(i));
+ it = cache.insert(key, dme);
+ }
+ return it.value();
+}
+
+// ------------ QDesignerMemberSheetPrivate
+class QDesignerPropertySheetPrivate {
+public:
+ typedef QDesignerPropertySheet::PropertyType PropertyType;
+ typedef QDesignerPropertySheet::ObjectType ObjectType;
+
+ explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent);
+
+ bool invalidIndex(const char *functionName, int index) const;
+ inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); }
+
+ PropertyType propertyType(int index) const;
+ QString transformLayoutPropertyName(int index) const;
+ QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = 0) const;
+ static ObjectType objectType(const QObject *o);
+
+ bool isReloadableProperty(int index) const;
+ bool isResourceProperty(int index) const;
+ void addResourceProperty(int index, QVariant::Type type);
+ QVariant resourceProperty(int index) const;
+ void setResourceProperty(int index, const QVariant &value);
+ QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue
+ QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only)
+
+ bool isStringProperty(int index) const;
+ void addStringProperty(int index);
+ qdesigner_internal::PropertySheetStringValue stringProperty(int index) const;
+ void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value);
+
+ bool isKeySequenceProperty(int index) const;
+ void addKeySequenceProperty(int index);
+ qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const;
+ void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value);
+
+ enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty };
+ class Info {
+ public:
+ Info();
+
+ QString group;
+ QVariant defaultValue;
+ bool changed;
+ bool visible;
+ bool attribute;
+ bool reset;
+ PropertyType propertyType;
+ PropertyKind kind;
+ };
+
+ Info &ensureInfo(int index);
+
+ QDesignerPropertySheet *q;
+ QDesignerFormEditorInterface *m_core;
+ const QDesignerMetaObjectInterface *m_meta;
+ const ObjectType m_objectType;
+
+ typedef QHash<int, Info> InfoHash;
+ InfoHash m_info;
+ QHash<int, QVariant> m_fakeProperties;
+ QHash<int, QVariant> m_addProperties;
+ QHash<QString, int> m_addIndex;
+ QHash<int, QVariant> m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here
+ QHash<int, qdesigner_internal::PropertySheetStringValue> m_stringProperties; // only PropertySheetStringValue
+ QHash<int, qdesigner_internal::PropertySheetKeySequenceValue> m_keySequenceProperties; // only PropertySheetKeySequenceValue
+
+ const bool m_canHaveLayoutAttributes;
+
+ // Variables used for caching the layout, access via layout().
+ QPointer<QObject> m_object;
+ mutable QPointer<QLayout> m_lastLayout;
+ mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet;
+ mutable bool m_LastLayoutByDesigner;
+
+ qdesigner_internal::DesignerPixmapCache *m_pixmapCache;
+ qdesigner_internal::DesignerIconCache *m_iconCache;
+ QPointer<qdesigner_internal::FormWindowBase> m_fwb;
+
+ // Enable Qt's internal properties starting with prefix "_q_"
+ static bool m_internalDynamicPropertiesEnabled;
+};
+
+bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false;
+
+/*
+ The property is reloadable if its contents depends on resource.
+*/
+bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const
+{
+ return isResourceProperty(index)
+ || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet
+ || q->property(index).type() == QVariant::Url;
+}
+
+/*
+ Resource properties are those which:
+ 1) are reloadable
+ 2) their state is associated with a file which can be taken from resources
+ 3) we don't store them in Qt meta object system (because designer keeps different data structure for them)
+*/
+
+bool QDesignerPropertySheetPrivate::isResourceProperty(int index) const
+{
+ return m_resourceProperties.contains(index);
+}
+
+void QDesignerPropertySheetPrivate::addResourceProperty(int index, QVariant::Type type)
+{
+ if (type == QVariant::Pixmap)
+ m_resourceProperties.insert(index, qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue()));
+ else if (type == QVariant::Icon)
+ m_resourceProperties.insert(index, qVariantFromValue(qdesigner_internal::PropertySheetIconValue()));
+}
+
+QVariant QDesignerPropertySheetPrivate::emptyResourceProperty(int index) const
+{
+ QVariant v = m_resourceProperties.value(index);
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(v))
+ return qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue());
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(v))
+ return qVariantFromValue(qdesigner_internal::PropertySheetIconValue());
+ return v;
+}
+
+QVariant QDesignerPropertySheetPrivate::defaultResourceProperty(int index) const
+{
+ return m_info.value(index).defaultValue;
+}
+
+QVariant QDesignerPropertySheetPrivate::resourceProperty(int index) const
+{
+ return m_resourceProperties.value(index);
+}
+
+void QDesignerPropertySheetPrivate::setResourceProperty(int index, const QVariant &value)
+{
+ Q_ASSERT(isResourceProperty(index));
+
+ QVariant &v = m_resourceProperties[index];
+ if ((qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(value) && qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(v))
+ || (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(value) && qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(v)))
+ v = value;
+}
+
+bool QDesignerPropertySheetPrivate::isStringProperty(int index) const
+{
+ return m_stringProperties.contains(index);
+}
+
+void QDesignerPropertySheetPrivate::addStringProperty(int index)
+{
+ m_stringProperties.insert(index, qdesigner_internal::PropertySheetStringValue());
+}
+
+qdesigner_internal::PropertySheetStringValue QDesignerPropertySheetPrivate::stringProperty(int index) const
+{
+ return m_stringProperties.value(index);
+}
+
+void QDesignerPropertySheetPrivate::setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value)
+{
+ Q_ASSERT(isStringProperty(index));
+
+ m_stringProperties[index] = value;
+}
+
+bool QDesignerPropertySheetPrivate::isKeySequenceProperty(int index) const
+{
+ return m_keySequenceProperties.contains(index);
+}
+
+void QDesignerPropertySheetPrivate::addKeySequenceProperty(int index)
+{
+ m_keySequenceProperties.insert(index, qdesigner_internal::PropertySheetKeySequenceValue());
+}
+
+qdesigner_internal::PropertySheetKeySequenceValue QDesignerPropertySheetPrivate::keySequenceProperty(int index) const
+{
+ return m_keySequenceProperties.value(index);
+}
+
+void QDesignerPropertySheetPrivate::setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value)
+{
+ Q_ASSERT(isKeySequenceProperty(index));
+
+ m_keySequenceProperties[index] = value;
+}
+
+QDesignerPropertySheetPrivate::Info::Info() :
+ changed(false),
+ visible(true),
+ attribute(false),
+ reset(true),
+ propertyType(QDesignerPropertySheet::PropertyNone),
+ kind(NormalProperty)
+{
+}
+
+QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent) :
+ q(sheetPublic),
+ m_core(formEditorForObject(sheetParent)),
+ m_meta(m_core->introspection()->metaObject(object)),
+ m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)),
+ m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)),
+ m_object(object),
+ m_lastLayout(0),
+ m_lastLayoutPropertySheet(0),
+ m_LastLayoutByDesigner(false),
+ m_pixmapCache(0),
+ m_iconCache(0)
+{
+}
+
+qdesigner_internal::FormWindowBase *QDesignerPropertySheet::formWindowBase() const
+{
+ return d->m_fwb;
+}
+
+bool QDesignerPropertySheetPrivate::invalidIndex(const char *functionName, int index) const
+{
+ if (index < 0 || index >= count()) {
+ qWarning() << "** WARNING " << functionName << " invoked for " << m_object->objectName() << " was passed an invalid index " << index << '.';
+ return true;
+ }
+ return false;
+}
+
+QLayout* QDesignerPropertySheetPrivate::layout(QDesignerPropertySheetExtension **layoutPropertySheet) const
+{
+ // Return the layout and its property sheet
+ // only if it is managed by designer and not one created on a custom widget.
+ // (attempt to cache the value as this requires some hoops).
+ if (layoutPropertySheet)
+ *layoutPropertySheet = 0;
+
+ if (!m_object->isWidgetType() || !m_canHaveLayoutAttributes)
+ return 0;
+
+ QWidget *widget = qobject_cast<QWidget*>(m_object);
+ QLayout *widgetLayout = qdesigner_internal::LayoutInfo::internalLayout(widget);
+ if (!widgetLayout) {
+ m_lastLayout = 0;
+ m_lastLayoutPropertySheet = 0;
+ return 0;
+ }
+ // Smart logic to avoid retrieving the meta DB from the widget every time.
+ if (widgetLayout != m_lastLayout) {
+ m_lastLayout = widgetLayout;
+ m_LastLayoutByDesigner = false;
+ m_lastLayoutPropertySheet = 0;
+ // Is this a layout managed by designer or some layout on a custom widget?
+ if (qdesigner_internal::LayoutInfo::managedLayout(m_core ,widgetLayout)) {
+ m_LastLayoutByDesigner = true;
+ m_lastLayoutPropertySheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), m_lastLayout);
+ }
+ }
+ if (!m_LastLayoutByDesigner)
+ return 0;
+
+ if (layoutPropertySheet)
+ *layoutPropertySheet = m_lastLayoutPropertySheet;
+
+ return m_lastLayout;
+}
+
+QDesignerPropertySheetPrivate::Info &QDesignerPropertySheetPrivate::ensureInfo(int index)
+{
+ InfoHash::iterator it = m_info.find(index);
+ if (it == m_info.end())
+ it = m_info.insert(index, Info());
+ return it.value();
+}
+
+QDesignerPropertySheet::PropertyType QDesignerPropertySheetPrivate::propertyType(int index) const
+{
+ const InfoHash::const_iterator it = m_info.constFind(index);
+ if (it == m_info.constEnd())
+ return QDesignerPropertySheet::PropertyNone;
+ return it.value().propertyType;
+}
+
+QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) const
+{
+ typedef QMap<QDesignerPropertySheet::PropertyType, QString> TypeNameMap;
+ static TypeNameMap typeNameMap;
+ if (typeNameMap.empty()) {
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QLatin1String("objectName"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QLatin1String("leftMargin"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QLatin1String("topMargin"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRightMargin, QLatin1String("rightMargin"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBottomMargin, QLatin1String("bottomMargin"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSpacing, QLatin1String("spacing"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutHorizontalSpacing, QLatin1String("horizontalSpacing"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutVerticalSpacing, QLatin1String("verticalSpacing"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSizeConstraint, QLatin1String("sizeConstraint"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFieldGrowthPolicy, QLatin1String("fieldGrowthPolicy"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRowWrapPolicy, QLatin1String("rowWrapPolicy"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLabelAlignment, QLatin1String("labelAlignment"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFormAlignment, QLatin1String("formAlignment"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBoxStretch, QLatin1String("stretch"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowStretch, QLatin1String("rowStretch"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnStretch, QLatin1String("columnStretch"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowMinimumHeight, QLatin1String("rowMinimumHeight"));
+ typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnMinimumWidth, QLatin1String("columnMinimumWidth"));
+ }
+ const TypeNameMap::const_iterator it = typeNameMap.constFind(propertyType(index));
+ if (it != typeNameMap.constEnd())
+ return it.value();
+ return QString();
+}
+
+// ----------- QDesignerPropertySheet
+
+QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject(const QObject *o)
+{
+ if (qobject_cast<const QLayout *>(o))
+ return ObjectLayout;
+
+ if (!o->isWidgetType())
+ return ObjectNone;
+
+ if (qobject_cast<const QLayoutWidget *>(o))
+ return ObjectLayoutWidget;
+
+ if (qobject_cast<const QLabel*>(o))
+ return ObjectLabel;
+
+ if (o->inherits("Q3GroupBox"))
+ return ObjectQ3GroupBox;
+
+ return ObjectNone;
+}
+
+QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name)
+{
+ typedef QHash<QString, PropertyType> PropertyTypeHash;
+ static PropertyTypeHash propertyTypeHash;
+ if (propertyTypeHash.empty()) {
+ propertyTypeHash.insert(QLatin1String(layoutObjectNameC), PropertyLayoutObjectName);
+ propertyTypeHash.insert(QLatin1String(layoutLeftMarginC), PropertyLayoutLeftMargin);
+ propertyTypeHash.insert(QLatin1String(layoutTopMarginC), PropertyLayoutTopMargin);
+ propertyTypeHash.insert(QLatin1String(layoutRightMarginC), PropertyLayoutRightMargin);
+ propertyTypeHash.insert(QLatin1String(layoutBottomMarginC), PropertyLayoutBottomMargin);
+ propertyTypeHash.insert(QLatin1String(layoutSpacingC), PropertyLayoutSpacing);
+ propertyTypeHash.insert(QLatin1String(layoutHorizontalSpacingC), PropertyLayoutHorizontalSpacing);
+ propertyTypeHash.insert(QLatin1String(layoutVerticalSpacingC), PropertyLayoutVerticalSpacing);
+ propertyTypeHash.insert(QLatin1String(layoutSizeConstraintC), PropertyLayoutSizeConstraint);
+ propertyTypeHash.insert(QLatin1String(layoutFieldGrowthPolicyC), PropertyLayoutFieldGrowthPolicy);
+ propertyTypeHash.insert(QLatin1String(layoutRowWrapPolicyC), PropertyLayoutRowWrapPolicy);
+ propertyTypeHash.insert(QLatin1String(layoutLabelAlignmentC), PropertyLayoutLabelAlignment);
+ propertyTypeHash.insert(QLatin1String(layoutFormAlignmentC), PropertyLayoutFormAlignment);
+ propertyTypeHash.insert(QLatin1String(layoutboxStretchPropertyC), PropertyLayoutBoxStretch);
+ propertyTypeHash.insert(QLatin1String(layoutGridRowStretchPropertyC), PropertyLayoutGridRowStretch);
+ propertyTypeHash.insert(QLatin1String(layoutGridColumnStretchPropertyC), PropertyLayoutGridColumnStretch);
+ propertyTypeHash.insert(QLatin1String(layoutGridRowMinimumHeightC), PropertyLayoutGridRowMinimumHeight);
+ propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC), PropertyLayoutGridColumnMinimumWidth);
+ propertyTypeHash.insert(QLatin1String("buddy"), PropertyBuddy);
+ propertyTypeHash.insert(QLatin1String("geometry"), PropertyGeometry);
+ propertyTypeHash.insert(QLatin1String("checkable"), PropertyCheckable);
+ propertyTypeHash.insert(QLatin1String("accessibleName"), PropertyAccessibility);
+ propertyTypeHash.insert(QLatin1String("accessibleDescription"), PropertyAccessibility);
+ propertyTypeHash.insert(QLatin1String("windowTitle"), PropertyWindowTitle);
+ propertyTypeHash.insert(QLatin1String("windowIcon"), PropertyWindowIcon);
+ propertyTypeHash.insert(QLatin1String("windowFilePath"), PropertyWindowFilePath);
+ propertyTypeHash.insert(QLatin1String("windowOpacity"), PropertyWindowOpacity);
+ propertyTypeHash.insert(QLatin1String("windowIconText"), PropertyWindowIconText);
+ propertyTypeHash.insert(QLatin1String("windowModality"), PropertyWindowModality);
+ propertyTypeHash.insert(QLatin1String("windowModified"), PropertyWindowModified);
+ propertyTypeHash.insert(QLatin1String("styleSheet"), PropertyStyleSheet);
+ }
+ return propertyTypeHash.value(name, PropertyNone);
+}
+
+QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) :
+ QObject(parent),
+ d(new QDesignerPropertySheetPrivate(this, object, parent))
+{
+ typedef QDesignerPropertySheetPrivate::Info Info;
+ const QDesignerMetaObjectInterface *baseMeta = d->m_meta;
+
+ while (baseMeta &&baseMeta->className().startsWith(QLatin1String("QDesigner"))) {
+ baseMeta = baseMeta->superClass();
+ }
+ Q_ASSERT(baseMeta != 0);
+
+ QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(d->m_object);
+ d->m_fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
+ if (d->m_fwb) {
+ d->m_pixmapCache = d->m_fwb->pixmapCache();
+ d->m_iconCache = d->m_fwb->iconCache();
+ d->m_fwb->addReloadablePropertySheet(this, object);
+ }
+
+ for (int index=0; index<count(); ++index) {
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ const QString name = p->name();
+ if (p->type() == QVariant::KeySequence) {
+ createFakeProperty(name);
+ } else {
+ setVisible(index, false); // use the default for `real' properties
+ }
+
+ QString pgroup = baseMeta->className();
+
+ if (const QDesignerMetaObjectInterface *pmeta = propertyIntroducedBy(baseMeta, index)) {
+ pgroup = pmeta->className();
+ }
+
+ Info &info = d->ensureInfo(index);
+ info.group = pgroup;
+ info.propertyType = propertyTypeFromName(name);
+
+ if (p->type() == QVariant::Cursor || p->type() == QVariant::Icon || p->type() == QVariant::Pixmap) {
+ info.defaultValue = p->read(d->m_object);
+ if (p->type() == QVariant::Icon || p->type() == QVariant::Pixmap)
+ d->addResourceProperty(index, p->type());
+ } else if (p->type() == QVariant::String) {
+ d->addStringProperty(index);
+ } else if (p->type() == QVariant::KeySequence) {
+ d->addKeySequenceProperty(index);
+ }
+ }
+
+ if (object->isWidgetType()) {
+ createFakeProperty(QLatin1String("focusPolicy"));
+ createFakeProperty(QLatin1String("cursor"));
+ createFakeProperty(QLatin1String("toolTip"));
+ createFakeProperty(QLatin1String("whatsThis"));
+ createFakeProperty(QLatin1String("acceptDrops"));
+ createFakeProperty(QLatin1String("dragEnabled"));
+ // windowModality is visible only for the main container, in which case the form windows enables it on loading
+ setVisible(createFakeProperty(QLatin1String("windowModality")), false);
+ if (qobject_cast<const QToolBar *>(d->m_object)) // prevent toolbars from being dragged off
+ createFakeProperty(QLatin1String("floatable"), QVariant(true));
+
+ if (d->m_canHaveLayoutAttributes) {
+ static const QString layoutGroup = QLatin1String("Layout");
+ const char* fakeLayoutProperties[] = {
+ layoutObjectNameC, layoutLeftMarginC, layoutTopMarginC, layoutRightMarginC, layoutBottomMarginC, layoutSpacingC, layoutHorizontalSpacingC, layoutVerticalSpacingC,
+ layoutFieldGrowthPolicyC, layoutRowWrapPolicyC, layoutLabelAlignmentC, layoutFormAlignmentC,
+ layoutboxStretchPropertyC, layoutGridRowStretchPropertyC, layoutGridColumnStretchPropertyC,
+ layoutGridRowMinimumHeightC, layoutGridColumnMinimumWidthC
+#ifdef USE_LAYOUT_SIZE_CONSTRAINT
+ , layoutSizeConstraintC
+#endif
+ };
+ const int fakeLayoutPropertyCount = sizeof(fakeLayoutProperties)/sizeof(const char*);
+ const int size = count();
+ for (int i = 0; i < fakeLayoutPropertyCount; i++) {
+ createFakeProperty(QLatin1String(fakeLayoutProperties[i]), 0);
+ setAttribute(size + i, true);
+ setPropertyGroup(size + i, layoutGroup);
+ }
+ }
+
+ if (d->m_objectType == ObjectLabel)
+ createFakeProperty(QLatin1String("buddy"), QVariant(QByteArray()));
+ /* We need to create a fake property since the property does not work
+ * for non-toplevel windows or on other systems than Mac and only if
+ * it is above a certain Mac OS version. */
+ if (qobject_cast<const QMainWindow *>(d->m_object))
+ createFakeProperty(QLatin1String("unifiedTitleAndToolBarOnMac"), false);
+ }
+
+ if (qobject_cast<const QDialog*>(object)) {
+ createFakeProperty(QLatin1String("modal"));
+ }
+ if (qobject_cast<const QDockWidget*>(object)) {
+ createFakeProperty(QLatin1String("floating"));
+ }
+
+ typedef QList<QByteArray> ByteArrayList;
+ const ByteArrayList names = object->dynamicPropertyNames();
+ if (!names.empty()) {
+ const ByteArrayList::const_iterator cend = names.constEnd();
+ for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) {
+ const char* cName = it->constData();
+ const QString name = QString::fromLatin1(cName);
+ const int idx = addDynamicProperty(name, object->property(cName));
+ if (idx != -1)
+ d->ensureInfo(idx).kind = QDesignerPropertySheetPrivate::DefaultDynamicProperty;
+ }
+ }
+}
+
+QDesignerPropertySheet::~QDesignerPropertySheet()
+{
+ if (d->m_fwb)
+ d->m_fwb->removeReloadablePropertySheet(this);
+ delete d;
+}
+
+QObject *QDesignerPropertySheet::object() const
+{
+ return d->m_object;
+}
+
+bool QDesignerPropertySheet::dynamicPropertiesAllowed() const
+{
+ return true;
+}
+
+bool QDesignerPropertySheet::canAddDynamicProperty(const QString &propName) const
+{
+ const int index = d->m_meta->indexOfProperty(propName);
+ if (index != -1)
+ return false; // property already exists and is not a dynamic one
+ if (d->m_addIndex.contains(propName)) {
+ const int idx = d->m_addIndex.value(propName);
+ if (isVisible(idx))
+ return false; // dynamic property already exists
+ else
+ return true;
+ }
+ if (!QDesignerPropertySheet::internalDynamicPropertiesEnabled() && propName.startsWith(QLatin1String("_q_")))
+ return false;
+ return true;
+}
+
+int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QVariant &value)
+{
+ typedef QDesignerPropertySheetPrivate::Info Info;
+ if (!value.isValid())
+ return -1; // property has invalid type
+ if (!canAddDynamicProperty(propName))
+ return -1;
+
+ QVariant v = value;
+ if (value.type() == QVariant::Icon)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetIconValue());
+ else if (value.type() == QVariant::Pixmap)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue());
+ else if (value.type() == QVariant::String)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ else if (value.type() == QVariant::KeySequence)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue());
+
+
+ if (d->m_addIndex.contains(propName)) {
+ const int idx = d->m_addIndex.value(propName);
+ // have to be invisible, this was checked in canAddDynamicProperty() method
+ setVisible(idx, true);
+ d->m_addProperties.insert(idx, v);
+ setChanged(idx, false);
+ const int index = d->m_meta->indexOfProperty(propName);
+ Info &info = d->ensureInfo(index);
+ info.defaultValue = value;
+ info.kind = QDesignerPropertySheetPrivate::DynamicProperty;
+ if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap)
+ d->addResourceProperty(idx, value.type());
+ else if (value.type() == QVariant::String)
+ d->addStringProperty(idx);
+ else if (value.type() == QVariant::KeySequence)
+ d->addKeySequenceProperty(idx);
+ return idx;
+ }
+
+ const int index = count();
+ d->m_addIndex.insert(propName, index);
+ d->m_addProperties.insert(index, v);
+ Info &info = d->ensureInfo(index);
+ info.visible = true;
+ info.changed = false;
+ info.defaultValue = value;
+ info.kind = QDesignerPropertySheetPrivate::DynamicProperty;
+ setPropertyGroup(index, tr("Dynamic Properties"));
+ if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap)
+ d->addResourceProperty(index, value.type());
+ else if (value.type() == QVariant::String)
+ d->addStringProperty(index);
+ else if (value.type() == QVariant::KeySequence)
+ d->addKeySequenceProperty(index);
+ return index;
+}
+
+bool QDesignerPropertySheet::removeDynamicProperty(int index)
+{
+ if (!d->m_addIndex.contains(propertyName(index)))
+ return false;
+
+ setVisible(index, false);
+ return true;
+}
+
+bool QDesignerPropertySheet::isDynamic(int index) const
+{
+ if (!d->m_addProperties.contains(index))
+ return false;
+
+ switch (propertyType(index)) {
+ case PropertyBuddy:
+ if (d->m_objectType == ObjectLabel)
+ return false;
+ break;
+ case PropertyLayoutLeftMargin:
+ case PropertyLayoutTopMargin:
+ case PropertyLayoutRightMargin:
+ case PropertyLayoutBottomMargin:
+ case PropertyLayoutSpacing:
+ case PropertyLayoutHorizontalSpacing:
+ case PropertyLayoutVerticalSpacing:
+ case PropertyLayoutObjectName:
+ case PropertyLayoutSizeConstraint:
+ case PropertyLayoutFieldGrowthPolicy:
+ case PropertyLayoutRowWrapPolicy:
+ case PropertyLayoutLabelAlignment:
+ case PropertyLayoutFormAlignment:
+ case PropertyLayoutBoxStretch:
+ case PropertyLayoutGridRowStretch:
+ case PropertyLayoutGridColumnStretch:
+ case PropertyLayoutGridRowMinimumHeight:
+ case PropertyLayoutGridColumnMinimumWidth:
+ if (d->m_object->isWidgetType() && d->m_canHaveLayoutAttributes)
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool QDesignerPropertySheet::isDynamicProperty(int index) const
+{
+ // Do not complain here, as an invalid index might be encountered
+ // if someone implements a property sheet only, omitting the dynamic sheet.
+ if (index < 0 || index >= count())
+ return false;
+ return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DynamicProperty;
+}
+
+bool QDesignerPropertySheet::isDefaultDynamicProperty(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DefaultDynamicProperty;
+}
+
+bool QDesignerPropertySheet::isResourceProperty(int index) const
+{
+ return d->isResourceProperty(index);
+}
+
+QVariant QDesignerPropertySheet::defaultResourceProperty(int index) const
+{
+ return d->defaultResourceProperty(index);
+}
+
+qdesigner_internal::DesignerPixmapCache *QDesignerPropertySheet::pixmapCache() const
+{
+ return d->m_pixmapCache;
+}
+
+void QDesignerPropertySheet::setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache)
+{
+ d->m_pixmapCache = cache;
+}
+
+qdesigner_internal::DesignerIconCache *QDesignerPropertySheet::iconCache() const
+{
+ return d->m_iconCache;
+}
+
+void QDesignerPropertySheet::setIconCache(qdesigner_internal::DesignerIconCache *cache)
+{
+ d->m_iconCache = cache;
+}
+
+int QDesignerPropertySheet::createFakeProperty(const QString &propertyName, const QVariant &value)
+{
+ typedef QDesignerPropertySheetPrivate::Info Info;
+ // fake properties
+ const int index = d->m_meta->indexOfProperty(propertyName);
+ if (index != -1) {
+ if (!(d->m_meta->property(index)->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute))
+ return -1;
+ Info &info = d->ensureInfo(index);
+ info.visible = false;
+ info.kind = QDesignerPropertySheetPrivate::FakeProperty;
+ QVariant v = value.isValid() ? value : metaProperty(index);
+ if (v.type() == QVariant::String)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ if (v.type() == QVariant::KeySequence)
+ v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue());
+ d->m_fakeProperties.insert(index, v);
+ return index;
+ }
+ if (!value.isValid())
+ return -1;
+
+ const int newIndex = count();
+ d->m_addIndex.insert(propertyName, newIndex);
+ d->m_addProperties.insert(newIndex, value);
+ Info &info = d->ensureInfo(newIndex);
+ info.propertyType = propertyTypeFromName(propertyName);
+ info.kind = QDesignerPropertySheetPrivate::FakeProperty;
+ return newIndex;
+}
+
+bool QDesignerPropertySheet::isAdditionalProperty(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ return d->m_addProperties.contains(index);
+}
+
+bool QDesignerPropertySheet::isFakeProperty(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ // additional properties must be fake
+ return (d->m_fakeProperties.contains(index) || isAdditionalProperty(index));
+}
+
+int QDesignerPropertySheet::count() const
+{
+ return d->count();
+}
+
+int QDesignerPropertySheet::indexOf(const QString &name) const
+{
+ int index = d->m_meta->indexOfProperty(name);
+
+ if (index == -1)
+ index = d->m_addIndex.value(name, -1);
+
+ return index;
+}
+
+QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyType(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return PropertyNone;
+ return d->propertyType(index);
+}
+
+QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectType() const
+{
+ return d->m_objectType;
+}
+
+QString QDesignerPropertySheet::propertyName(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return QString();
+ if (isAdditionalProperty(index))
+ return d->m_addIndex.key(index);
+
+ return d->m_meta->property(index)->name();
+}
+
+QString QDesignerPropertySheet::propertyGroup(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return QString();
+ const QString g = d->m_info.value(index).group;
+
+ if (!g.isEmpty())
+ return g;
+
+ if (propertyType(index) == PropertyAccessibility)
+ return QString::fromUtf8("Accessibility");
+
+ if (isAdditionalProperty(index))
+ return d->m_meta->className();
+
+ return g;
+}
+
+void QDesignerPropertySheet::setPropertyGroup(int index, const QString &group)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return;
+ d->ensureInfo(index).group = group;
+}
+
+QVariant QDesignerPropertySheet::property(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return QVariant();
+ if (isAdditionalProperty(index)) {
+ if (isFakeLayoutProperty(index)) {
+ QDesignerPropertySheetExtension *layoutPropertySheet;
+ if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
+ const QString newPropName = d->transformLayoutPropertyName(index);
+ if (!newPropName.isEmpty()) {
+ const int newIndex = layoutPropertySheet->indexOf(newPropName);
+ if (newIndex != -1)
+ return layoutPropertySheet->property(newIndex);
+ return QVariant();
+ }
+ }
+ }
+ return d->m_addProperties.value(index);
+ }
+
+ if (isFakeProperty(index)) {
+ return d->m_fakeProperties.value(index);
+ }
+
+ if (d->isResourceProperty(index))
+ return d->resourceProperty(index);
+
+ if (d->isStringProperty(index)) {
+ QString strValue = metaProperty(index).toString();
+ qdesigner_internal::PropertySheetStringValue value = d->stringProperty(index);
+ if (strValue != value.value()) {
+ value.setValue(strValue);
+ d->setStringProperty(index, value); // cache it
+ }
+ return qVariantFromValue(value);
+ }
+
+ if (d->isKeySequenceProperty(index)) {
+ QKeySequence keyValue = qVariantValue<QKeySequence>(metaProperty(index));
+ qdesigner_internal::PropertySheetKeySequenceValue value = d->keySequenceProperty(index);
+ if (keyValue != value.value()) {
+ value.setValue(keyValue);
+ d->setKeySequenceProperty(index, value); // cache it
+ }
+ return qVariantFromValue(value);
+ }
+
+ return metaProperty(index);
+}
+
+QVariant QDesignerPropertySheet::metaProperty(int index) const
+{
+ Q_ASSERT(!isFakeProperty(index));
+
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ QVariant v = p->read(d->m_object);
+ switch (p->kind()) {
+ case QDesignerMetaPropertyInterface::FlagKind: {
+ qdesigner_internal::PropertySheetFlagValue psflags = qdesigner_internal::PropertySheetFlagValue(v.toInt(), designerMetaFlagsFor(p->enumerator()));
+ qVariantSetValue(v, psflags);
+ }
+ break;
+ case QDesignerMetaPropertyInterface::EnumKind: {
+ qdesigner_internal::PropertySheetEnumValue pse = qdesigner_internal::PropertySheetEnumValue(v.toInt(), designerMetaEnumFor(p->enumerator()));
+ qVariantSetValue(v, pse);
+ }
+ break;
+ case QDesignerMetaPropertyInterface::OtherKind:
+ break;
+ }
+ return v;
+}
+
+QVariant QDesignerPropertySheet::resolvePropertyValue(int index, const QVariant &value) const
+{
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetEnumValue>(value))
+ return qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(value).value;
+
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetFlagValue>(value))
+ return qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(value).value;
+
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetStringValue>(value))
+ return qVariantValue<qdesigner_internal::PropertySheetStringValue>(value).value();
+
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetKeySequenceValue>(value))
+ return qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value).value();
+
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(value)) {
+ const QString path = qVariantValue<qdesigner_internal::PropertySheetPixmapValue>(value).path();
+ if (path.isEmpty())
+ return defaultResourceProperty(index);
+ if (d->m_pixmapCache) {
+ return d->m_pixmapCache->pixmap(qvariant_cast<qdesigner_internal::PropertySheetPixmapValue>(value));
+ }
+ }
+
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(value)) {
+ const int pathCount = qVariantValue<qdesigner_internal::PropertySheetIconValue>(value).paths().count();
+ if (pathCount == 0)
+ return defaultResourceProperty(index);
+ if (d->m_iconCache)
+ return d->m_iconCache->icon(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(value));
+ }
+
+ return value;
+}
+
+void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value)
+{
+ Q_ASSERT(isFakeProperty(index));
+
+ QVariant &v = d->m_fakeProperties[index];
+
+ // set resource properties also (if we are going to have fake resource properties)
+ if (qVariantCanConvert<qdesigner_internal::PropertySheetFlagValue>(value) || qVariantCanConvert<qdesigner_internal::PropertySheetEnumValue>(value)) {
+ v = value;
+ } else if (qVariantCanConvert<qdesigner_internal::PropertySheetFlagValue>(v)) {
+ qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(v);
+ f.value = value.toInt();
+ qVariantSetValue(v, f);
+ Q_ASSERT(value.type() == QVariant::Int);
+ } else if (qVariantCanConvert<qdesigner_internal::PropertySheetEnumValue>(v)) {
+ qdesigner_internal::PropertySheetEnumValue e = qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(v);
+ e.value = value.toInt();
+ qVariantSetValue(v, e);
+ Q_ASSERT(value.type() == QVariant::Int);
+ } else {
+ v = value;
+ }
+}
+
+void QDesignerPropertySheet::clearFakeProperties()
+{
+ d->m_fakeProperties.clear();
+}
+
+// Buddy needs to be byte array, else uic won't work
+static QVariant toByteArray(const QVariant &value) {
+ if (value.type() == QVariant::ByteArray)
+ return value;
+ const QByteArray ba = value.toString().toUtf8();
+ return QVariant(ba);
+}
+
+void QDesignerPropertySheet::setProperty(int index, const QVariant &value)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return;
+ if (isAdditionalProperty(index)) {
+ if (d->m_objectType == ObjectLabel && propertyType(index) == PropertyBuddy) {
+ QFormBuilderExtra::applyBuddy(value.toString(), QFormBuilderExtra::BuddyApplyVisibleOnly, qobject_cast<QLabel *>(d->m_object));
+ d->m_addProperties[index] = toByteArray(value);
+ return;
+ }
+
+ if (isFakeLayoutProperty(index)) {
+ QDesignerPropertySheetExtension *layoutPropertySheet;
+ if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
+ const QString newPropName = d->transformLayoutPropertyName(index);
+ if (!newPropName.isEmpty()) {
+ const int newIndex = layoutPropertySheet->indexOf(newPropName);
+ if (newIndex != -1)
+ layoutPropertySheet->setProperty(newIndex, value);
+ }
+ }
+ }
+
+ if (isDynamicProperty(index)) {
+ if (d->isResourceProperty(index))
+ d->setResourceProperty(index, value);
+ if (d->isStringProperty(index))
+ d->setStringProperty(index, qVariantValue<qdesigner_internal::PropertySheetStringValue>(value));
+ if (d->isKeySequenceProperty(index))
+ d->setKeySequenceProperty(index, qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value));
+ d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value));
+ if (d->m_object->isWidgetType()) {
+ QWidget *w = qobject_cast<QWidget *>(d->m_object);
+ w->setStyleSheet(w->styleSheet());
+ }
+ }
+ d->m_addProperties[index] = value;
+ } else if (isFakeProperty(index)) {
+ setFakeProperty(index, value);
+ } else {
+ if (d->isResourceProperty(index))
+ d->setResourceProperty(index, value);
+ if (d->isStringProperty(index))
+ d->setStringProperty(index, qVariantValue<qdesigner_internal::PropertySheetStringValue>(value));
+ if (d->isKeySequenceProperty(index))
+ d->setKeySequenceProperty(index, qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value));
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ p->write(d->m_object, resolvePropertyValue(index, value));
+ if (qobject_cast<QGroupBox *>(d->m_object) && propertyType(index) == PropertyCheckable) {
+ const int idx = indexOf(QLatin1String("focusPolicy"));
+ if (!isChanged(idx)) {
+ qdesigner_internal::PropertySheetEnumValue e = qVariantValue<qdesigner_internal::PropertySheetEnumValue>(property(idx));
+ if (value.toBool()) {
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(idx);
+ p->write(d->m_object, Qt::NoFocus);
+ e.value = Qt::StrongFocus;
+ QVariant v;
+ qVariantSetValue(v, e);
+ setFakeProperty(idx, v);
+ } else {
+ e.value = Qt::NoFocus;
+ QVariant v;
+ qVariantSetValue(v, e);
+ setFakeProperty(idx, v);
+ }
+ }
+ }
+ }
+}
+
+bool QDesignerPropertySheet::hasReset(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ if (isAdditionalProperty(index))
+ return d->m_info.value(index).reset;
+ return true;
+}
+
+bool QDesignerPropertySheet::reset(int index)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ if (d->isStringProperty(index))
+ setProperty(index, qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+ if (d->isKeySequenceProperty(index))
+ setProperty(index, qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue()));
+ if (d->isResourceProperty(index)) {
+ setProperty(index, d->emptyResourceProperty(index));
+ return true;
+ } else if (isDynamic(index)) {
+ const QString propName = propertyName(index);
+ const QVariant oldValue = d->m_addProperties.value(index);
+ const QVariant newValue = d->m_info.value(index).defaultValue;
+ if (oldValue == newValue)
+ return true;
+ d->m_object->setProperty(propName.toUtf8(), newValue);
+ d->m_addProperties[index] = newValue;
+ return true;
+ } else if (!d->m_info.value(index).defaultValue.isNull()) {
+ setProperty(index, d->m_info.value(index).defaultValue);
+ return true;
+ }
+ if (isAdditionalProperty(index)) {
+ const PropertyType pType = propertyType(index);
+ if (d->m_objectType == ObjectLabel && pType == PropertyBuddy) {
+ setProperty(index, QVariant(QByteArray()));
+ return true;
+ }
+ if (isFakeLayoutProperty(index)) {
+ // special properties
+ switch (pType) {
+ case PropertyLayoutObjectName:
+ setProperty(index, QString());
+ return true;
+ case PropertyLayoutSizeConstraint:
+ setProperty(index, QVariant(QLayout::SetDefaultConstraint));
+ return true;
+ case PropertyLayoutBoxStretch:
+ case PropertyLayoutGridRowStretch:
+ case PropertyLayoutGridColumnStretch:
+ case PropertyLayoutGridRowMinimumHeight:
+ case PropertyLayoutGridColumnMinimumWidth:
+ case PropertyLayoutFieldGrowthPolicy:
+ case PropertyLayoutRowWrapPolicy:
+ case PropertyLayoutLabelAlignment:
+ case PropertyLayoutFormAlignment: {
+ QDesignerPropertySheetExtension *layoutPropertySheet;
+ if (d->layout(&layoutPropertySheet) && layoutPropertySheet)
+ return layoutPropertySheet->reset(layoutPropertySheet->indexOf(d->transformLayoutPropertyName(index)));
+ }
+ break;
+ default:
+ break;
+ }
+ // special margins
+ int value = -1;
+ switch (d->m_objectType) {
+ case ObjectQ3GroupBox: {
+ const QWidget *w = qobject_cast<const QWidget *>(d->m_object);
+ switch (pType) {
+ case PropertyLayoutLeftMargin:
+ value = w->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ break;
+ case PropertyLayoutTopMargin:
+ value = w->style()->pixelMetric(QStyle::PM_LayoutTopMargin);
+ break;
+ case PropertyLayoutRightMargin:
+ value = w->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
+ break;
+ case PropertyLayoutBottomMargin:
+ value = w->style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
+ break;
+ case PropertyLayoutSpacing:
+ case PropertyLayoutHorizontalSpacing:
+ case PropertyLayoutVerticalSpacing:
+ value = -1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case ObjectLayoutWidget:
+ if (pType == PropertyLayoutLeftMargin ||
+ pType == PropertyLayoutTopMargin ||
+ pType == PropertyLayoutRightMargin ||
+ pType == PropertyLayoutBottomMargin)
+ value = 0;
+ break;
+ default:
+ break;
+ }
+ setProperty(index, value);
+ return true;
+ }
+ return false;
+ } else if (isFakeProperty(index)) {
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ const bool result = p->reset(d->m_object);
+ d->m_fakeProperties[index] = p->read(d->m_object);
+ return result;
+ } else if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) {
+ if (QWidget *w = qobject_cast<QWidget*>(d->m_object)) {
+ QWidget *widget = w;
+ if (qdesigner_internal::Utils::isCentralWidget(d->m_fwb, widget) && d->m_fwb->parentWidget())
+ widget = d->m_fwb->parentWidget();
+
+ if (widget != w && widget->parentWidget()) {
+ QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ widget->parentWidget()->adjustSize();
+ }
+ QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+ widget->adjustSize();
+ return true;
+ }
+ }
+ // ### TODO: reset for fake properties.
+
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ return p->reset(d->m_object);
+}
+
+bool QDesignerPropertySheet::isChanged(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ if (isAdditionalProperty(index)) {
+ if (isFakeLayoutProperty(index)) {
+ QDesignerPropertySheetExtension *layoutPropertySheet;
+ if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
+ const QString newPropName = d->transformLayoutPropertyName(index);
+ if (!newPropName.isEmpty()) {
+ const int newIndex = layoutPropertySheet->indexOf(newPropName);
+ if (newIndex != -1)
+ return layoutPropertySheet->isChanged(newIndex);
+ return false;
+ }
+ }
+ }
+ }
+ return d->m_info.value(index).changed;
+}
+
+void QDesignerPropertySheet::setChanged(int index, bool changed)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return;
+ if (isAdditionalProperty(index)) {
+ if (isFakeLayoutProperty(index)) {
+ QDesignerPropertySheetExtension *layoutPropertySheet;
+ if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
+ const QString newPropName = d->transformLayoutPropertyName(index);
+ if (!newPropName.isEmpty()) {
+ const int newIndex = layoutPropertySheet->indexOf(newPropName);
+ if (newIndex != -1)
+ layoutPropertySheet->setChanged(newIndex, changed);
+ }
+ }
+ }
+ }
+ if (d->isReloadableProperty(index)) {
+ if (d->m_fwb) {
+ if (changed)
+ d->m_fwb->addReloadableProperty(this, index);
+ else
+ d->m_fwb->removeReloadableProperty(this, index);
+ }
+ }
+ d->ensureInfo(index).changed = changed;
+}
+
+bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const
+{
+ if (!isAdditionalProperty(index))
+ return false;
+
+ switch (propertyType(index)) {
+ case PropertyLayoutObjectName:
+ case PropertyLayoutSizeConstraint:
+ return true;
+ case PropertyLayoutLeftMargin:
+ case PropertyLayoutTopMargin:
+ case PropertyLayoutRightMargin:
+ case PropertyLayoutBottomMargin:
+ case PropertyLayoutSpacing:
+ case PropertyLayoutHorizontalSpacing:
+ case PropertyLayoutVerticalSpacing:
+ case PropertyLayoutFieldGrowthPolicy:
+ case PropertyLayoutRowWrapPolicy:
+ case PropertyLayoutLabelAlignment:
+ case PropertyLayoutFormAlignment:
+ case PropertyLayoutBoxStretch:
+ case PropertyLayoutGridRowStretch:
+ case PropertyLayoutGridColumnStretch:
+ case PropertyLayoutGridRowMinimumHeight:
+ case PropertyLayoutGridColumnMinimumWidth:
+ return d->m_canHaveLayoutAttributes;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QDesignerPropertySheet::isVisible(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+
+ const PropertyType type = propertyType(index);
+ if (isAdditionalProperty(index)) {
+ if (isFakeLayoutProperty(index) && d->m_object->isWidgetType()) {
+ const QLayout *currentLayout = d->layout();
+ if (!currentLayout)
+ return false;
+ const int visibleMask = qdesigner_internal::LayoutProperties::visibleProperties(currentLayout);
+ switch (type) {
+ case PropertyLayoutSpacing:
+ return visibleMask & qdesigner_internal::LayoutProperties::SpacingProperty;
+ case PropertyLayoutHorizontalSpacing:
+ case PropertyLayoutVerticalSpacing:
+ return visibleMask & qdesigner_internal::LayoutProperties::HorizSpacingProperty;
+ case PropertyLayoutFieldGrowthPolicy:
+ return visibleMask & qdesigner_internal::LayoutProperties::FieldGrowthPolicyProperty;
+ case PropertyLayoutRowWrapPolicy:
+ return visibleMask & qdesigner_internal::LayoutProperties::RowWrapPolicyProperty;
+ case PropertyLayoutLabelAlignment:
+ return visibleMask & qdesigner_internal::LayoutProperties::LabelAlignmentProperty;
+ case PropertyLayoutFormAlignment:
+ return visibleMask & qdesigner_internal::LayoutProperties::FormAlignmentProperty;
+ case PropertyLayoutBoxStretch:
+ return visibleMask & qdesigner_internal::LayoutProperties::BoxStretchProperty;
+ case PropertyLayoutGridRowStretch:
+ return visibleMask & qdesigner_internal::LayoutProperties::GridRowStretchProperty;
+ case PropertyLayoutGridColumnStretch:
+ return visibleMask & qdesigner_internal::LayoutProperties::GridColumnStretchProperty;
+ case PropertyLayoutGridRowMinimumHeight:
+ return visibleMask & qdesigner_internal::LayoutProperties::GridRowMinimumHeightProperty;
+ case PropertyLayoutGridColumnMinimumWidth:
+ return visibleMask & qdesigner_internal::LayoutProperties::GridColumnMinimumWidthProperty;
+ default:
+ break;
+ }
+ return true;
+ }
+ return d->m_info.value(index).visible;
+ }
+
+ if (isFakeProperty(index)) {
+ if (type == PropertyWindowModality) // Hidden for child widgets
+ return d->m_info.value(index).visible;
+ return true;
+ }
+
+ const bool visible = d->m_info.value(index).visible;
+ switch (type) {
+ case PropertyWindowTitle:
+ case PropertyWindowIcon:
+ case PropertyWindowFilePath:
+ case PropertyWindowOpacity:
+ case PropertyWindowIconText:
+ case PropertyWindowModified:
+ return visible;
+ default:
+ if (visible)
+ return true;
+ break;
+ }
+
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ if (!(p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess))
+ return false;
+
+ // Enabled handling
+ return (p->attributes(d->m_object) & QDesignerMetaPropertyInterface::DesignableAttribute) ||
+ (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute);
+}
+
+void QDesignerPropertySheet::setVisible(int index, bool visible)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return;
+ d->ensureInfo(index).visible = visible;
+}
+
+bool QDesignerPropertySheet::isEnabled(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ if (isAdditionalProperty(index))
+ return true;
+
+ if (isFakeProperty(index))
+ return true;
+
+ // Grey out geometry of laid-out widgets (including splitter)
+ if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) {
+ bool isManaged;
+ const qdesigner_internal::LayoutInfo::Type lt = qdesigner_internal::LayoutInfo::laidoutWidgetType(d->m_core, qobject_cast<QWidget *>(d->m_object), &isManaged);
+ return !isManaged || lt == qdesigner_internal::LayoutInfo::NoLayout;
+ }
+
+ if (d->m_info.value(index).visible == true) // Sun CC 5.5 oddity, wants true
+ return true;
+
+ const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+ return (p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess) &&
+ (p->attributes(d->m_object) & QDesignerMetaPropertyInterface::DesignableAttribute);
+}
+
+bool QDesignerPropertySheet::isAttribute(int index) const
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return false;
+ if (isAdditionalProperty(index))
+ return d->m_info.value(index).attribute;
+
+ if (isFakeProperty(index))
+ return false;
+
+ return d->m_info.value(index).attribute;
+}
+
+void QDesignerPropertySheet::setAttribute(int index, bool attribute)
+{
+ if (d->invalidIndex(Q_FUNC_INFO, index))
+ return;
+ d->ensureInfo(index).attribute = attribute;
+}
+
+QDesignerFormEditorInterface *QDesignerPropertySheet::core() const
+{
+ return d->m_core;
+}
+
+bool QDesignerPropertySheet::internalDynamicPropertiesEnabled()
+{
+ return QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled;
+}
+
+void QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(bool v)
+{
+ QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = v;
+}
+
+// ---------- QDesignerAbstractPropertySheetFactory
+
+struct QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate {
+ PropertySheetFactoryPrivate();
+ const QString m_propertySheetId;
+ const QString m_dynamicPropertySheetId;
+
+ typedef QMap<QObject*, QObject*> ExtensionMap;
+ ExtensionMap m_extensions;
+ typedef QHash<QObject*, bool> ExtendedSet;
+ ExtendedSet m_extended;
+};
+
+QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate::PropertySheetFactoryPrivate() :
+ m_propertySheetId(Q_TYPEID(QDesignerPropertySheetExtension)),
+ m_dynamicPropertySheetId(Q_TYPEID(QDesignerDynamicPropertySheetExtension))
+{
+}
+
+// ---------- QDesignerAbstractPropertySheetFactory
+
+
+QDesignerAbstractPropertySheetFactory::QDesignerAbstractPropertySheetFactory(QExtensionManager *parent) :
+ QExtensionFactory(parent),
+ m_impl(new PropertySheetFactoryPrivate)
+{
+}
+
+QDesignerAbstractPropertySheetFactory::~QDesignerAbstractPropertySheetFactory()
+{
+ delete m_impl;
+}
+
+QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const QString &iid) const
+{
+ typedef PropertySheetFactoryPrivate::ExtensionMap ExtensionMap;
+ if (!object)
+ return 0;
+
+ if (iid != m_impl->m_propertySheetId && iid != m_impl->m_dynamicPropertySheetId)
+ return 0;
+
+ ExtensionMap::iterator it = m_impl->m_extensions.find(object);
+ if (it == m_impl->m_extensions.end()) {
+ if (QObject *ext = createPropertySheet(object, const_cast<QDesignerAbstractPropertySheetFactory*>(this))) {
+ connect(ext, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
+ it = m_impl->m_extensions.insert(object, ext);
+ }
+ }
+
+ if (!m_impl->m_extended.contains(object)) {
+ connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
+ m_impl->m_extended.insert(object, true);
+ }
+
+ if (it == m_impl->m_extensions.end())
+ return 0;
+
+ return it.value();
+}
+
+void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object)
+{
+ QMutableMapIterator<QObject*, QObject*> it(m_impl->m_extensions);
+ while (it.hasNext()) {
+ it.next();
+
+ QObject *o = it.key();
+ if (o == object || object == it.value()) {
+ it.remove();
+ }
+ }
+
+ m_impl->m_extended.remove(object);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h b/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h
new file mode 100644
index 0000000..8a25baf
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_PROPERTYSHEET_H
+#define QDESIGNER_PROPERTYSHEET_H
+
+#include "shared_global_p.h"
+#include "dynamicpropertysheet.h"
+#include <QtDesigner/propertysheet.h>
+#include <QtDesigner/default_extensionfactory.h>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QVariant>
+#include <QtCore/QPair>
+
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QLayout;
+class QDesignerFormEditorInterface;
+class QDesignerPropertySheetPrivate;
+
+namespace qdesigner_internal
+{
+ class DesignerPixmapCache;
+ class DesignerIconCache;
+ class FormWindowBase;
+}
+
+class QDESIGNER_SHARED_EXPORT QDesignerPropertySheet: public QObject, public QDesignerPropertySheetExtension, public QDesignerDynamicPropertySheetExtension
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerPropertySheetExtension QDesignerDynamicPropertySheetExtension)
+public:
+ explicit QDesignerPropertySheet(QObject *object, QObject *parent = 0);
+ virtual ~QDesignerPropertySheet();
+
+ virtual int indexOf(const QString &name) const;
+
+ virtual int count() const;
+ virtual QString propertyName(int index) const;
+
+ virtual QString propertyGroup(int index) const;
+ virtual void setPropertyGroup(int index, const QString &group);
+
+ virtual bool hasReset(int index) const;
+ virtual bool reset(int index);
+
+ virtual bool isAttribute(int index) const;
+ virtual void setAttribute(int index, bool b);
+
+ virtual bool isVisible(int index) const;
+ virtual void setVisible(int index, bool b);
+
+ virtual QVariant property(int index) const;
+ virtual void setProperty(int index, const QVariant &value);
+
+ virtual bool isChanged(int index) const;
+
+ virtual void setChanged(int index, bool changed);
+
+ virtual bool dynamicPropertiesAllowed() const;
+ virtual int addDynamicProperty(const QString &propertyName, const QVariant &value);
+ virtual bool removeDynamicProperty(int index);
+ virtual bool isDynamicProperty(int index) const;
+ virtual bool canAddDynamicProperty(const QString &propertyName) const;
+
+ bool isDefaultDynamicProperty(int index) const;
+
+ bool isResourceProperty(int index) const;
+ QVariant defaultResourceProperty(int index) const;
+
+ qdesigner_internal::DesignerPixmapCache *pixmapCache() const;
+ void setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache);
+ qdesigner_internal::DesignerIconCache *iconCache() const;
+ void setIconCache(qdesigner_internal::DesignerIconCache *cache);
+ int createFakeProperty(const QString &propertyName, const QVariant &value = QVariant());
+
+ virtual bool isEnabled(int index) const;
+ QObject *object() const;
+
+ static bool internalDynamicPropertiesEnabled();
+ static void setInternalDynamicPropertiesEnabled(bool v);
+
+protected:
+ bool isAdditionalProperty(int index) const;
+ bool isFakeProperty(int index) const;
+ QVariant resolvePropertyValue(int index, const QVariant &value) const;
+ QVariant metaProperty(int index) const;
+ void setFakeProperty(int index, const QVariant &value);
+ void clearFakeProperties();
+
+ bool isFakeLayoutProperty(int index) const;
+ bool isDynamic(int index) const;
+ qdesigner_internal::FormWindowBase *formWindowBase() const;
+ QDesignerFormEditorInterface *core() const;
+
+public:
+ enum PropertyType { PropertyNone,
+ PropertyLayoutObjectName,
+ PropertyLayoutLeftMargin,
+ PropertyLayoutTopMargin,
+ PropertyLayoutRightMargin,
+ PropertyLayoutBottomMargin,
+ PropertyLayoutSpacing,
+ PropertyLayoutHorizontalSpacing,
+ PropertyLayoutVerticalSpacing,
+ PropertyLayoutSizeConstraint,
+ PropertyLayoutFieldGrowthPolicy,
+ PropertyLayoutRowWrapPolicy,
+ PropertyLayoutLabelAlignment,
+ PropertyLayoutFormAlignment,
+ PropertyLayoutBoxStretch,
+ PropertyLayoutGridRowStretch,
+ PropertyLayoutGridColumnStretch,
+ PropertyLayoutGridRowMinimumHeight,
+ PropertyLayoutGridColumnMinimumWidth,
+ PropertyBuddy,
+ PropertyAccessibility,
+ PropertyGeometry,
+ PropertyCheckable,
+ PropertyWindowTitle,
+ PropertyWindowIcon,
+ PropertyWindowFilePath,
+ PropertyWindowOpacity,
+ PropertyWindowIconText,
+ PropertyWindowModality,
+ PropertyWindowModified,
+ PropertyStyleSheet
+ };
+
+ enum ObjectType { ObjectNone, ObjectLabel, ObjectLayout, ObjectLayoutWidget, ObjectQ3GroupBox };
+
+ static ObjectType objectTypeFromObject(const QObject *o);
+ static PropertyType propertyTypeFromName(const QString &name);
+
+protected:
+ PropertyType propertyType(int index) const;
+ ObjectType objectType() const;
+
+private:
+ QDesignerPropertySheetPrivate *d;
+};
+
+/* Abstract base class for factories that register a property sheet that implements
+ * both QDesignerPropertySheetExtension and QDesignerDynamicPropertySheetExtension
+ * by multiple inheritance. The factory maintains ownership of
+ * the extension and returns it for both id's. */
+
+class QDESIGNER_SHARED_EXPORT QDesignerAbstractPropertySheetFactory: public QExtensionFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(QAbstractExtensionFactory)
+public:
+ explicit QDesignerAbstractPropertySheetFactory(QExtensionManager *parent = 0);
+ virtual ~QDesignerAbstractPropertySheetFactory();
+
+ QObject *extension(QObject *object, const QString &iid) const;
+
+private slots:
+ void objectDestroyed(QObject *object);
+
+private:
+ virtual QObject *createPropertySheet(QObject *qObject, QObject *parent) const = 0;
+
+ struct PropertySheetFactoryPrivate;
+ PropertySheetFactoryPrivate *m_impl;
+};
+
+/* Convenience factory template for property sheets that implement
+ * QDesignerPropertySheetExtension and QDesignerDynamicPropertySheetExtension
+ * by multiple inheritance. */
+
+template <class Object, class PropertySheet>
+class QDesignerPropertySheetFactory : public QDesignerAbstractPropertySheetFactory {
+public:
+ explicit QDesignerPropertySheetFactory(QExtensionManager *parent = 0);
+
+ static void registerExtension(QExtensionManager *mgr);
+
+private:
+ // Does a qobject_cast on the object.
+ virtual QObject *createPropertySheet(QObject *qObject, QObject *parent) const;
+};
+
+template <class Object, class PropertySheet>
+QDesignerPropertySheetFactory<Object, PropertySheet>::QDesignerPropertySheetFactory(QExtensionManager *parent) :
+ QDesignerAbstractPropertySheetFactory(parent)
+{
+}
+
+template <class Object, class PropertySheet>
+QObject *QDesignerPropertySheetFactory<Object, PropertySheet>::createPropertySheet(QObject *qObject, QObject *parent) const
+{
+ Object *object = qobject_cast<Object *>(qObject);
+ if (!object)
+ return 0;
+ return new PropertySheet(object, parent);
+}
+
+template <class Object, class PropertySheet>
+void QDesignerPropertySheetFactory<Object, PropertySheet>::registerExtension(QExtensionManager *mgr)
+{
+ QDesignerPropertySheetFactory *factory = new QDesignerPropertySheetFactory(mgr);
+ mgr->registerExtensions(factory, Q_TYPEID(QDesignerPropertySheetExtension));
+ mgr->registerExtensions(factory, Q_TYPEID(QDesignerDynamicPropertySheetExtension));
+}
+
+
+// Standard property sheet
+typedef QDesignerPropertySheetFactory<QObject, QDesignerPropertySheet> QDesignerDefaultPropertySheetFactory;
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_PROPERTYSHEET_H
diff --git a/tools/designer/src/lib/shared/qdesigner_qsettings.cpp b/tools/designer/src/lib/shared/qdesigner_qsettings.cpp
new file mode 100644
index 0000000..efea643
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_qsettings.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qdesigner_qsettings_p.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTextStream>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+
+/*!
+ \class QDesignerSettingsSimple
+
+ \brief Implements QDesignerSettingsInterface by calls to QSettings
+ */
+
+QDesignerQSettings::QDesignerQSettings() :
+ m_settings(qApp->organizationName(), settingsApplicationName())
+{
+}
+
+QString QDesignerQSettings::settingsApplicationName()
+{
+ return qApp->applicationName();
+}
+
+void QDesignerQSettings::beginGroup(const QString &prefix)
+{
+ m_settings.beginGroup(prefix);
+}
+
+void QDesignerQSettings::endGroup()
+{
+ m_settings.endGroup();
+}
+
+bool QDesignerQSettings::contains(const QString &key) const
+{
+ return m_settings.contains(key);
+}
+
+void QDesignerQSettings::setValue(const QString &key, const QVariant &value)
+{
+ m_settings.setValue(key, value);
+}
+
+QVariant QDesignerQSettings::value(const QString &key, const QVariant &defaultValue) const
+{
+ return m_settings.value(key, defaultValue);
+}
+
+void QDesignerQSettings::remove(const QString &key)
+{
+ m_settings.remove(key);
+}
diff --git a/tools/designer/src/lib/shared/qdesigner_qsettings_p.h b/tools/designer/src/lib/shared/qdesigner_qsettings_p.h
new file mode 100644
index 0000000..2ca749b
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_qsettings_p.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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_QSETTINGS_H
+#define QDESIGNER_QSETTINGS_H
+
+#include "abstractsettings_p.h"
+#include "shared_global_p.h"
+
+#include <QtCore/QSettings>
+
+QT_BEGIN_NAMESPACE
+
+// Implements QDesignerSettingsInterface by calls to QSettings
+class QDESIGNER_SHARED_EXPORT QDesignerQSettings : public QDesignerSettingsInterface
+{
+public:
+ QDesignerQSettings();
+
+ virtual void beginGroup(const QString &prefix);
+ virtual void endGroup();
+
+ virtual bool contains(const QString &key) const;
+ virtual void setValue(const QString &key, const QVariant &value);
+ virtual QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+ virtual void remove(const QString &key);
+
+ // The application name to be used for settings. Allows for including
+ // the Qt version to prevent settings of different Qt versions from
+ // interfering.
+ static QString settingsApplicationName();
+
+private:
+ QSettings m_settings;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_QSETTINGS_H
diff --git a/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp b/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp
new file mode 100644
index 0000000..c36ab9a
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp
@@ -0,0 +1,396 @@
+/****************************************************************************
+**
+** 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_stackedbox_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "orderdialog_p.h"
+#include "promotiontaskmenu_p.h"
+#include "widgetfactory_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QToolButton>
+#include <QtGui/QAction>
+#include <QtGui/qevent.h>
+#include <QtGui/QMenu>
+#include <QtGui/QStackedWidget>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static QToolButton *createToolButton(QWidget *parent, Qt::ArrowType at, const QString &name) {
+ QToolButton *rc = new QToolButton();
+ rc->setAttribute(Qt::WA_NoChildEventsForParent, true);
+ rc->setParent(parent);
+ rc->setObjectName(name);
+ rc->setArrowType(at);
+ rc->setAutoRaise(true);
+ rc->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ rc->setFixedSize(QSize(15, 15));
+ return rc;
+}
+
+// --------------- QStackedWidgetPreviewEventFilter
+QStackedWidgetPreviewEventFilter::QStackedWidgetPreviewEventFilter(QStackedWidget *parent) :
+ QObject(parent),
+ m_buttonToolTipEnabled(false), // Not on preview
+ m_stackedWidget(parent),
+ m_prev(createToolButton(m_stackedWidget, Qt::LeftArrow, QLatin1String("__qt__passive_prev"))),
+ m_next(createToolButton(m_stackedWidget, Qt::RightArrow, QLatin1String("__qt__passive_next")))
+{
+ connect(m_prev, SIGNAL(clicked()), this, SLOT(prevPage()));
+ connect(m_next, SIGNAL(clicked()), this, SLOT(nextPage()));
+
+ updateButtons();
+ m_stackedWidget->installEventFilter(this);
+ m_prev->installEventFilter(this);
+ m_next->installEventFilter(this);
+}
+
+void QStackedWidgetPreviewEventFilter::install(QStackedWidget *stackedWidget)
+{
+ new QStackedWidgetPreviewEventFilter(stackedWidget);
+}
+
+void QStackedWidgetPreviewEventFilter::updateButtons()
+{
+ m_prev->move(m_stackedWidget->width() - 31, 1);
+ m_prev->show();
+ m_prev->raise();
+
+ m_next->move(m_stackedWidget->width() - 16, 1);
+ m_next->show();
+ m_next->raise();
+}
+
+void QStackedWidgetPreviewEventFilter::prevPage()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ fw->clearSelection();
+ fw->selectWidget(stackedWidget(), true);
+ }
+ const int count = m_stackedWidget->count();
+ if (count > 1) {
+ int newIndex = m_stackedWidget->currentIndex() - 1;
+ if (newIndex < 0)
+ newIndex = count - 1;
+ gotoPage(newIndex);
+ }
+}
+
+void QStackedWidgetPreviewEventFilter::nextPage()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ fw->clearSelection();
+ fw->selectWidget(stackedWidget(), true);
+ }
+ const int count = m_stackedWidget->count();
+ if (count > 1)
+ gotoPage((m_stackedWidget->currentIndex() + 1) % count);
+}
+
+bool QStackedWidgetPreviewEventFilter::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched->isWidgetType()) {
+ if (watched == m_stackedWidget) {
+ switch (event->type()) {
+ case QEvent::LayoutRequest:
+ updateButtons();
+ break;
+ case QEvent::ChildAdded:
+ case QEvent::ChildRemoved:
+ case QEvent::Resize:
+ case QEvent::Show:
+ updateButtons();
+ break;
+ default:
+ break;
+ }
+ }
+ if (m_buttonToolTipEnabled && (watched == m_next || watched == m_prev)) {
+ switch (event->type()) {
+ case QEvent::ToolTip:
+ updateButtonToolTip(watched); // Tooltip includes page number, so, refresh on demand
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+void QStackedWidgetPreviewEventFilter::gotoPage(int page)
+{
+ m_stackedWidget->setCurrentIndex(page);
+ updateButtons();
+}
+
+static inline QString stackedClassName(QStackedWidget *w)
+{
+ if (const QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w))
+ return qdesigner_internal::WidgetFactory::classNameOf(fw->core(), w);
+ return QLatin1String("Stacked widget");
+}
+
+void QStackedWidgetPreviewEventFilter::updateButtonToolTip(QObject *o)
+{
+ QString className = QLatin1String("Stacked widget");
+ if (const QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_stackedWidget))
+ className = qdesigner_internal::WidgetFactory::classNameOf(fw->core(), m_stackedWidget);
+ if (o == m_prev) {
+ const QString msg = tr("Go to previous page of %1 '%2' (%3/%4).").arg(stackedClassName(m_stackedWidget)).arg(m_stackedWidget->objectName()).arg(m_stackedWidget->currentIndex() + 1).arg(m_stackedWidget->count());
+ m_prev->setToolTip(msg);
+ } else {
+ if (o == m_next) {
+ const QString msg = tr("Go to next page of %1 '%2' (%3/%4).").arg(stackedClassName(m_stackedWidget)).arg(m_stackedWidget->objectName()).arg(m_stackedWidget->currentIndex() + 1).arg(m_stackedWidget->count());
+ m_next->setToolTip(msg);
+ }
+ }
+}
+
+// --------------- QStackedWidgetEventFilter
+QStackedWidgetEventFilter::QStackedWidgetEventFilter(QStackedWidget *parent) :
+ QStackedWidgetPreviewEventFilter(parent),
+ m_actionPreviousPage(new QAction(tr("Previous Page"), this)),
+ m_actionNextPage(new QAction(tr("Next Page"), this)),
+ m_actionDeletePage(new QAction(tr("Delete"), this)),
+ m_actionInsertPage(new QAction(tr("Before Current Page"), this)),
+ m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)),
+ m_actionChangePageOrder(new QAction(tr("Change Page Order..."), this)),
+ m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
+{
+ setButtonToolTipEnabled(true);
+ connect(m_actionPreviousPage, SIGNAL(triggered()), this, SLOT(prevPage()));
+ connect(m_actionNextPage, SIGNAL(triggered()), this, SLOT(nextPage()));
+ connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage()));
+ connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage()));
+ connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter()));
+ connect(m_actionChangePageOrder, SIGNAL(triggered()), this, SLOT(changeOrder()));
+}
+
+void QStackedWidgetEventFilter::install(QStackedWidget *stackedWidget)
+{
+ new QStackedWidgetEventFilter(stackedWidget);
+}
+
+QStackedWidgetEventFilter *QStackedWidgetEventFilter::eventFilterOf(const QStackedWidget *stackedWidget)
+{
+ // Look for 1st order children only..otherwise, we might get filters of nested widgets
+ const QObjectList children = stackedWidget->children();
+ const QObjectList::const_iterator cend = children.constEnd();
+ for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
+ QObject *o = *it;
+ if (!o->isWidgetType())
+ if (QStackedWidgetEventFilter *ef = qobject_cast<QStackedWidgetEventFilter *>(o))
+ return ef;
+ }
+ return 0;
+}
+
+QMenu *QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(const QStackedWidget *stackedWidget, QMenu *popup)
+{
+ QStackedWidgetEventFilter *filter = eventFilterOf(stackedWidget);
+ if (!filter)
+ return 0;
+ return filter->addContextMenuActions(popup);
+}
+
+void QStackedWidgetEventFilter::removeCurrentPage()
+{
+ if (stackedWidget()->currentIndex() == -1)
+ return;
+
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ qdesigner_internal::DeleteStackedWidgetPageCommand *cmd = new qdesigner_internal::DeleteStackedWidgetPageCommand(fw);
+ cmd->init(stackedWidget());
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QStackedWidgetEventFilter::changeOrder()
+{
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget());
+
+ if (!fw)
+ return;
+
+ const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(fw->core(), stackedWidget());
+ const int pageCount = oldPages.size();
+ if (pageCount < 2)
+ return;
+
+ qdesigner_internal::OrderDialog dlg(fw);
+ dlg.setPageList(oldPages);
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ const QWidgetList newPages = dlg.pageList();
+ if (newPages == oldPages)
+ return;
+
+ fw->beginCommand(tr("Change Page Order"));
+ for(int i=0; i < pageCount; ++i) {
+ if (newPages.at(i) == stackedWidget()->widget(i))
+ continue;
+ qdesigner_internal::MoveStackedWidgetCommand *cmd = new qdesigner_internal::MoveStackedWidgetCommand(fw);
+ cmd->init(stackedWidget(), newPages.at(i), i);
+ fw->commandHistory()->push(cmd);
+ }
+ fw->endCommand();
+}
+
+void QStackedWidgetEventFilter::addPage()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw);
+ cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertBefore);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QStackedWidgetEventFilter::addPageAfter()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw);
+ cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertAfter);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QStackedWidgetEventFilter::gotoPage(int page) {
+ // Are we on a form or in a preview?
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
+ qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw);
+ cmd->init(stackedWidget(), QLatin1String("currentIndex"), page);
+ fw->commandHistory()->push(cmd);
+ fw->emitSelectionChanged(); // Magically prevent an endless loop triggered by auto-repeat.
+ updateButtons();
+ } else {
+ QStackedWidgetPreviewEventFilter::gotoPage(page);
+ }
+}
+
+QMenu *QStackedWidgetEventFilter::addContextMenuActions(QMenu *popup)
+{
+ QMenu *pageMenu = 0;
+ const int count = stackedWidget()->count();
+ const bool hasSeveralPages = count > 1;
+ m_actionDeletePage->setEnabled(hasSeveralPages);
+ if (count) {
+ const QString pageSubMenuLabel = tr("Page %1 of %2").arg(stackedWidget()->currentIndex() + 1).arg(count);
+ pageMenu = popup->addMenu(pageSubMenuLabel);
+ pageMenu->addAction(m_actionDeletePage);
+ // Set up promotion menu for current widget.
+ if (QWidget *page = stackedWidget()->currentWidget ()) {
+ m_pagePromotionTaskMenu->setWidget(page);
+ m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(stackedWidget()),
+ qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
+ pageMenu);
+ }
+ }
+ QMenu *insertPageMenu = popup->addMenu(tr("Insert Page"));
+ insertPageMenu->addAction(m_actionInsertPageAfter);
+ insertPageMenu->addAction(m_actionInsertPage);
+ popup->addAction(m_actionNextPage);
+ m_actionNextPage->setEnabled(hasSeveralPages);
+ popup->addAction(m_actionPreviousPage);
+ m_actionPreviousPage->setEnabled(hasSeveralPages);
+ popup->addAction(m_actionChangePageOrder);
+ m_actionChangePageOrder->setEnabled(hasSeveralPages);
+ popup->addSeparator();
+ return pageMenu;
+}
+
+// -------- QStackedWidgetPropertySheet
+
+static const char *pagePropertyName = "currentPageName";
+
+QStackedWidgetPropertySheet::QStackedWidgetPropertySheet(QStackedWidget *object, QObject *parent) :
+ QDesignerPropertySheet(object, parent),
+ m_stackedWidget(object)
+{
+ createFakeProperty(QLatin1String(pagePropertyName), QString());
+}
+
+bool QStackedWidgetPropertySheet::isEnabled(int index) const
+{
+ if (propertyName(index) != QLatin1String(pagePropertyName))
+ return QDesignerPropertySheet::isEnabled(index);
+ return m_stackedWidget->currentWidget() != 0;
+}
+
+void QStackedWidgetPropertySheet::setProperty(int index, const QVariant &value)
+{
+ if (propertyName(index) == QLatin1String(pagePropertyName)) {
+ if (QWidget *w = m_stackedWidget->currentWidget())
+ w->setObjectName(value.toString());
+ } else {
+ QDesignerPropertySheet::setProperty(index, value);
+ }
+}
+
+QVariant QStackedWidgetPropertySheet::property(int index) const
+{
+ if (propertyName(index) == QLatin1String(pagePropertyName)) {
+ if (const QWidget *w = m_stackedWidget->currentWidget())
+ return w->objectName();
+ return QString();
+ }
+ return QDesignerPropertySheet::property(index);
+}
+
+bool QStackedWidgetPropertySheet::reset(int index)
+{
+ if (propertyName(index) == QLatin1String(pagePropertyName)) {
+ setProperty(index, QString());
+ return true;
+ }
+ return QDesignerPropertySheet::reset(index);
+}
+
+bool QStackedWidgetPropertySheet::checkProperty(const QString &propertyName)
+{
+ return propertyName != QLatin1String(pagePropertyName);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_stackedbox_p.h b/tools/designer/src/lib/shared/qdesigner_stackedbox_p.h
new file mode 100644
index 0000000..a48dd94
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_stackedbox_p.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_STACKEDBOX_H
+#define QDESIGNER_STACKEDBOX_H
+
+#include "shared_global_p.h"
+#include "qdesigner_propertysheet_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QStackedWidget;
+class QWidget;
+class QAction;
+class QMenu;
+class QToolButton;
+
+namespace qdesigner_internal {
+ class PromotionTaskMenu;
+}
+
+// Event filter to be installed on a QStackedWidget in preview mode.
+// Create two buttons to switch pages.
+
+class QDESIGNER_SHARED_EXPORT QStackedWidgetPreviewEventFilter : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QStackedWidgetPreviewEventFilter(QStackedWidget *parent);
+
+ // Install helper on QStackedWidget
+ static void install(QStackedWidget *stackedWidget);
+ bool eventFilter(QObject *watched, QEvent *event);
+
+ void setButtonToolTipEnabled(bool v) { m_buttonToolTipEnabled = v; }
+ bool buttonToolTipEnabled() const { return m_buttonToolTipEnabled; }
+
+public slots:
+ void updateButtons();
+ void prevPage();
+ void nextPage();
+
+protected:
+ QStackedWidget *stackedWidget() const { return m_stackedWidget; }
+ virtual void gotoPage(int page);
+
+private:
+ void updateButtonToolTip(QObject *o);
+
+ bool m_buttonToolTipEnabled;
+ QStackedWidget *m_stackedWidget;
+ QToolButton *m_prev;
+ QToolButton *m_next;
+};
+
+// Event filter to be installed on a QStackedWidget in editing mode.
+// In addition to the browse buttons, handles context menu and everything
+
+class QDESIGNER_SHARED_EXPORT QStackedWidgetEventFilter : public QStackedWidgetPreviewEventFilter
+{
+ Q_OBJECT
+public:
+ explicit QStackedWidgetEventFilter(QStackedWidget *parent);
+
+ // Install helper on QStackedWidget
+ static void install(QStackedWidget *stackedWidget);
+ static QStackedWidgetEventFilter *eventFilterOf(const QStackedWidget *stackedWidget);
+ // Convenience to add a menu on a tackedWidget
+ static QMenu *addStackedWidgetContextMenuActions(const QStackedWidget *stackedWidget, QMenu *popup);
+
+ // Add context menu and return page submenu or 0.
+ QMenu *addContextMenuActions(QMenu *popup);
+
+private slots:
+ void removeCurrentPage();
+ void addPage();
+ void addPageAfter();
+ void changeOrder();
+
+protected:
+ virtual void gotoPage(int page);
+
+private:
+ QAction *m_actionPreviousPage;
+ QAction *m_actionNextPage;
+ QAction *m_actionDeletePage;
+ QAction *m_actionInsertPage;
+ QAction *m_actionInsertPageAfter;
+ QAction *m_actionChangePageOrder;
+ qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu;
+};
+
+// PropertySheet to handle the "currentPageName" property
+class QDESIGNER_SHARED_EXPORT QStackedWidgetPropertySheet : public QDesignerPropertySheet {
+public:
+ explicit QStackedWidgetPropertySheet(QStackedWidget *object, QObject *parent = 0);
+
+ virtual void setProperty(int index, const QVariant &value);
+ virtual QVariant property(int index) const;
+ virtual bool reset(int index);
+ virtual bool isEnabled(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:
+ QStackedWidget *m_stackedWidget;
+};
+
+typedef QDesignerPropertySheetFactory<QStackedWidget, QStackedWidgetPropertySheet> QStackedWidgetPropertySheetFactory;
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_STACKEDBOX_H
diff --git a/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp b/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp
new file mode 100644
index 0000000..903b066
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp
@@ -0,0 +1,567 @@
+/****************************************************************************
+**
+** 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_tabwidget_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "promotiontaskmenu_p.h"
+#include "formwindowbase_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QApplication>
+#include <QtGui/QTabBar>
+#include <QtGui/QAction>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QLabel>
+#include <QtGui/QTabWidget>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+// Store tab widget as drag source
+class MyMimeData : public QMimeData
+{
+ Q_OBJECT
+public:
+ MyMimeData(const QTabWidget *tab) : m_tab(tab) {}
+ static bool fromMyTab(const QMimeData *mimeData, const QTabWidget *tab) {
+ if (!mimeData)
+ return false;
+ const MyMimeData *m = qobject_cast<const MyMimeData *>(mimeData);
+ return m && m->m_tab == tab;
+ }
+private:
+ const QTabWidget *m_tab;
+};
+
+} // namespace qdesigner_internal
+
+// ------------- QTabWidgetEventFilter
+
+QTabWidgetEventFilter::QTabWidgetEventFilter(QTabWidget *parent) :
+ QObject(parent),
+ m_tabWidget(parent),
+ m_dropIndicator(0),
+ m_dragPage(0),
+ m_mousePressed(false),
+ m_actionDeletePage(new QAction(tr("Delete"), this)),
+ m_actionInsertPage(new QAction(tr("Before Current Page"), this)),
+ m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)),
+ m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
+{
+ tabBar()->setAcceptDrops(true);
+ tabBar()->installEventFilter(this);
+
+ connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage()));
+ connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter()));
+ connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage()));
+}
+
+QTabWidgetEventFilter::~QTabWidgetEventFilter()
+{
+}
+
+void QTabWidgetEventFilter::install(QTabWidget *tabWidget)
+{
+ new QTabWidgetEventFilter(tabWidget);
+}
+
+QTabWidgetEventFilter *QTabWidgetEventFilter::eventFilterOf(const QTabWidget *tabWidget)
+{
+ // Look for 1st order children only..otherwise, we might get filters of nested tab widgets
+ const QObjectList children = tabWidget->children();
+ const QObjectList::const_iterator cend = children.constEnd();
+ for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
+ QObject *o = *it;
+ if (!o->isWidgetType())
+ if (QTabWidgetEventFilter *ef = qobject_cast<QTabWidgetEventFilter*>(o))
+ return ef;
+ }
+ return 0;
+}
+
+QMenu *QTabWidgetEventFilter::addTabWidgetContextMenuActions(const QTabWidget *tabWidget, QMenu *popup)
+{
+ QTabWidgetEventFilter *filter = eventFilterOf(tabWidget);
+ if (!filter)
+ return 0;
+ return filter->addContextMenuActions(popup);
+}
+
+QTabBar *QTabWidgetEventFilter::tabBar() const
+{
+ // QTabWidget::tabBar() accessor is protected, grmbl...
+ if (!m_cachedTabBar) {
+ const QList<QTabBar *> tabBars = qFindChildren<QTabBar *>(m_tabWidget);
+ Q_ASSERT(tabBars.size() == 1);
+ m_cachedTabBar = tabBars.front();
+ }
+ return m_cachedTabBar;
+
+}
+
+static bool canMove(const QPoint &pressPoint, const QMouseEvent *e)
+{
+ const QPoint pt = pressPoint - e->pos();
+ return pt.manhattanLength() > QApplication::startDragDistance();
+}
+
+bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e)
+{
+ const QEvent::Type type = e->type();
+ // Do not try to locate tab bar and form window, etc. for uninteresting events and
+ // avoid asserts about missing tab bars when being destroyed
+ switch (type) {
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ case QEvent::DragLeave:
+ case QEvent::DragEnter:
+ case QEvent::DragMove:
+ case QEvent::Drop:
+ break;
+ default:
+ return false;
+ }
+
+ if (o != tabBar())
+ return false;
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return false;
+
+ switch (type) {
+ case QEvent::MouseButtonDblClick:
+ break;
+ case QEvent::MouseButtonPress: {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(e);
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ fw->clearSelection();
+ fw->selectWidget(m_tabWidget, true);
+ }
+ if (mev->button() & Qt::LeftButton) {
+ m_mousePressed = true;
+ m_pressPoint = mev->pos();
+
+ QTabBar *tabbar = tabBar();
+ const int count = tabbar->count();
+ for (int i = 0; i < count; ++i) {
+ if (tabbar->tabRect(i).contains(m_pressPoint)) {
+ if (i != tabbar->currentIndex()) {
+ qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw);
+ cmd->init(m_tabWidget, QLatin1String("currentIndex"), i);
+ fw->commandHistory()->push(cmd);
+ }
+ break;
+ }
+ }
+ }
+ } break;
+
+ case QEvent::MouseButtonRelease:
+ m_mousePressed = false;
+ break;
+
+ case QEvent::MouseMove: {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
+ if (m_mousePressed && canMove(m_pressPoint, mouseEvent)) {
+ const int index = m_tabWidget->currentIndex();
+ if (index == -1)
+ break;
+
+ m_mousePressed = false;
+ QDrag *drg = new QDrag(m_tabWidget);
+ drg->setMimeData(new qdesigner_internal::MyMimeData(m_tabWidget));
+
+ m_dragIndex = index;
+ m_dragPage = m_tabWidget->currentWidget();
+ m_dragLabel = m_tabWidget->tabText(index);
+ m_dragIcon = m_tabWidget->tabIcon(index);
+ if (m_dragIcon.isNull()) {
+ QLabel *label = new QLabel(m_dragLabel);
+ label->adjustSize();
+ drg->setPixmap(QPixmap::grabWidget(label));
+ label->deleteLater();
+ } else {
+ drg->setPixmap(m_dragIcon.pixmap(22, 22));
+ }
+
+ m_tabWidget->removeTab(m_dragIndex);
+
+ const Qt::DropActions dropAction = drg->start(Qt::MoveAction);
+
+ if (dropAction == Qt::IgnoreAction) {
+ // abort
+ m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel);
+ m_tabWidget->setCurrentIndex(m_dragIndex);
+ }
+
+ if (m_dropIndicator)
+ m_dropIndicator->hide();
+ }
+ } break;
+
+ case QEvent::DragLeave: {
+ if (m_dropIndicator)
+ m_dropIndicator->hide();
+ } break;
+
+ case QEvent::DragEnter:
+ case QEvent::DragMove: {
+ QDragMoveEvent *de = static_cast<QDragMoveEvent*>(e);
+ if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget))
+ return false;
+
+ if (de->proposedAction() == Qt::MoveAction)
+ de->acceptProposedAction();
+ else {
+ de->setDropAction(Qt::MoveAction);
+ de->accept();
+ }
+
+ QRect rect;
+ const int index = pageFromPosition(de->pos(), rect);
+
+ if (!m_dropIndicator) {
+ m_dropIndicator = new QWidget(m_tabWidget);
+ QPalette p = m_dropIndicator->palette();
+ p.setColor(m_tabWidget->backgroundRole(), Qt::red);
+ m_dropIndicator->setPalette(p);
+ }
+
+ QPoint pos;
+ if (index == m_tabWidget->count())
+ pos = tabBar()->mapToParent(QPoint(rect.x() + rect.width(), rect.y()));
+ else
+ pos = tabBar()->mapToParent(QPoint(rect.x(), rect.y()));
+
+ m_dropIndicator->setGeometry(pos.x(), pos.y() , 3, rect.height());
+ m_dropIndicator->show();
+ } break;
+
+ case QEvent::Drop: {
+ QDropEvent *de = static_cast<QDropEvent*>(e);
+ if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget))
+ return false;
+ de->acceptProposedAction();
+ de->accept();
+
+ QRect rect;
+ const int newIndex = pageFromPosition(de->pos(), rect);
+
+ qdesigner_internal::MoveTabPageCommand *cmd = new qdesigner_internal::MoveTabPageCommand(fw);
+ m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel);
+ cmd->init(m_tabWidget, m_dragPage, m_dragIcon, m_dragLabel, m_dragIndex, newIndex);
+ fw->commandHistory()->push(cmd);
+ } break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QTabWidgetEventFilter::removeCurrentPage()
+{
+ if (!m_tabWidget->currentWidget())
+ return;
+
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ qdesigner_internal::DeleteTabPageCommand *cmd = new qdesigner_internal::DeleteTabPageCommand(fw);
+ cmd->init(m_tabWidget);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QTabWidgetEventFilter::addPage()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw);
+ cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertBefore);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QTabWidgetEventFilter::addPageAfter()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw);
+ cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertAfter);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+QDesignerFormWindowInterface *QTabWidgetEventFilter::formWindow() const
+{
+ return QDesignerFormWindowInterface::findFormWindow(const_cast<QTabWidget*>(m_tabWidget));
+}
+
+// Get page from mouse position. Default to new page if in right half of last page?
+int QTabWidgetEventFilter::pageFromPosition(const QPoint &pos, QRect &rect) const
+{
+ int index = 0;
+ const QTabBar *tabbar = tabBar();
+ const int count = m_tabWidget->count();
+ for (; index < count; index++) {
+ const QRect rc = tabbar->tabRect(index);
+ if (rc.contains(pos)) {
+ rect = rc;
+ break;
+ }
+ }
+
+ if (index == count -1) {
+ QRect rect2 = rect;
+ rect2.setLeft(rect2.left() + rect2.width() / 2);
+ if (rect2.contains(pos))
+ index++;
+ }
+ return index;
+}
+
+QMenu *QTabWidgetEventFilter::addContextMenuActions(QMenu *popup)
+{
+ QMenu *pageMenu = 0;
+ const int count = m_tabWidget->count();
+ m_actionDeletePage->setEnabled(count > 1);
+ if (count) {
+ const int currentIndex = m_tabWidget->currentIndex();
+ const QString pageSubMenuLabel = tr("Page %1 of %2").arg(currentIndex + 1).arg(count);
+ pageMenu = popup->addMenu(pageSubMenuLabel);
+ pageMenu->addAction(m_actionDeletePage);
+ // Set up promotion menu for current widget.
+ if (QWidget *page = m_tabWidget->currentWidget ()) {
+ m_pagePromotionTaskMenu->setWidget(page);
+ m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(m_tabWidget),
+ qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
+ pageMenu);
+ }
+ }
+
+ QMenu *insertPageMenu = popup->addMenu(tr("Insert Page"));
+ insertPageMenu->addAction(m_actionInsertPageAfter);
+ insertPageMenu->addAction(m_actionInsertPage);
+ popup->addSeparator();
+ return pageMenu;
+}
+
+// ----------- QTabWidgetPropertySheet
+
+static const char *currentTabTextKey = "currentTabText";
+static const char *currentTabNameKey = "currentTabName";
+static const char *currentTabIconKey = "currentTabIcon";
+static const char *currentTabToolTipKey = "currentTabToolTip";
+static const char *currentTabWhatsThisKey = "currentTabWhatsThis";
+
+QTabWidgetPropertySheet::QTabWidgetPropertySheet(QTabWidget *object, QObject *parent) :
+ QDesignerPropertySheet(object, parent),
+ m_tabWidget(object)
+{
+ createFakeProperty(QLatin1String(currentTabTextKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+ createFakeProperty(QLatin1String(currentTabNameKey), QString());
+ createFakeProperty(QLatin1String(currentTabIconKey), qVariantFromValue(qdesigner_internal::PropertySheetIconValue()));
+ if (formWindowBase())
+ formWindowBase()->addReloadableProperty(this, indexOf(QLatin1String(currentTabIconKey)));
+ createFakeProperty(QLatin1String(currentTabToolTipKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+ createFakeProperty(QLatin1String(currentTabWhatsThisKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+}
+
+QTabWidgetPropertySheet::TabWidgetProperty QTabWidgetPropertySheet::tabWidgetPropertyFromName(const QString &name)
+{
+ typedef QHash<QString, TabWidgetProperty> TabWidgetPropertyHash;
+ static TabWidgetPropertyHash tabWidgetPropertyHash;
+ if (tabWidgetPropertyHash.empty()) {
+ tabWidgetPropertyHash.insert(QLatin1String(currentTabTextKey), PropertyCurrentTabText);
+ tabWidgetPropertyHash.insert(QLatin1String(currentTabNameKey), PropertyCurrentTabName);
+ tabWidgetPropertyHash.insert(QLatin1String(currentTabIconKey), PropertyCurrentTabIcon);
+ tabWidgetPropertyHash.insert(QLatin1String(currentTabToolTipKey), PropertyCurrentTabToolTip);
+ tabWidgetPropertyHash.insert(QLatin1String(currentTabWhatsThisKey), PropertyCurrentTabWhatsThis);
+ }
+ return tabWidgetPropertyHash.value(name, PropertyTabWidgetNone);
+}
+
+void QTabWidgetPropertySheet::setProperty(int index, const QVariant &value)
+{
+ const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+ if (tabWidgetProperty == PropertyTabWidgetNone) {
+ QDesignerPropertySheet::setProperty(index, value);
+ return;
+ }
+
+ // index-dependent
+ const int currentIndex = m_tabWidget->currentIndex();
+ QWidget *currentWidget = m_tabWidget->currentWidget();
+ if (!currentWidget)
+ return;
+
+ switch (tabWidgetProperty) {
+ case PropertyCurrentTabText:
+ m_tabWidget->setTabText(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].text = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+ break;
+ case PropertyCurrentTabName:
+ currentWidget->setObjectName(value.toString());
+ break;
+ case PropertyCurrentTabIcon:
+ m_tabWidget->setTabIcon(currentIndex, qvariant_cast<QIcon>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].icon = qVariantValue<qdesigner_internal::PropertySheetIconValue>(value);
+ break;
+ case PropertyCurrentTabToolTip:
+ m_tabWidget->setTabToolTip(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].tooltip = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+ break;
+ case PropertyCurrentTabWhatsThis:
+ m_tabWidget->setTabWhatsThis(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].whatsthis = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+ break;
+ case PropertyTabWidgetNone:
+ break;
+ }
+}
+
+bool QTabWidgetPropertySheet::isEnabled(int index) const
+{
+ if (tabWidgetPropertyFromName(propertyName(index)) == PropertyTabWidgetNone)
+ return QDesignerPropertySheet::isEnabled(index);
+ return m_tabWidget->currentIndex() != -1;
+}
+
+QVariant QTabWidgetPropertySheet::property(int index) const
+{
+ const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+ if (tabWidgetProperty == PropertyTabWidgetNone)
+ return QDesignerPropertySheet::property(index);
+
+ // index-dependent
+ QWidget *currentWidget = m_tabWidget->currentWidget();
+ if (!currentWidget) {
+ if (tabWidgetProperty == PropertyCurrentTabIcon)
+ return qVariantFromValue(qdesigner_internal::PropertySheetIconValue());
+ if (tabWidgetProperty == PropertyCurrentTabText)
+ return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ if (tabWidgetProperty == PropertyCurrentTabToolTip)
+ return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ if (tabWidgetProperty == PropertyCurrentTabWhatsThis)
+ return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ return QVariant(QString());
+ }
+
+ // index-dependent
+ switch (tabWidgetProperty) {
+ case PropertyCurrentTabText:
+ return qVariantFromValue(m_pageToData.value(currentWidget).text);
+ case PropertyCurrentTabName:
+ return currentWidget->objectName();
+ case PropertyCurrentTabIcon:
+ return qVariantFromValue(m_pageToData.value(currentWidget).icon);
+ case PropertyCurrentTabToolTip:
+ return qVariantFromValue(m_pageToData.value(currentWidget).tooltip);
+ case PropertyCurrentTabWhatsThis:
+ return qVariantFromValue(m_pageToData.value(currentWidget).whatsthis);
+ case PropertyTabWidgetNone:
+ break;
+ }
+ return QVariant();
+}
+
+bool QTabWidgetPropertySheet::reset(int index)
+{
+ const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+ if (tabWidgetProperty == PropertyTabWidgetNone)
+ return QDesignerPropertySheet::reset(index);
+
+ // index-dependent
+ QWidget *currentWidget = m_tabWidget->currentWidget();
+ if (!currentWidget)
+ return false;
+
+ // index-dependent
+ switch (tabWidgetProperty) {
+ case PropertyCurrentTabName:
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentTabToolTip:
+ m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue();
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentTabWhatsThis:
+ m_pageToData[currentWidget].whatsthis = qdesigner_internal::PropertySheetStringValue();
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentTabText:
+ m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue();
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentTabIcon:
+ m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue();
+ setProperty(index, QIcon());
+ break;
+ case PropertyTabWidgetNone:
+ break;
+ }
+ return true;
+}
+
+bool QTabWidgetPropertySheet::checkProperty(const QString &propertyName)
+{
+ switch (tabWidgetPropertyFromName(propertyName)) {
+ case PropertyCurrentTabText:
+ case PropertyCurrentTabName:
+ case PropertyCurrentTabToolTip:
+ case PropertyCurrentTabWhatsThis:
+ case PropertyCurrentTabIcon:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "qdesigner_tabwidget.moc" // required for MyMimeData
diff --git a/tools/designer/src/lib/shared/qdesigner_tabwidget_p.h b/tools/designer/src/lib/shared/qdesigner_tabwidget_p.h
new file mode 100644
index 0000000..b5af372
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_tabwidget_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_TABWIDGET_H
+#define QDESIGNER_TABWIDGET_H
+
+#include "shared_global_p.h"
+#include "qdesigner_propertysheet_p.h"
+#include "qdesigner_utils_p.h"
+
+#include <QtCore/QPointer>
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QTabWidget;
+class QTabBar;
+class QMenu;
+class QAction;
+
+namespace qdesigner_internal {
+ class PromotionTaskMenu;
+}
+
+class QDESIGNER_SHARED_EXPORT QTabWidgetEventFilter : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QTabWidgetEventFilter(QTabWidget *parent);
+ ~QTabWidgetEventFilter();
+
+ // Install helper on QTabWidget
+ static void install(QTabWidget *tabWidget);
+ static QTabWidgetEventFilter *eventFilterOf(const QTabWidget *tabWidget);
+ // Convenience to add a menu on a tackedWidget
+ static QMenu *addTabWidgetContextMenuActions(const QTabWidget *tabWidget, QMenu *popup);
+
+ // Add context menu and return page submenu or 0.
+ QMenu *addContextMenuActions(QMenu *popup);
+
+ virtual bool eventFilter(QObject *o, QEvent *e);
+
+ QDesignerFormWindowInterface *formWindow() const;
+
+private slots:
+ void removeCurrentPage();
+ void addPage();
+ void addPageAfter();
+
+private:
+ int pageFromPosition(const QPoint &pos, QRect &rect) const;
+ QTabBar *tabBar() const;
+
+ QTabWidget *m_tabWidget;
+ mutable QPointer<QTabBar> m_cachedTabBar;
+ QPoint m_pressPoint;
+ QWidget *m_dropIndicator;
+ int m_dragIndex;
+ QWidget *m_dragPage;
+ QString m_dragLabel;
+ QIcon m_dragIcon;
+ bool m_mousePressed;
+ QAction *m_actionDeletePage;
+ QAction *m_actionInsertPage;
+ QAction *m_actionInsertPageAfter;
+ qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu;
+};
+
+// PropertySheet to handle the page properties
+class QDESIGNER_SHARED_EXPORT QTabWidgetPropertySheet : public QDesignerPropertySheet {
+public:
+ explicit QTabWidgetPropertySheet(QTabWidget *object, QObject *parent = 0);
+
+ virtual void setProperty(int index, const QVariant &value);
+ virtual QVariant property(int index) const;
+ virtual bool reset(int index);
+ virtual bool isEnabled(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:
+ enum TabWidgetProperty { PropertyCurrentTabText, PropertyCurrentTabName, PropertyCurrentTabIcon,
+ PropertyCurrentTabToolTip, PropertyCurrentTabWhatsThis, PropertyTabWidgetNone };
+
+ static TabWidgetProperty tabWidgetPropertyFromName(const QString &name);
+ QTabWidget *m_tabWidget;
+ struct PageData
+ {
+ qdesigner_internal::PropertySheetStringValue text;
+ qdesigner_internal::PropertySheetStringValue tooltip;
+ qdesigner_internal::PropertySheetStringValue whatsthis;
+ qdesigner_internal::PropertySheetIconValue icon;
+ };
+ QMap<QWidget *, PageData> m_pageToData;
+};
+
+typedef QDesignerPropertySheetFactory<QTabWidget, QTabWidgetPropertySheet> QTabWidgetPropertySheetFactory;
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_TABWIDGET_H
diff --git a/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp b/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp
new file mode 100644
index 0000000..cce0528
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp
@@ -0,0 +1,781 @@
+/****************************************************************************
+**
+** 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::QDesignerTaskMenu
+*/
+
+#include "qdesigner_taskmenu_p.h"
+#include "qdesigner_command_p.h"
+#include "richtexteditor_p.h"
+#include "plaintexteditor_p.h"
+#include "stylesheeteditor_p.h"
+#include "qlayout_widget_p.h"
+#include "layout_p.h"
+#include "spacer_widget_p.h"
+#include "textpropertyeditor_p.h"
+#include "promotiontaskmenu_p.h"
+#include "metadatabase_p.h"
+#include "scriptdialog_p.h"
+#include "scriptcommand_p.h"
+#include "signalslotdialog_p.h"
+#include "qdesigner_membersheet_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "morphmenu_p.h"
+#include "qdesigner_integration_p.h"
+#include "formlayoutmenu_p.h"
+#include "ui_selectsignaldialog.h"
+#include "widgetfactory_p.h"
+#include "abstractintrospection_p.h"
+#include "widgetdatabase_p.h"
+
+#include <shared_enums_p.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#include <QtGui/QWidget>
+#include <QtGui/QMenuBar>
+#include <QtGui/QMainWindow>
+#include <QtGui/QStatusBar>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QPushButton>
+#include <QtGui/QUndoStack>
+#include <QtCore/QDebug>
+#include <QtCore/QSignalMapper>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+static QMenuBar *findMenuBar(const QWidget *widget)
+{
+ const QList<QObject*> children = widget->children();
+ foreach (QObject *obj, widget->children()) {
+ if (QMenuBar *mb = qobject_cast<QMenuBar*>(obj)) {
+ return mb;
+ }
+ }
+
+ return 0;
+}
+
+static QStatusBar *findStatusBar(const QWidget *widget)
+{
+ const QList<QObject*> children = widget->children();
+ foreach (QObject *obj, widget->children()) {
+ if (QStatusBar *sb = qobject_cast<QStatusBar*>(obj)) {
+ return sb;
+ }
+ }
+
+ return 0;
+}
+
+static inline QAction *createSeparatorHelper(QObject *parent) {
+ QAction *rc = new QAction(parent);
+ rc->setSeparator(true);
+ return rc;
+}
+
+static inline qdesigner_internal::QDesignerIntegration *integration(const QDesignerFormEditorInterface *core) {
+ return qobject_cast<qdesigner_internal::QDesignerIntegration *>(core->integration());
+}
+
+static QString objName(const QDesignerFormEditorInterface *core, QObject *object) {
+ QDesignerPropertySheetExtension *sheet
+ = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), object);
+ Q_ASSERT(sheet != 0);
+
+ const QString objectNameProperty = QLatin1String("objectName");
+ const int index = sheet->indexOf(objectNameProperty);
+ const qdesigner_internal::PropertySheetStringValue objectNameValue
+ = qVariantValue<qdesigner_internal::PropertySheetStringValue>(sheet->property(index));
+ return objectNameValue.value();
+}
+
+enum { ApplyMinimumWidth = 0x1, ApplyMinimumHeight = 0x2, ApplyMaximumWidth = 0x4, ApplyMaximumHeight = 0x8 };
+
+namespace {
+// --------------- ObjectNameDialog
+class ObjectNameDialog : public QDialog
+{
+ public:
+ ObjectNameDialog(QWidget *parent, const QString &oldName);
+ QString newObjectName() const;
+
+ private:
+ qdesigner_internal::TextPropertyEditor *m_editor;
+};
+
+ObjectNameDialog::ObjectNameDialog(QWidget *parent, const QString &oldName)
+ : QDialog(parent),
+ m_editor( new qdesigner_internal::TextPropertyEditor(this, qdesigner_internal::TextPropertyEditor::EmbeddingNone,
+ qdesigner_internal::ValidationObjectName))
+{
+ setWindowTitle(QCoreApplication::translate("ObjectNameDialog", "Change Object Name"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+ vboxLayout->addWidget(new QLabel(QCoreApplication::translate("ObjectNameDialog", "Object Name")));
+
+ m_editor->setText(oldName);
+ m_editor->selectAll();
+ m_editor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ vboxLayout->addWidget(m_editor);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal, this);
+ QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+ okButton->setDefault(true);
+ vboxLayout->addWidget(buttonBox);
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+QString ObjectNameDialog::newObjectName() const
+{
+ return m_editor->text();
+}
+
+}
+
+namespace qdesigner_internal {
+// -------------- QDesignerTaskMenuPrivate
+class QDesignerTaskMenuPrivate {
+public:
+ QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent);
+
+ QDesignerTaskMenu *m_q;
+ QPointer<QWidget> m_widget;
+ QAction *m_separator;
+ QAction *m_separator2;
+ QAction *m_separator3;
+ QAction *m_separator4;
+ QAction *m_separator5;
+ QAction *m_separator6;
+ QAction *m_separator7;
+ QAction *m_changeObjectNameAction;
+ QAction *m_changeToolTip;
+ QAction *m_changeWhatsThis;
+ QAction *m_changeStyleSheet;
+ MorphMenu *m_morphMenu;
+ FormLayoutMenu *m_formLayoutMenu;
+
+ QAction *m_addMenuBar;
+ QAction *m_addToolBar;
+ QAction *m_addStatusBar;
+ QAction *m_removeStatusBar;
+ QAction *m_changeScript;
+ QAction *m_containerFakeMethods;
+ QAction *m_navigateToSlot;
+ PromotionTaskMenu* m_promotionTaskMenu;
+ QActionGroup *m_sizeActionGroup;
+ QAction *m_sizeActionsSubMenu;
+};
+
+QDesignerTaskMenuPrivate::QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent) :
+ m_q(0),
+ m_widget(widget),
+ m_separator(createSeparatorHelper(parent)),
+ m_separator2(createSeparatorHelper(parent)),
+ m_separator3(createSeparatorHelper(parent)),
+ m_separator4(createSeparatorHelper(parent)),
+ m_separator5(createSeparatorHelper(parent)),
+ m_separator6(createSeparatorHelper(parent)),
+ m_separator7(createSeparatorHelper(parent)),
+ m_changeObjectNameAction(new QAction(QDesignerTaskMenu::tr("Change objectName..."), parent)),
+ m_changeToolTip(new QAction(QDesignerTaskMenu::tr("Change toolTip..."), parent)),
+ m_changeWhatsThis(new QAction(QDesignerTaskMenu::tr("Change whatsThis..."), parent)),
+ m_changeStyleSheet(new QAction(QDesignerTaskMenu::tr("Change styleSheet..."), parent)),
+ m_morphMenu(new MorphMenu(parent)),
+ m_formLayoutMenu(new FormLayoutMenu(parent)),
+ m_addMenuBar(new QAction(QDesignerTaskMenu::tr("Create Menu Bar"), parent)),
+ m_addToolBar(new QAction(QDesignerTaskMenu::tr("Add Tool Bar"), parent)),
+ m_addStatusBar(new QAction(QDesignerTaskMenu::tr("Create Status Bar"), parent)),
+ m_removeStatusBar(new QAction(QDesignerTaskMenu::tr("Remove Status Bar"), parent)),
+ m_changeScript(new QAction(QDesignerTaskMenu::tr("Change script..."), parent)),
+ m_containerFakeMethods(new QAction(QDesignerTaskMenu::tr("Change signals/slots..."), parent)),
+ m_navigateToSlot(new QAction(QDesignerTaskMenu::tr("Go to slot..."), parent)),
+ m_promotionTaskMenu(new PromotionTaskMenu(widget, PromotionTaskMenu::ModeManagedMultiSelection, parent)),
+ m_sizeActionGroup(new QActionGroup(parent)),
+ m_sizeActionsSubMenu(new QAction(QDesignerTaskMenu::tr("Size Constraints"), parent))
+{
+ QMenu *sizeMenu = new QMenu;
+ m_sizeActionsSubMenu->setMenu(sizeMenu);
+ QAction *sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Width"));
+ sizeAction->setData(ApplyMinimumWidth);
+ sizeMenu->addAction(sizeAction);
+
+ sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Height"));
+ sizeAction->setData(ApplyMinimumHeight);
+ sizeMenu->addAction(sizeAction);
+
+ sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Size"));
+ sizeAction->setData(ApplyMinimumWidth|ApplyMinimumHeight);
+ sizeMenu->addAction(sizeAction);
+
+ sizeMenu->addSeparator();
+
+ sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Width"));
+ sizeAction->setData(ApplyMaximumWidth);
+ sizeMenu->addAction(sizeAction);
+
+ sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Height"));
+ sizeAction->setData(ApplyMaximumHeight);
+ sizeMenu->addAction(sizeAction);
+
+ sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Size"));
+ sizeAction->setData(ApplyMaximumWidth|ApplyMaximumHeight);
+ sizeMenu->addAction(sizeAction);
+}
+
+// --------- QDesignerTaskMenu
+QDesignerTaskMenu::QDesignerTaskMenu(QWidget *widget, QObject *parent) :
+ QObject(parent),
+ d(new QDesignerTaskMenuPrivate(widget, parent))
+{
+ d->m_q = this;
+ Q_ASSERT(qobject_cast<QDesignerFormWindowInterface*>(widget) == 0);
+
+ connect(d->m_changeObjectNameAction, SIGNAL(triggered()), this, SLOT(changeObjectName()));
+ connect(d->m_changeToolTip, SIGNAL(triggered()), this, SLOT(changeToolTip()));
+ connect(d->m_changeWhatsThis, SIGNAL(triggered()), this, SLOT(changeWhatsThis()));
+ connect(d->m_changeStyleSheet, SIGNAL(triggered()), this, SLOT(changeStyleSheet()));
+ connect(d->m_addMenuBar, SIGNAL(triggered()), this, SLOT(createMenuBar()));
+ connect(d->m_addToolBar, SIGNAL(triggered()), this, SLOT(addToolBar()));
+ connect(d->m_addStatusBar, SIGNAL(triggered()), this, SLOT(createStatusBar()));
+ connect(d->m_removeStatusBar, SIGNAL(triggered()), this, SLOT(removeStatusBar()));
+ connect(d->m_changeScript, SIGNAL(triggered()), this, SLOT(changeScript()));
+ connect(d->m_containerFakeMethods, SIGNAL(triggered()), this, SLOT(containerFakeMethods()));
+ connect(d->m_navigateToSlot, SIGNAL(triggered()), this, SLOT(slotNavigateToSlot()));
+ connect(d->m_sizeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(applySize(QAction*)));
+}
+
+QDesignerTaskMenu::~QDesignerTaskMenu()
+{
+ delete d;
+}
+
+QAction *QDesignerTaskMenu::createSeparator()
+{
+ return createSeparatorHelper(this);
+}
+
+QWidget *QDesignerTaskMenu::widget() const
+{
+ return d->m_widget;
+}
+
+QDesignerFormWindowInterface *QDesignerTaskMenu::formWindow() const
+{
+ QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(widget());
+ Q_ASSERT(result != 0);
+ return result;
+}
+
+void QDesignerTaskMenu::createMenuBar()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
+ if (!mw) {
+ // ### warning message
+ return;
+ }
+
+ CreateMenuBarCommand *cmd = new CreateMenuBarCommand(fw);
+ cmd->init(mw);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QDesignerTaskMenu::addToolBar()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
+ if (!mw) {
+ // ### warning message
+ return;
+ }
+
+ AddToolBarCommand *cmd = new AddToolBarCommand(fw);
+ cmd->init(mw);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QDesignerTaskMenu::createStatusBar()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
+ if (!mw) {
+ // ### warning message
+ return;
+ }
+
+ CreateStatusBarCommand *cmd = new CreateStatusBarCommand(fw);
+ cmd->init(mw);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QDesignerTaskMenu::removeStatusBar()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
+ if (!mw) {
+ // ### warning message
+ return;
+ }
+
+ DeleteStatusBarCommand *cmd = new DeleteStatusBarCommand(fw);
+ cmd->init(findStatusBar(mw));
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+QList<QAction*> QDesignerTaskMenu::taskActions() const
+{
+ QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(widget());
+ Q_ASSERT(formWindow);
+
+ const bool isMainContainer = formWindow->mainContainer() == widget();
+
+ QList<QAction*> actions;
+
+ if (const QMainWindow *mw = qobject_cast<const QMainWindow*>(formWindow->mainContainer())) {
+ if (isMainContainer || mw->centralWidget() == widget()) {
+ if (!findMenuBar(mw)) {
+ actions.append(d->m_addMenuBar);
+ }
+
+ actions.append(d->m_addToolBar);
+ // ### create the status bar
+ if (!findStatusBar(mw))
+ actions.append(d->m_addStatusBar);
+ else
+ actions.append(d->m_removeStatusBar);
+ actions.append(d->m_separator);
+ }
+ }
+ actions.append(d->m_changeObjectNameAction);
+ d->m_morphMenu->populate(d->m_widget, formWindow, actions);
+ d->m_formLayoutMenu->populate(d->m_widget, formWindow, actions);
+ actions.append(d->m_separator2);
+ actions.append(d->m_changeToolTip);
+ actions.append(d->m_changeWhatsThis);
+ actions.append(d->m_changeStyleSheet);
+ actions.append(d->m_separator6);
+ actions.append(d->m_sizeActionsSubMenu);
+ d->m_promotionTaskMenu->setMode(formWindow->isManaged(d->m_widget) ?
+ PromotionTaskMenu::ModeManagedMultiSelection : PromotionTaskMenu::ModeUnmanagedMultiSelection);
+ d->m_promotionTaskMenu->addActions(formWindow, PromotionTaskMenu::LeadingSeparator, actions);
+
+#ifdef WANT_SCRIPT_OPTION
+ if (!isMainContainer) {
+ actions.append(d->m_separator4);
+ actions.append(d->m_changeScript);
+ }
+#endif
+ if (isMainContainer && !qt_extension<QDesignerLanguageExtension*>(formWindow->core()->extensionManager(), formWindow->core())) {
+ actions.append(d->m_separator5);
+ actions.append(d->m_containerFakeMethods);
+ }
+
+ if (isSlotNavigationEnabled(formWindow->core())) {
+ actions.append(d->m_separator7);
+ actions.append(d->m_navigateToSlot);
+ }
+
+ return actions;
+}
+
+void QDesignerTaskMenu::changeObjectName()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ Q_ASSERT(fw != 0);
+
+ const QString oldObjectName = objName(fw->core(), widget());
+
+ ObjectNameDialog dialog(fw, oldObjectName);
+ if (dialog.exec() == QDialog::Accepted) {
+ const QString newObjectName = dialog.newObjectName();
+ if (!newObjectName.isEmpty() && newObjectName != oldObjectName ) {
+ const QString objectNameProperty = QLatin1String("objectName");
+ PropertySheetStringValue objectNameValue;
+ objectNameValue.setValue(newObjectName);
+ setProperty(fw, CurrentWidgetMode, objectNameProperty, qVariantFromValue(objectNameValue));
+ }
+ }
+}
+
+void QDesignerTaskMenu::changeTextProperty(const QString &propertyName, const QString &windowTitle, PropertyMode pm, Qt::TextFormat desiredFormat)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+ Q_ASSERT(d->m_widget->parentWidget() != 0);
+
+ const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(fw->core()->extensionManager(), d->m_widget);
+ const int index = sheet->indexOf(propertyName);
+ if (index == -1) {
+ qDebug() << "** WARNING Invalid property" << propertyName << " passed to changeTextProperty!";
+ return;
+ }
+ PropertySheetStringValue textValue = qVariantValue<PropertySheetStringValue>(sheet->property(index));
+ const QString oldText = textValue.value();
+ // Pop up respective dialog
+ bool accepted = false;
+ QString newText;
+ switch (desiredFormat) {
+ case Qt::PlainText: {
+ PlainTextEditorDialog dlg(fw->core(), fw);
+ if (!windowTitle.isEmpty())
+ dlg.setWindowTitle(windowTitle);
+ dlg.setDefaultFont(d->m_widget->font());
+ dlg.setText(oldText);
+ accepted = dlg.showDialog() == QDialog::Accepted;
+ newText = dlg.text();
+ }
+ break;
+ default: {
+ RichTextEditorDialog dlg(fw->core(), fw);
+ if (!windowTitle.isEmpty())
+ dlg.setWindowTitle(windowTitle);
+ dlg.setDefaultFont(d->m_widget->font());
+ dlg.setText(oldText);
+ accepted = dlg.showDialog() == QDialog::Accepted;
+ newText = dlg.text(desiredFormat);
+ }
+ break;
+ }
+ // change property
+ if (!accepted || oldText == newText)
+ return;
+
+
+ textValue.setValue(newText);
+ setProperty(fw, pm, propertyName, qVariantFromValue(textValue));
+}
+
+void QDesignerTaskMenu::changeToolTip()
+{
+ changeTextProperty(QLatin1String("toolTip"), tr("Edit ToolTip"), MultiSelectionMode, Qt::AutoText);
+}
+
+void QDesignerTaskMenu::changeWhatsThis()
+{
+ changeTextProperty(QLatin1String("whatsThis"), tr("Edit WhatsThis"), MultiSelectionMode, Qt::AutoText);
+}
+
+void QDesignerTaskMenu::changeStyleSheet()
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ StyleSheetPropertyEditorDialog dlg(fw, fw, d->m_widget);
+ dlg.exec();
+ }
+}
+
+void QDesignerTaskMenu::changeScript()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+
+ MetaDataBase *metaDataBase = qobject_cast<MetaDataBase*>(fw->core()->metaDataBase());
+ if (!metaDataBase)
+ return;
+
+ const MetaDataBaseItem* item = metaDataBase->metaDataBaseItem(d->m_widget);
+ if (!item)
+ return;
+
+ const QString oldScript = item->script();
+ QString newScript = oldScript;
+
+ ScriptDialog scriptDialog(fw->core()->dialogGui(), fw);
+ if (!scriptDialog.editScript(newScript))
+ return;
+
+ // compile list of selected objects
+ ScriptCommand *scriptCommand = new ScriptCommand(fw);
+ if (!scriptCommand->init(applicableObjects(fw, MultiSelectionMode), newScript)) {
+ delete scriptCommand;
+ return;
+ }
+
+ fw->commandHistory()->push(scriptCommand);
+}
+
+void QDesignerTaskMenu::containerFakeMethods()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+ SignalSlotDialog::editMetaDataBase(fw, d->m_widget, fw);
+}
+
+static QString declaredInClass(const QDesignerMetaObjectInterface *metaObject, const QString &member)
+{
+ // Find class whose superclass does not contain the method.
+ const QDesignerMetaObjectInterface *meta = metaObject;
+
+ for (;;) {
+ const QDesignerMetaObjectInterface *tmpMeta = meta->superClass();
+ if (tmpMeta == 0)
+ break;
+ if (tmpMeta->indexOfMethod(member) == -1)
+ break;
+ meta = tmpMeta;
+ }
+ return meta->className();
+}
+
+bool QDesignerTaskMenu::isSlotNavigationEnabled(const QDesignerFormEditorInterface *core)
+{
+ if (QDesignerIntegration *integr = integration(core))
+ return integr->isSlotNavigationEnabled();
+ return false;
+}
+
+void QDesignerTaskMenu::slotNavigateToSlot()
+{
+ QDesignerFormEditorInterface *core = formWindow()->core();
+ Q_ASSERT(core);
+ navigateToSlot(core, widget());
+}
+
+void QDesignerTaskMenu::navigateToSlot(QDesignerFormEditorInterface *core,
+ QObject *object,
+ const QString &defaultSignal)
+{
+ const QString objectName = objName(core, object);
+ QMap<QString, QMap<QString, QStringList> > classToSignalList;
+
+ QDesignerIntegration *integr = integration(core);
+
+ // "real" signals
+ if (const QDesignerMetaObjectInterface *metaObject = core->introspection()->metaObject(object)) {
+ const int methodCount = metaObject->methodCount();
+ for (int i = 0; i < methodCount; ++i) {
+ const QDesignerMetaMethodInterface *metaMethod = metaObject->method(i);
+ if (metaMethod->methodType() == QDesignerMetaMethodInterface::Signal) {
+ const QString signature = metaMethod->signature();
+ const QStringList parameterNames = metaMethod->parameterNames();
+ classToSignalList[declaredInClass(metaObject, signature)][signature] = parameterNames;
+ }
+ }
+ }
+
+ // fake signals
+ if (qdesigner_internal::MetaDataBase *metaDataBase
+ = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase())) {
+ qdesigner_internal::MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(object);
+ Q_ASSERT(item);
+ const QStringList fakeSignals = item->fakeSignals();
+ foreach (const QString &fakeSignal, fakeSignals)
+ classToSignalList[item->customClassName()][fakeSignal] = QStringList();
+ }
+
+ if (object->isWidgetType()) {
+ QWidget *widget = static_cast<QWidget *>(object);
+ if (WidgetDataBase *db = qobject_cast<WidgetDataBase *>(core->widgetDataBase())) {
+ const QString promotedClassName = promotedCustomClassName(core, widget);
+ const int index = core->widgetDataBase()->indexOfClassName(promotedClassName);
+ if (index >= 0) {
+ WidgetDataBaseItem* item = static_cast<WidgetDataBaseItem*>(db->item(index));
+ const QStringList fakeSignals = item->fakeSignals();
+ foreach (const QString &fakeSignal, fakeSignals)
+ classToSignalList[promotedClassName][fakeSignal] = QStringList();
+ }
+ }
+ }
+
+ Ui::SelectSignalDialog dialogUi;
+ QDialog selectSignalDialog(0, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+ dialogUi.setupUi(&selectSignalDialog);
+
+ QMap<QString, QMap<QString, QStringList> >::const_iterator iter(classToSignalList.constBegin());
+ for (; iter != classToSignalList.constEnd(); ++iter) {
+ const QString className = iter.key();
+ QMap<QString, QStringList> signalNames = iter.value();
+
+ QMap<QString, QStringList>::const_iterator itSignal(signalNames.constBegin());
+ for (; itSignal != signalNames.constEnd(); ++itSignal) {
+ const QString signalName = itSignal.key();
+ QTreeWidgetItem *row = new QTreeWidgetItem(QStringList() << signalName << className);
+ row->setData(0, Qt::UserRole, itSignal.value());
+ dialogUi.signalList->addTopLevelItem(row);
+ }
+ }
+ if (dialogUi.signalList->topLevelItemCount() == 0) {
+ QTreeWidgetItem *row = new QTreeWidgetItem(QStringList() << tr("no signals available"));
+ dialogUi.signalList->addTopLevelItem(row);
+ dialogUi.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ } else {
+ connect(dialogUi.signalList, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
+ &selectSignalDialog, SLOT(accept()));
+ }
+
+ if (defaultSignal.isEmpty()) {
+ dialogUi.signalList->setCurrentItem(dialogUi.signalList->topLevelItem(0));
+ } else {
+ const QList<QTreeWidgetItem *> items = dialogUi.signalList->findItems (defaultSignal, Qt::MatchExactly, 0);
+ if (!items.empty())
+ dialogUi.signalList->setCurrentItem(items.front());
+ }
+
+ dialogUi.signalList->resizeColumnToContents(0);
+
+ if (selectSignalDialog.exec() == QDialog::Accepted) {
+ QTreeWidgetItem *selectedItem = dialogUi.signalList->selectedItems().first();
+ const QString signalSignature = selectedItem->text(0);
+ const QStringList parameterNames = qVariantValue<QStringList>(selectedItem->data(0, Qt::UserRole));
+
+ // TODO: Check wether signal is connected to slot
+ integr->emitNavigateToSlot(objectName, signalSignature, parameterNames);
+ }
+}
+
+// Add a command that takes over the value of the current geometry as
+// minimum/maximum size according to the flags.
+static void createSizeCommand(QDesignerFormWindowInterface *fw, QWidget *w, int flags)
+{
+ const QSize size = w->size();
+ if (flags & (ApplyMinimumWidth|ApplyMinimumHeight)) {
+ QSize minimumSize = w-> minimumSize();
+ if (flags & ApplyMinimumWidth)
+ minimumSize.setWidth(size.width());
+ if (flags & ApplyMinimumHeight)
+ minimumSize.setHeight(size.height());
+ SetPropertyCommand* cmd = new SetPropertyCommand(fw);
+ cmd->init(w, QLatin1String("minimumSize"), minimumSize);
+ fw->commandHistory()->push(cmd);
+ }
+ if (flags & (ApplyMaximumWidth|ApplyMaximumHeight)) {
+ QSize maximumSize = w-> maximumSize();
+ if (flags & ApplyMaximumWidth)
+ maximumSize.setWidth(size.width());
+ if (flags & ApplyMaximumHeight)
+ maximumSize.setHeight(size.height());
+ SetPropertyCommand* cmd = new SetPropertyCommand(fw);
+ cmd->init(w, QLatin1String("maximumSize"), maximumSize);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QDesignerTaskMenu::applySize(QAction *a)
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ if (!fw)
+ return;
+
+ const QWidgetList selection = applicableWidgets(fw, MultiSelectionMode);
+ if (selection.isEmpty())
+ return;
+
+ const int mask = a->data().toInt();
+ const int size = selection.size();
+ fw->commandHistory()->beginMacro(tr("Set size constraint on %n widget(s)", 0, size));
+ for (int i = 0; i < size; i++)
+ createSizeCommand(fw, selection.at(i), mask);
+ fw->commandHistory()->endMacro();
+}
+
+template <class Container>
+ static void getApplicableObjects(const QDesignerFormWindowInterface *fw, QWidget *current,
+ QDesignerTaskMenu::PropertyMode pm, Container *c)
+{
+ // Current is always first
+ c->push_back(current);
+ if (pm == QDesignerTaskMenu::CurrentWidgetMode)
+ return;
+ QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
+ if (!designerObjectInspector)
+ return; // Ooops, someone plugged an old-style Object Inspector
+ // Add managed or unmanaged selection according to current type, make current first
+ Selection s;
+ designerObjectInspector->getSelection(s);
+ const QWidgetList &source = fw->isManaged(current) ? s.managed : s.unmanaged;
+ const QWidgetList::const_iterator cend = source.constEnd();
+ for ( QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it)
+ if (*it != current) // was first
+ c->push_back(*it);
+}
+
+QObjectList QDesignerTaskMenu::applicableObjects(const QDesignerFormWindowInterface *fw, PropertyMode pm) const
+{
+ QObjectList rc;
+ getApplicableObjects(fw, d->m_widget, pm, &rc);
+ return rc;
+}
+
+QWidgetList QDesignerTaskMenu::applicableWidgets(const QDesignerFormWindowInterface *fw, PropertyMode pm) const
+{
+ QWidgetList rc;
+ getApplicableObjects(fw, d->m_widget, pm, &rc);
+ return rc;
+}
+
+void QDesignerTaskMenu::setProperty(QDesignerFormWindowInterface *fw, PropertyMode pm, const QString &name, const QVariant &newValue)
+{
+ SetPropertyCommand* setPropertyCommand = new SetPropertyCommand(fw);
+ if (setPropertyCommand->init(applicableObjects(fw, pm), name, newValue, d->m_widget)) {
+ fw->commandHistory()->push(setPropertyCommand);
+ } else {
+ delete setPropertyCommand;
+ qDebug() << "Unable to set property " << name << '.';
+ }
+}
+
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_taskmenu_p.h b/tools/designer/src/lib/shared/qdesigner_taskmenu_p.h
new file mode 100644
index 0000000..db5807b
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_taskmenu_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_TASKMENU_H
+#define QDESIGNER_TASKMENU_H
+
+#include "shared_global_p.h"
+#include "extensionfactory_p.h"
+#include <QtDesigner/QDesignerTaskMenuExtension>
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerFormEditorInterface;
+
+class QWidget;
+class QSignalMapper;
+
+namespace qdesigner_internal {
+class QDesignerTaskMenuPrivate;
+
+class QDESIGNER_SHARED_EXPORT QDesignerTaskMenu: public QObject, public QDesignerTaskMenuExtension
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerTaskMenuExtension)
+public:
+ QDesignerTaskMenu(QWidget *widget, QObject *parent);
+ virtual ~QDesignerTaskMenu();
+
+ QWidget *widget() const;
+
+ virtual QList<QAction*> taskActions() const;
+
+ enum PropertyMode { CurrentWidgetMode, MultiSelectionMode };
+
+ static bool isSlotNavigationEnabled(const QDesignerFormEditorInterface *core);
+ static void navigateToSlot(QDesignerFormEditorInterface *core, QObject *o,
+ const QString &defaultSignal = QString());
+
+protected:
+
+ QDesignerFormWindowInterface *formWindow() const;
+ void changeTextProperty(const QString &propertyName, const QString &windowTitle, PropertyMode pm, Qt::TextFormat desiredFormat);
+
+ QAction *createSeparator();
+
+ /* Retrieve the list of objects the task menu is supposed to act on. Note that a task menu can be invoked for
+ * an unmanaged widget [as of 4.5], in which case it must not use the cursor selection,
+ * but the unmanaged selection of the object inspector. */
+ QObjectList applicableObjects(const QDesignerFormWindowInterface *fw, PropertyMode pm) const;
+ QList<QWidget *> applicableWidgets(const QDesignerFormWindowInterface *fw, PropertyMode pm) const;
+
+ void setProperty(QDesignerFormWindowInterface *fw, PropertyMode pm, const QString &name, const QVariant &newValue);
+
+private slots:
+ void changeObjectName();
+ void changeToolTip();
+ void changeWhatsThis();
+ void changeStyleSheet();
+ void createMenuBar();
+ void addToolBar();
+ void createStatusBar();
+ void removeStatusBar();
+ void changeScript();
+ void containerFakeMethods();
+ void slotNavigateToSlot();
+ void applySize(QAction *a);
+
+private:
+ QDesignerTaskMenuPrivate *d;
+};
+
+typedef ExtensionFactory<QDesignerTaskMenuExtension, QWidget, QDesignerTaskMenu> QDesignerTaskMenuFactory;
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_TASKMENU_H
diff --git a/tools/designer/src/lib/shared/qdesigner_toolbar.cpp b/tools/designer/src/lib/shared/qdesigner_toolbar.cpp
new file mode 100644
index 0000000..cb77801
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_toolbar.cpp
@@ -0,0 +1,486 @@
+/****************************************************************************
+**
+** 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::Sentinel
+*/
+
+#include "qdesigner_toolbar_p.h"
+#include "qdesigner_command_p.h"
+#include "actionrepository_p.h"
+#include "actionprovider_p.h"
+#include "qdesigner_utils_p.h"
+#include "qdesigner_objectinspector_p.h"
+#include "promotiontaskmenu_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerPropertyEditorInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <actionprovider_p.h>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QToolButton>
+#include <QtGui/QToolBar>
+#include <QtGui/QMenu>
+#include <QtGui/qevent.h>
+#include <QtGui/QApplication>
+#include <QtGui/private/qtoolbarlayout_p.h>
+#include <QtCore/QDebug>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+typedef QList<QAction*> ActionList;
+
+namespace qdesigner_internal {
+// ------------------- ToolBarEventFilter
+void ToolBarEventFilter::install(QToolBar *tb)
+{
+ ToolBarEventFilter *tf = new ToolBarEventFilter(tb);
+ tb->installEventFilter(tf);
+ tb->setAcceptDrops(true); // ### fake
+}
+
+ToolBarEventFilter::ToolBarEventFilter(QToolBar *tb) :
+ QObject(tb),
+ m_toolBar(tb),
+ m_promotionTaskMenu(0)
+{
+}
+
+ToolBarEventFilter *ToolBarEventFilter::eventFilterOf(const QToolBar *tb)
+{
+ // Look for 1st order children only..otherwise, we might get filters of nested widgets
+ const QObjectList children = tb->children();
+ const QObjectList::const_iterator cend = children.constEnd();
+ for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
+ QObject *o = *it;
+ if (!o->isWidgetType())
+ if (ToolBarEventFilter *ef = qobject_cast<ToolBarEventFilter *>(o))
+ return ef;
+ }
+ return 0;
+}
+
+bool ToolBarEventFilter::eventFilter (QObject *watched, QEvent *event)
+{
+ if (watched != m_toolBar)
+ return QObject::eventFilter (watched, event);
+
+ switch (event->type()) {
+ case QEvent::ChildAdded: {
+ // Children should not interact with the mouse
+ const QChildEvent *ce = static_cast<const QChildEvent *>(event);
+ if (QWidget *w = qobject_cast<QWidget *>(ce->child())) {
+ w->setAttribute(Qt::WA_TransparentForMouseEvents, true);
+ w->setFocusPolicy(Qt::NoFocus);
+ }
+ }
+ break;
+ case QEvent::ContextMenu:
+ return handleContextMenuEvent(static_cast<QContextMenuEvent*>(event));
+ case QEvent::DragEnter:
+ case QEvent::DragMove:
+ return handleDragEnterMoveEvent(static_cast<QDragMoveEvent *>(event));
+ case QEvent::DragLeave:
+ return handleDragLeaveEvent(static_cast<QDragLeaveEvent *>(event));
+ case QEvent::Drop:
+ return handleDropEvent(static_cast<QDropEvent *>(event));
+ case QEvent::MouseButtonPress:
+ return handleMousePressEvent(static_cast<QMouseEvent*>(event));
+ case QEvent::MouseButtonRelease:
+ return handleMouseReleaseEvent(static_cast<QMouseEvent*>(event));
+ case QEvent::MouseMove:
+ return handleMouseMoveEvent(static_cast<QMouseEvent*>(event));
+ default:
+ break;
+ }
+ return QObject::eventFilter (watched, event);
+}
+
+ActionList ToolBarEventFilter::contextMenuActions(const QPoint &globalPos)
+{
+ ActionList rc;
+ const int index = actionIndexAt(m_toolBar, m_toolBar->mapFromGlobal(globalPos), m_toolBar->orientation());
+ const ActionList actions = m_toolBar->actions();
+ QAction *action = index != -1 ?actions.at(index) : 0;
+ QVariant itemData;
+
+ // Insert before
+ if (action && index != 0 && !action->isSeparator()) {
+ QAction *newSeperatorAct = new QAction(tr("Insert Separator before '%1'").arg(action->objectName()), 0);
+ qVariantSetValue(itemData, action);
+ newSeperatorAct->setData(itemData);
+ connect(newSeperatorAct, SIGNAL(triggered()), this, SLOT(slotInsertSeparator()));
+ rc.push_back(newSeperatorAct);
+ }
+
+ // Append separator
+ if (actions.empty() || !actions.back()->isSeparator()) {
+ QAction *newSeperatorAct = new QAction(tr("Append Separator"), 0);
+ qVariantSetValue(itemData, static_cast<QAction*>(0));
+ newSeperatorAct->setData(itemData);
+ connect(newSeperatorAct, SIGNAL(triggered()), this, SLOT(slotInsertSeparator()));
+ rc.push_back(newSeperatorAct);
+ }
+ // Promotion
+ if (!m_promotionTaskMenu)
+ m_promotionTaskMenu = new PromotionTaskMenu(m_toolBar, PromotionTaskMenu::ModeSingleWidget, this);
+ m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::LeadingSeparator|PromotionTaskMenu::TrailingSeparator, rc);
+ // Remove
+ if (action) {
+ QAction *a = new QAction(tr("Remove action '%1'").arg(action->objectName()), 0);
+ qVariantSetValue(itemData, action);
+ a->setData(itemData);
+ connect(a, SIGNAL(triggered()), this, SLOT(slotRemoveSelectedAction()));
+ rc.push_back(a);
+ }
+
+ QAction *remove_toolbar = new QAction(tr("Remove Toolbar '%1'").arg(m_toolBar->objectName()), 0);
+ connect(remove_toolbar, SIGNAL(triggered()), this, SLOT(slotRemoveToolBar()));
+ rc.push_back(remove_toolbar);
+ return rc;
+}
+
+bool ToolBarEventFilter::handleContextMenuEvent(QContextMenuEvent * event )
+{
+ event->accept();
+
+ const QPoint globalPos = event->globalPos();
+ const ActionList al = contextMenuActions(event->globalPos());
+
+ QMenu menu(0);
+ const ActionList::const_iterator acend = al.constEnd();
+ for (ActionList::const_iterator it = al.constBegin(); it != acend; ++it)
+ menu.addAction(*it);
+ menu.exec(globalPos);
+ return true;
+}
+
+void ToolBarEventFilter::slotRemoveSelectedAction()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (!action)
+ return;
+
+ QAction *a = qvariant_cast<QAction*>(action->data());
+ Q_ASSERT(a != 0);
+
+ QDesignerFormWindowInterface *fw = formWindow();
+ Q_ASSERT(fw);
+
+ const ActionList actions = m_toolBar->actions();
+ const int pos = actions.indexOf(a);
+ QAction *action_before = 0;
+ if (pos != -1 && actions.count() > pos + 1)
+ action_before = actions.at(pos + 1);
+
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ cmd->init(m_toolBar, a, action_before);
+ fw->commandHistory()->push(cmd);
+}
+
+void ToolBarEventFilter::slotRemoveToolBar()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ Q_ASSERT(fw);
+ DeleteToolBarCommand *cmd = new DeleteToolBarCommand(fw);
+ cmd->init(m_toolBar);
+ fw->commandHistory()->push(cmd);
+}
+
+void ToolBarEventFilter::slotInsertSeparator()
+{
+ QDesignerFormWindowInterface *fw = formWindow();
+ QAction *theSender = qobject_cast<QAction*>(sender());
+ QAction *previous = qvariant_cast<QAction *>(theSender->data());
+ fw->beginCommand(tr("Insert Separator"));
+ QAction *action = createAction(fw, QLatin1String("separator"), true);
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(m_toolBar, action, previous);
+ fw->commandHistory()->push(cmd);
+ fw->endCommand();
+}
+
+QDesignerFormWindowInterface *ToolBarEventFilter::formWindow() const
+{
+ return QDesignerFormWindowInterface::findFormWindow(m_toolBar);
+}
+
+QAction *ToolBarEventFilter::createAction(QDesignerFormWindowInterface *fw, const QString &objectName, bool separator)
+{
+ QAction *action = new QAction(fw);
+ fw->core()->widgetFactory()->initialize(action);
+ if (separator)
+ action->setSeparator(true);
+
+ action->setObjectName(objectName);
+ fw->ensureUniqueObjectName(action);
+
+ qdesigner_internal::AddActionCommand *cmd = new qdesigner_internal::AddActionCommand(fw);
+ cmd->init(action);
+ fw->commandHistory()->push(cmd);
+
+ return action;
+}
+
+void ToolBarEventFilter::adjustDragIndicator(const QPoint &pos)
+{
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QDesignerFormEditorInterface *core = fw->core();
+ if (QDesignerActionProviderExtension *a = qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), m_toolBar))
+ a->adjustIndicator(pos);
+ }
+}
+
+void ToolBarEventFilter::hideDragIndicator()
+{
+ adjustDragIndicator(QPoint(-1, -1));
+}
+
+bool ToolBarEventFilter::handleMousePressEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton || withinHandleArea(m_toolBar, event->pos()))
+ return false;
+
+ if (QDesignerFormWindowInterface *fw = formWindow()) {
+ QDesignerFormEditorInterface *core = fw->core();
+ // Keep selection in sync
+ fw->clearSelection(false);
+ if (QDesignerObjectInspector *oi = qobject_cast<QDesignerObjectInspector *>(core->objectInspector())) {
+ oi->clearSelection();
+ oi->selectObject(m_toolBar);
+ }
+ core->propertyEditor()->setObject(m_toolBar);
+ }
+ m_startPosition = m_toolBar->mapFromGlobal(event->globalPos());
+ event->accept();
+ return true;
+}
+
+bool ToolBarEventFilter::handleMouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton || m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos()))
+ return false;
+
+ // Accept the event, otherwise, form window selection will trigger
+ m_startPosition = QPoint();
+ event->accept();
+ return true;
+}
+
+bool ToolBarEventFilter::handleMouseMoveEvent(QMouseEvent *event)
+{
+ if (m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos()))
+ return false;
+
+ const QPoint pos = m_toolBar->mapFromGlobal(event->globalPos());
+ if ((pos - m_startPosition).manhattanLength() > qApp->startDragDistance()) {
+ startDrag(m_startPosition, event->modifiers());
+ m_startPosition = QPoint();
+ event->accept();
+ return true;
+ }
+ return false;
+}
+
+bool ToolBarEventFilter::handleDragEnterMoveEvent(QDragMoveEvent *event)
+{
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d)
+ return false;
+
+ if (d->actionList().isEmpty()) {
+ event->ignore();
+ hideDragIndicator();
+ return true;
+ }
+
+ QAction *action = d->actionList().first();
+ if (!action || action->menu() || m_toolBar->actions().contains(action) || !Utils::isObjectAncestorOf(formWindow()->mainContainer(), action)) {
+ event->ignore();
+ hideDragIndicator();
+ return true;
+ }
+
+ d->accept(event);
+ adjustDragIndicator(event->pos());
+ return true;
+}
+
+bool ToolBarEventFilter::handleDragLeaveEvent(QDragLeaveEvent *)
+{
+ hideDragIndicator();
+ return false;
+}
+
+bool ToolBarEventFilter::handleDropEvent(QDropEvent *event)
+{
+ const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+ if (!d)
+ return false;
+
+ if (d->actionList().isEmpty()) {
+ event->ignore();
+ hideDragIndicator();
+ return true;
+ }
+
+ QAction *action = d->actionList().first();
+
+ const ActionList actions = m_toolBar->actions();
+ if (!action || actions.contains(action)) {
+ event->ignore();
+ hideDragIndicator();
+ return true;
+ }
+
+ // Try to find action to 'insert before'. Click on action or in free area, else ignore.
+ QAction *beforeAction = 0;
+ const QPoint pos = event->pos();
+ const int index = actionIndexAt(m_toolBar, pos, m_toolBar->orientation());
+ if (index != -1) {
+ beforeAction = actions.at(index);
+ } else {
+ if (!freeArea(m_toolBar).contains(pos)) {
+ event->ignore();
+ hideDragIndicator();
+ return true;
+ }
+ }
+
+ event->acceptProposedAction();
+ QDesignerFormWindowInterface *fw = formWindow();
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(m_toolBar, action, beforeAction);
+ fw->commandHistory()->push(cmd);
+ hideDragIndicator();
+ return true;
+}
+
+void ToolBarEventFilter::startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers)
+{
+ const int index = actionIndexAt(m_toolBar, pos, m_toolBar->orientation());
+ if (index == - 1)
+ return;
+
+ const ActionList actions = m_toolBar->actions();
+ QAction *action = actions.at(index);
+ QDesignerFormWindowInterface *fw = formWindow();
+
+ const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction;
+ if (dropAction == Qt::MoveAction) {
+ RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+ const int nextIndex = index + 1;
+ QAction *nextAction = nextIndex < actions.size() ? actions.at(nextIndex) : 0;
+ cmd->init(m_toolBar, action, nextAction);
+ fw->commandHistory()->push(cmd);
+ }
+
+ QDrag *drag = new QDrag(m_toolBar);
+ drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap( action));
+ drag->setMimeData(new ActionRepositoryMimeData(action, dropAction));
+
+ if (drag->start(dropAction) == Qt::IgnoreAction) {
+ hideDragIndicator();
+ if (dropAction == Qt::MoveAction) {
+ const ActionList currentActions = m_toolBar->actions();
+ QAction *previous = 0;
+ if (index >= 0 && index < currentActions.size())
+ previous = currentActions.at(index);
+ InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+ cmd->init(m_toolBar, action, previous);
+ fw->commandHistory()->push(cmd);
+ }
+ }
+}
+
+QAction *ToolBarEventFilter::actionAt(const QToolBar *tb, const QPoint &pos)
+{
+ const int index = actionIndexAt(tb, pos, tb->orientation());
+ if (index == -1)
+ return 0;
+ return tb->actions().at(index);
+}
+
+QRect ToolBarEventFilter::handleArea(const QToolBar *tb)
+{
+ const QToolBarLayout *tbl = qobject_cast<QToolBarLayout *>(tb->layout());
+ Q_ASSERT(tbl);
+ return tbl->handleRect();
+}
+
+bool ToolBarEventFilter::withinHandleArea(const QToolBar *tb, const QPoint &pos)
+{
+ return handleArea(tb).contains(pos);
+}
+
+// Determine the free area behind the last action.
+QRect ToolBarEventFilter::freeArea(const QToolBar *tb)
+{
+ QRect rc = QRect(QPoint(0, 0), tb->size());
+ const ActionList actionList = tb->actions();
+ QRect exclusionRectangle = actionList.empty() ? handleArea(tb) : tb->actionGeometry(actionList.back());
+ switch (tb->orientation()) {
+ case Qt::Horizontal:
+ switch (QApplication::layoutDirection()) {
+ case Qt::LeftToRight:
+ rc.setX(exclusionRectangle.right() + 1);
+ break;
+ case Qt::RightToLeft:
+ rc.setRight(exclusionRectangle.x());
+ break;
+ }
+ break;
+ case Qt::Vertical:
+ rc.setY(exclusionRectangle.bottom() + 1);
+ break;
+ }
+ return rc;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_toolbar_p.h b/tools/designer/src/lib/shared/qdesigner_toolbar_p.h
new file mode 100644
index 0000000..fd14eb4
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_toolbar_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_TOOLBAR_H
+#define QDESIGNER_TOOLBAR_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QAction>
+#include <QtGui/QToolButton>
+
+#include <QtCore/QList>
+#include <QtCore/QPoint>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QToolBar;
+class QRect;
+class QAction;
+
+namespace qdesigner_internal {
+
+class PromotionTaskMenu;
+
+// Special event filter for tool bars in designer.
+// Handles drag and drop to and from. Ensures that each
+// child widget is WA_TransparentForMouseEvents to enable drag and drop.
+
+class QDESIGNER_SHARED_EXPORT ToolBarEventFilter : public QObject {
+ Q_OBJECT
+
+public:
+ static void install(QToolBar *tb);
+
+ // Find action by position. Note that QToolBar::actionAt() will
+ // not work as designer sets WA_TransparentForMouseEvents on its tool bar buttons
+ // to be able to drag them. This function will return the dummy
+ // sentinel action when applied to tool bars created by designer if the position matches.
+ static QAction *actionAt(const QToolBar *tb, const QPoint &pos);
+
+ static bool withinHandleArea(const QToolBar *tb, const QPoint &pos);
+ static QRect handleArea(const QToolBar *tb);
+ static QRect freeArea(const QToolBar *tb);
+
+ // Utility to create an action
+ static QAction *createAction(QDesignerFormWindowInterface *fw, const QString &objectName, bool separator);
+
+ virtual bool eventFilter (QObject *watched, QEvent *event);
+
+ // Helper for task menu extension
+ QList<QAction *> contextMenuActions(const QPoint &globalPos = QPoint(-1, -1));
+
+ static ToolBarEventFilter *eventFilterOf(const QToolBar *tb);
+
+private slots:
+ void slotRemoveSelectedAction();
+ void slotRemoveToolBar();
+ void slotInsertSeparator();
+
+private:
+ explicit ToolBarEventFilter(QToolBar *tb);
+
+ bool handleContextMenuEvent(QContextMenuEvent * event);
+ bool handleDragEnterMoveEvent(QDragMoveEvent *event);
+ bool handleDragLeaveEvent(QDragLeaveEvent *);
+ bool handleDropEvent(QDropEvent *event);
+ bool handleMousePressEvent(QMouseEvent *event);
+ bool handleMouseReleaseEvent(QMouseEvent *event);
+ bool handleMouseMoveEvent(QMouseEvent *event);
+
+ QDesignerFormWindowInterface *formWindow() const;
+ void adjustDragIndicator(const QPoint &pos);
+ void hideDragIndicator();
+ void startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers);
+ bool withinHandleArea(const QPoint &pos) const;
+
+ QToolBar *m_toolBar;
+ PromotionTaskMenu *m_promotionTaskMenu;
+ QPoint m_startPosition;
+};
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_TOOLBAR_H
diff --git a/tools/designer/src/lib/shared/qdesigner_toolbox.cpp b/tools/designer/src/lib/shared/qdesigner_toolbox.cpp
new file mode 100644
index 0000000..46c8ffe
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_toolbox.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** 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_toolbox_p.h"
+#include "qdesigner_command_p.h"
+#include "orderdialog_p.h"
+#include "promotiontaskmenu_p.h"
+#include "formwindowbase_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtCore/QEvent>
+#include <QtGui/QAction>
+#include <QtGui/QToolBox>
+#include <QtGui/QMenu>
+#include <QtGui/QLayout>
+#include <QtGui/QApplication>
+#include <QtGui/QContextMenuEvent>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+QToolBoxHelper::QToolBoxHelper(QToolBox *toolbox) :
+ QObject(toolbox),
+ m_toolbox(toolbox),
+ m_actionDeletePage(new QAction(tr("Delete Page"), this)),
+ m_actionInsertPage(new QAction(tr("Before Current Page"), this)),
+ m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)),
+ m_actionChangePageOrder(new QAction(tr("Change Page Order..."), this)),
+ m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
+{
+ connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage()));
+ connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage()));
+ connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter()));
+ connect(m_actionChangePageOrder, SIGNAL(triggered()), this, SLOT(changeOrder()));
+
+ m_toolbox->installEventFilter(this);
+}
+
+void QToolBoxHelper::install(QToolBox *toolbox)
+{
+ new QToolBoxHelper(toolbox);
+}
+
+bool QToolBoxHelper::eventFilter(QObject *watched, QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::ChildPolished:
+ // Install on the buttons
+ if (watched == m_toolbox) {
+ QChildEvent *ce = static_cast<QChildEvent *>(event);
+ if (!qstrcmp(ce->child()->metaObject()->className(), "QToolBoxButton"))
+ ce->child()->installEventFilter(this);
+ }
+ break;
+ case QEvent::ContextMenu:
+ if (watched != m_toolbox) {
+ // An action invoked from the passive interactor (ToolBox button) might
+ // cause its deletion within its event handler, triggering a warning. Re-post
+ // the event to the toolbox.
+ QContextMenuEvent *current = static_cast<QContextMenuEvent *>(event);
+ QContextMenuEvent *copy = new QContextMenuEvent(current->reason(), current->pos(), current-> globalPos(), current->modifiers());
+ QApplication::postEvent(m_toolbox, copy);
+ current->accept();
+ return true;
+ }
+ break;
+ case QEvent::MouseButtonRelease:
+ if (watched != m_toolbox)
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) {
+ fw->clearSelection();
+ fw->selectWidget(m_toolbox, true);
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+QToolBoxHelper *QToolBoxHelper::helperOf(const QToolBox *toolbox)
+{
+ // Look for 1st order children only..otherwise, we might get filters of nested widgets
+ const QObjectList children = toolbox->children();
+ const QObjectList::const_iterator cend = children.constEnd();
+ for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
+ QObject *o = *it;
+ if (!o->isWidgetType())
+ if (QToolBoxHelper *h = qobject_cast<QToolBoxHelper *>(o))
+ return h;
+ }
+ return 0;
+}
+
+QMenu *QToolBoxHelper::addToolBoxContextMenuActions(const QToolBox *toolbox, QMenu *popup)
+{
+ QToolBoxHelper *helper = helperOf(toolbox);
+ if (!helper)
+ return 0;
+ return helper->addContextMenuActions(popup);
+}
+
+void QToolBoxHelper::removeCurrentPage()
+{
+ if (m_toolbox->currentIndex() == -1 || !m_toolbox->widget(m_toolbox->currentIndex()))
+ return;
+
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) {
+ qdesigner_internal::DeleteToolBoxPageCommand *cmd = new qdesigner_internal::DeleteToolBoxPageCommand(fw);
+ cmd->init(m_toolbox);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QToolBoxHelper::addPage()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) {
+ qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw);
+ cmd->init(m_toolbox, qdesigner_internal::AddToolBoxPageCommand::InsertBefore);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+void QToolBoxHelper::changeOrder()
+{
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox);
+
+ if (!fw)
+ return;
+
+ const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(fw->core(), m_toolbox);
+ const int pageCount = oldPages.size();
+ if (pageCount < 2)
+ return;
+
+ qdesigner_internal::OrderDialog dlg(fw);
+ dlg.setPageList(oldPages);
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ const QWidgetList newPages = dlg.pageList();
+ if (newPages == oldPages)
+ return;
+
+ fw->beginCommand(tr("Change Page Order"));
+ for(int i=0; i < pageCount; ++i) {
+ if (newPages.at(i) == m_toolbox->widget(i))
+ continue;
+ qdesigner_internal::MoveToolBoxPageCommand *cmd = new qdesigner_internal::MoveToolBoxPageCommand(fw);
+ cmd->init(m_toolbox, newPages.at(i), i);
+ fw->commandHistory()->push(cmd);
+ }
+ fw->endCommand();
+}
+
+void QToolBoxHelper::addPageAfter()
+{
+ if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) {
+ qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw);
+ cmd->init(m_toolbox, qdesigner_internal::AddToolBoxPageCommand::InsertAfter);
+ fw->commandHistory()->push(cmd);
+ }
+}
+
+QPalette::ColorRole QToolBoxHelper::currentItemBackgroundRole() const
+{
+ const QWidget *w = m_toolbox->widget(0);
+ if (!w)
+ return QPalette::Window;
+ return w->backgroundRole();
+}
+
+void QToolBoxHelper::setCurrentItemBackgroundRole(QPalette::ColorRole role)
+{
+ const int count = m_toolbox->count();
+ for (int i = 0; i < count; ++i) {
+ QWidget *w = m_toolbox->widget(i);
+ w->setBackgroundRole(role);
+ w->update();
+ }
+}
+
+QMenu *QToolBoxHelper::addContextMenuActions(QMenu *popup) const
+{
+ QMenu *pageMenu = 0;
+ const int count = m_toolbox->count();
+ m_actionDeletePage->setEnabled(count > 1);
+ if (count) {
+ const QString pageSubMenuLabel = tr("Page %1 of %2").arg(m_toolbox->currentIndex() + 1).arg(count);
+ pageMenu = popup->addMenu(pageSubMenuLabel);
+
+ pageMenu->addAction(m_actionDeletePage);
+ // Set up promotion menu for current widget.
+ if (QWidget *page = m_toolbox->currentWidget ()) {
+ m_pagePromotionTaskMenu->setWidget(page);
+ m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(m_toolbox),
+ qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
+ pageMenu);
+ }
+ }
+ QMenu *insertPageMenu = popup->addMenu(tr("Insert Page"));
+ insertPageMenu->addAction(m_actionInsertPageAfter);
+ insertPageMenu->addAction(m_actionInsertPage);
+ if (count > 1) {
+ popup->addAction(m_actionChangePageOrder);
+ }
+ popup->addSeparator();
+ return pageMenu;
+}
+
+// -------- QToolBoxWidgetPropertySheet
+
+static const char *currentItemTextKey = "currentItemText";
+static const char *currentItemNameKey = "currentItemName";
+static const char *currentItemIconKey = "currentItemIcon";
+static const char *currentItemToolTipKey = "currentItemToolTip";
+static const char *tabSpacingKey = "tabSpacing";
+
+enum { tabSpacingDefault = -1 };
+
+QToolBoxWidgetPropertySheet::QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent) :
+ QDesignerPropertySheet(object, parent),
+ m_toolBox(object)
+{
+ createFakeProperty(QLatin1String(currentItemTextKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+ createFakeProperty(QLatin1String(currentItemNameKey), QString());
+ createFakeProperty(QLatin1String(currentItemIconKey), qVariantFromValue(qdesigner_internal::PropertySheetIconValue()));
+ if (formWindowBase())
+ formWindowBase()->addReloadableProperty(this, indexOf(QLatin1String(currentItemIconKey)));
+ createFakeProperty(QLatin1String(currentItemToolTipKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+ createFakeProperty(QLatin1String(tabSpacingKey), QVariant(tabSpacingDefault));
+}
+
+QToolBoxWidgetPropertySheet::ToolBoxProperty QToolBoxWidgetPropertySheet::toolBoxPropertyFromName(const QString &name)
+{
+ typedef QHash<QString, ToolBoxProperty> ToolBoxPropertyHash;
+ static ToolBoxPropertyHash toolBoxPropertyHash;
+ if (toolBoxPropertyHash.empty()) {
+ toolBoxPropertyHash.insert(QLatin1String(currentItemTextKey), PropertyCurrentItemText);
+ toolBoxPropertyHash.insert(QLatin1String(currentItemNameKey), PropertyCurrentItemName);
+ toolBoxPropertyHash.insert(QLatin1String(currentItemIconKey), PropertyCurrentItemIcon);
+ toolBoxPropertyHash.insert(QLatin1String(currentItemToolTipKey), PropertyCurrentItemToolTip);
+ toolBoxPropertyHash.insert(QLatin1String(tabSpacingKey), PropertyTabSpacing);
+ }
+ return toolBoxPropertyHash.value(name, PropertyToolBoxNone);
+}
+
+void QToolBoxWidgetPropertySheet::setProperty(int index, const QVariant &value)
+{
+ const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index));
+ // independent of index
+ switch (toolBoxProperty) {
+ case PropertyTabSpacing:
+ m_toolBox->layout()->setSpacing(value.toInt());
+ return;
+ case PropertyToolBoxNone:
+ QDesignerPropertySheet::setProperty(index, value);
+ return;
+ default:
+ break;
+ }
+ // index-dependent
+ const int currentIndex = m_toolBox->currentIndex();
+ QWidget *currentWidget = m_toolBox->currentWidget();
+ if (!currentWidget)
+ return;
+
+ switch (toolBoxProperty) {
+ case PropertyCurrentItemText:
+ m_toolBox->setItemText(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].text = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+ break;
+ case PropertyCurrentItemName:
+ currentWidget->setObjectName(value.toString());
+ break;
+ case PropertyCurrentItemIcon:
+ m_toolBox->setItemIcon(currentIndex, qvariant_cast<QIcon>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].icon = qVariantValue<qdesigner_internal::PropertySheetIconValue>(value);
+ break;
+ case PropertyCurrentItemToolTip:
+ m_toolBox->setItemToolTip(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+ m_pageToData[currentWidget].tooltip = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+ break;
+ case PropertyTabSpacing:
+ case PropertyToolBoxNone:
+ break;
+ }
+}
+
+bool QToolBoxWidgetPropertySheet::isEnabled(int index) const
+{
+ switch (toolBoxPropertyFromName(propertyName(index))) {
+ case PropertyToolBoxNone: // independent of index
+ case PropertyTabSpacing:
+ return QDesignerPropertySheet::isEnabled(index);
+ default:
+ break;
+ }
+ return m_toolBox->currentIndex() != -1;
+}
+
+QVariant QToolBoxWidgetPropertySheet::property(int index) const
+{
+ const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index));
+ // independent of index
+ switch (toolBoxProperty) {
+ case PropertyTabSpacing:
+ return m_toolBox->layout()->spacing();
+ case PropertyToolBoxNone:
+ return QDesignerPropertySheet::property(index);
+ default:
+ break;
+ }
+ // index-dependent
+ QWidget *currentWidget = m_toolBox->currentWidget();
+ if (!currentWidget) {
+ if (toolBoxProperty == PropertyCurrentItemIcon)
+ return qVariantFromValue(qdesigner_internal::PropertySheetIconValue());
+ if (toolBoxProperty == PropertyCurrentItemText)
+ return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ if (toolBoxProperty == PropertyCurrentItemToolTip)
+ return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+ return QVariant(QString());
+ }
+
+ // index-dependent
+ switch (toolBoxProperty) {
+ case PropertyCurrentItemText:
+ return qVariantFromValue(m_pageToData.value(currentWidget).text);
+ case PropertyCurrentItemName:
+ return currentWidget->objectName();
+ case PropertyCurrentItemIcon:
+ return qVariantFromValue(m_pageToData.value(currentWidget).icon);
+ case PropertyCurrentItemToolTip:
+ return qVariantFromValue(m_pageToData.value(currentWidget).tooltip);
+ case PropertyTabSpacing:
+ case PropertyToolBoxNone:
+ break;
+ }
+ return QVariant();
+}
+
+bool QToolBoxWidgetPropertySheet::reset(int index)
+{
+ const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index));
+ // independent of index
+ switch (toolBoxProperty) {
+ case PropertyTabSpacing:
+ setProperty(index, QVariant(tabSpacingDefault));
+ return true;
+ case PropertyToolBoxNone:
+ return QDesignerPropertySheet::reset(index);
+ default:
+ break;
+ }
+ // index-dependent
+ QWidget *currentWidget = m_toolBox->currentWidget();
+ if (!currentWidget)
+ return false;
+
+ // index-dependent
+ switch (toolBoxProperty) {
+ case PropertyCurrentItemName:
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentItemToolTip:
+ m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue();
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentItemText:
+ m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue();
+ setProperty(index, QString());
+ break;
+ case PropertyCurrentItemIcon:
+ m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue();
+ setProperty(index, QIcon());
+ break;
+ case PropertyTabSpacing:
+ case PropertyToolBoxNone:
+ break;
+ }
+ return true;
+}
+
+bool QToolBoxWidgetPropertySheet::checkProperty(const QString &propertyName)
+{
+ switch (toolBoxPropertyFromName(propertyName)) {
+ case PropertyCurrentItemText:
+ case PropertyCurrentItemName:
+ case PropertyCurrentItemToolTip:
+ case PropertyCurrentItemIcon:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_toolbox_p.h b/tools/designer/src/lib/shared/qdesigner_toolbox_p.h
new file mode 100644
index 0000000..fdd738a
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_toolbox_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_TOOLBOX_H
+#define QDESIGNER_TOOLBOX_H
+
+#include "shared_global_p.h"
+#include "qdesigner_propertysheet_p.h"
+#include "qdesigner_utils_p.h"
+#include <QtGui/QPalette>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+ class PromotionTaskMenu;
+}
+
+class QToolBox;
+
+class QAction;
+class QMenu;
+
+class QDESIGNER_SHARED_EXPORT QToolBoxHelper : public QObject
+{
+ Q_OBJECT
+
+ explicit QToolBoxHelper(QToolBox *toolbox);
+public:
+ // Install helper on QToolBox
+ static void install(QToolBox *toolbox);
+ static QToolBoxHelper *helperOf(const QToolBox *toolbox);
+ // Convenience to add a menu on a toolbox
+ static QMenu *addToolBoxContextMenuActions(const QToolBox *toolbox, QMenu *popup);
+
+ QPalette::ColorRole currentItemBackgroundRole() const;
+ void setCurrentItemBackgroundRole(QPalette::ColorRole role);
+
+ bool eventFilter(QObject *watched, QEvent *event);
+ // Add context menu and return page submenu or 0.
+
+ QMenu *addContextMenuActions(QMenu *popup) const;
+
+private slots:
+ void removeCurrentPage();
+ void addPage();
+ void addPageAfter();
+ void changeOrder();
+
+private:
+ QToolBox *m_toolbox;
+ QAction *m_actionDeletePage;
+ QAction *m_actionInsertPage;
+ QAction *m_actionInsertPageAfter;
+ QAction *m_actionChangePageOrder;
+ qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu;
+};
+
+// PropertySheet to handle the page properties
+class QDESIGNER_SHARED_EXPORT QToolBoxWidgetPropertySheet : public QDesignerPropertySheet {
+public:
+ explicit QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent = 0);
+
+ virtual void setProperty(int index, const QVariant &value);
+ virtual QVariant property(int index) const;
+ virtual bool reset(int index);
+ virtual bool isEnabled(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:
+ enum ToolBoxProperty { PropertyCurrentItemText, PropertyCurrentItemName, PropertyCurrentItemIcon,
+ PropertyCurrentItemToolTip, PropertyTabSpacing, PropertyToolBoxNone };
+
+ static ToolBoxProperty toolBoxPropertyFromName(const QString &name);
+ QToolBox *m_toolBox;
+ struct PageData
+ {
+ qdesigner_internal::PropertySheetStringValue text;
+ qdesigner_internal::PropertySheetStringValue tooltip;
+ qdesigner_internal::PropertySheetIconValue icon;
+ };
+ QMap<QWidget *, PageData> m_pageToData;
+};
+
+typedef QDesignerPropertySheetFactory<QToolBox, QToolBoxWidgetPropertySheet> QToolBoxWidgetPropertySheetFactory;
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_TOOLBOX_H
diff --git a/tools/designer/src/lib/shared/qdesigner_utils.cpp b/tools/designer/src/lib/shared/qdesigner_utils.cpp
new file mode 100644
index 0000000..d2f092e
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_utils.cpp
@@ -0,0 +1,734 @@
+/****************************************************************************
+**
+** 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_utils_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "abstractformbuilder.h"
+#include "formwindowbase_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerIconCacheInterface>
+#include <QtDesigner/QDesignerResourceBrowserInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QDesignerTaskMenuExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QIcon>
+#include <QtGui/QPixmap>
+#include <QtCore/QDir>
+
+#include <QtGui/QApplication>
+#include <QtCore/QProcess>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QQueue>
+#include <QtGui/QListWidget>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QTableWidget>
+#include <QtGui/QComboBox>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal
+{
+ QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message)
+ {
+ qWarning("Designer: %s", qPrintable(message));
+ }
+
+ void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item)
+ {
+ if (!item)
+ return;
+
+ for (int c = 0; c < item->columnCount(); c++) {
+ const QVariant v = item->data(c, Qt::DecorationPropertyRole);
+ if (qVariantCanConvert<PropertySheetIconValue>(v))
+ item->setIcon(c, iconCache->icon(qVariantValue<PropertySheetIconValue>(v)));
+ }
+ }
+
+ void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item)
+ {
+ if (!item)
+ return;
+
+ const QVariant v = item->data(Qt::DecorationPropertyRole);
+ if (qVariantCanConvert<PropertySheetIconValue>(v))
+ item->setIcon(iconCache->icon(qVariantValue<PropertySheetIconValue>(v)));
+ }
+
+ void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item)
+ {
+ if (!item)
+ return;
+
+ const QVariant v = item->data(Qt::DecorationPropertyRole);
+ if (qVariantCanConvert<PropertySheetIconValue>(v))
+ item->setIcon(iconCache->icon(qVariantValue<PropertySheetIconValue>(v)));
+ }
+
+ void reloadIconResources(DesignerIconCache *iconCache, QObject *object)
+ {
+ if (QListWidget *listWidget = qobject_cast<QListWidget *>(object)) {
+ for (int i = 0; i < listWidget->count(); i++)
+ reloadListItem(iconCache, listWidget->item(i));
+ } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(object)) {
+ for (int i = 0; i < comboBox->count(); i++) {
+ const QVariant v = comboBox->itemData(i, Qt::DecorationPropertyRole);
+ if (qVariantCanConvert<PropertySheetIconValue>(v)) {
+ QIcon icon = iconCache->icon(qVariantValue<PropertySheetIconValue>(v));
+ comboBox->setItemIcon(i, icon);
+ comboBox->setItemData(i, icon);
+ }
+ }
+ } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget *>(object)) {
+ reloadTreeItem(iconCache, treeWidget->headerItem());
+ QQueue<QTreeWidgetItem *> itemsQueue;
+ for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
+ itemsQueue.enqueue(treeWidget->topLevelItem(i));
+ while (!itemsQueue.isEmpty()) {
+ QTreeWidgetItem *item = itemsQueue.dequeue();
+ for (int i = 0; i < item->childCount(); i++)
+ itemsQueue.enqueue(item->child(i));
+ reloadTreeItem(iconCache, item);
+ }
+ } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget *>(object)) {
+ const int columnCount = tableWidget->columnCount();
+ const int rowCount = tableWidget->rowCount();
+ for (int c = 0; c < columnCount; c++)
+ reloadTableItem(iconCache, tableWidget->horizontalHeaderItem(c));
+ for (int r = 0; r < rowCount; r++)
+ reloadTableItem(iconCache, tableWidget->verticalHeaderItem(r));
+ for (int c = 0; c < columnCount; c++)
+ for (int r = 0; r < rowCount; r++)
+ reloadTableItem(iconCache, tableWidget->item(r, c));
+ }
+ }
+
+ // ------------- DesignerMetaEnum
+ DesignerMetaEnum::DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator) :
+ MetaEnum<int>(name, scope, separator)
+ {
+ }
+
+
+ QString DesignerMetaEnum::toString(int value, SerializationMode sm, bool *ok) const
+ {
+ // find value
+ bool valueOk;
+ const QString item = valueToKey(value, &valueOk);
+ if (ok)
+ *ok = valueOk;
+
+ if (!valueOk || sm == NameOnly)
+ return item;
+
+ QString qualifiedItem;
+ appendQualifiedName(item, qualifiedItem);
+ return qualifiedItem;
+ }
+
+ QString DesignerMetaEnum::messageToStringFailed(int value) const
+ {
+ return QCoreApplication::translate("DesignerMetaEnum", "%1 is not a valid enumeration value of '%2'.").arg(value).arg(name());
+ }
+
+ QString DesignerMetaEnum::messageParseFailed(const QString &s) const
+ {
+ return QCoreApplication::translate("DesignerMetaEnum", "'%1' could not be converted to an enumeration value of type '%2'.").arg(s).arg(name());
+ }
+ // -------------- DesignerMetaFlags
+ DesignerMetaFlags::DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator) :
+ MetaEnum<uint>(name, scope, separator)
+ {
+ }
+
+ QStringList DesignerMetaFlags::flags(int ivalue) const
+ {
+ typedef MetaEnum<uint>::KeyToValueMap::const_iterator KeyToValueMapIterator;
+ QStringList rc;
+ const uint v = static_cast<uint>(ivalue);
+ const KeyToValueMapIterator cend = keyToValueMap().constEnd();
+ for (KeyToValueMapIterator it = keyToValueMap().constBegin();it != cend; ++it ) {
+ const uint itemValue = it.value();
+ // Check for equality first as flag values can be 0 or -1, too. Takes preference over a bitwise flag
+ if (v == itemValue) {
+ rc.clear();
+ rc.push_back(it.key());
+ return rc;
+ }
+ // Do not add 0-flags (None-flags)
+ if (itemValue)
+ if ((v & itemValue) == itemValue)
+ rc.push_back(it.key());
+ }
+ return rc;
+ }
+
+
+ QString DesignerMetaFlags::toString(int value, SerializationMode sm) const
+ {
+ const QStringList flagIds = flags(value);
+ if (flagIds.empty())
+ return QString();
+
+ const QChar delimiter = QLatin1Char('|');
+ QString rc;
+ const QStringList::const_iterator cend = flagIds.constEnd();
+ for (QStringList::const_iterator it = flagIds.constBegin(); it != cend; ++it) {
+ if (!rc.isEmpty())
+ rc += delimiter ;
+ if (sm == FullyQualified)
+ appendQualifiedName(*it, rc);
+ else
+ rc += *it;
+ }
+ return rc;
+ }
+
+
+ int DesignerMetaFlags::parseFlags(const QString &s, bool *ok) const
+ {
+ if (s.isEmpty()) {
+ if (ok)
+ *ok = true;
+ return 0;
+ }
+ uint flags = 0;
+ bool valueOk = true;
+ QStringList keys = s.split(QString(QLatin1Char('|')));
+ const QStringList::iterator cend = keys.end();
+ for (QStringList::iterator it = keys.begin(); it != cend; ++it) {
+ const uint flagValue = keyToValue(*it, &valueOk);
+ if (!valueOk) {
+ flags = 0;
+ break;
+ }
+ flags |= flagValue;
+ }
+ if (ok)
+ *ok = valueOk;
+ return static_cast<int>(flags);
+ }
+
+ QString DesignerMetaFlags::messageParseFailed(const QString &s) const
+ {
+ return QCoreApplication::translate("DesignerMetaFlags", "'%1' could not be converted to a flag value of type '%2'.").arg(s).arg(name());
+ }
+
+ // ---------- PropertySheetEnumValue
+
+ PropertySheetEnumValue::PropertySheetEnumValue(int v, const DesignerMetaEnum &me) :
+ value(v),
+ metaEnum(me)
+ {
+ }
+ PropertySheetEnumValue::PropertySheetEnumValue() :
+ value(0)
+ {
+ }
+
+ // ---------------- PropertySheetFlagValue
+ PropertySheetFlagValue::PropertySheetFlagValue(int v, const DesignerMetaFlags &mf) :
+ value(v),
+ metaFlags(mf)
+ {
+ }
+
+ PropertySheetFlagValue::PropertySheetFlagValue() :
+ value(0)
+ {
+ }
+
+ // ---------------- PropertySheetPixmapValue
+ PropertySheetPixmapValue::PropertySheetPixmapValue(const QString &path) : m_path(path)
+ {
+ }
+
+ PropertySheetPixmapValue::PropertySheetPixmapValue()
+ {
+ }
+
+ PropertySheetPixmapValue::PixmapSource PropertySheetPixmapValue::getPixmapSource(QDesignerFormEditorInterface *core, const QString & path)
+ {
+ if (const QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core))
+ return lang->isLanguageResource(path) ? LanguageResourcePixmap : FilePixmap;
+ return path.startsWith(QLatin1Char(':')) ? ResourcePixmap : FilePixmap;
+ }
+
+ int PropertySheetPixmapValue::compare(const PropertySheetPixmapValue &other) const
+ {
+ return m_path.compare(other.m_path);
+ }
+
+ QString PropertySheetPixmapValue::path() const
+ {
+ return m_path;
+ }
+
+ void PropertySheetPixmapValue::setPath(const QString &path)
+ {
+ if (m_path == path)
+ return;
+ m_path = path;
+ }
+
+ // ---------- PropertySheetIconValue
+ PropertySheetIconValue::PropertySheetIconValue(const PropertySheetPixmapValue &pixmap)
+ {
+ setPixmap(QIcon::Normal, QIcon::Off, pixmap);
+ }
+
+ PropertySheetIconValue::PropertySheetIconValue()
+ {
+ }
+
+ bool PropertySheetIconValue::equals(const PropertySheetIconValue &rhs) const
+ {
+ return m_paths == rhs.m_paths;
+ }
+
+ bool PropertySheetIconValue::operator<(const PropertySheetIconValue &other) const
+ {
+ QMapIterator<ModeStateKey, PropertySheetPixmapValue> itThis(m_paths);
+ QMapIterator<ModeStateKey, PropertySheetPixmapValue> itOther(other.m_paths);
+ while (itThis.hasNext() && itOther.hasNext()) {
+ const ModeStateKey thisPair = itThis.next().key();
+ const ModeStateKey otherPair = itOther.next().key();
+ if (thisPair < otherPair)
+ return true;
+ else if (otherPair < thisPair)
+ return false;
+ const int crc = itThis.value().compare(itOther.value());
+ if (crc < 0)
+ return true;
+ if (crc > 0)
+ return false;
+ }
+ if (itOther.hasNext())
+ return true;
+ return false;
+ }
+
+ PropertySheetPixmapValue PropertySheetIconValue::pixmap(QIcon::Mode mode, QIcon::State state) const
+ {
+ const ModeStateKey pair = qMakePair(mode, state);
+ return m_paths.value(pair);
+ }
+
+ void PropertySheetIconValue::setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &pixmap)
+ {
+ const ModeStateKey pair = qMakePair(mode, state);
+ if (pixmap.path().isEmpty())
+ m_paths.remove(pair);
+ else
+ m_paths.insert(pair, pixmap);
+ }
+
+ QPixmap DesignerPixmapCache::pixmap(const PropertySheetPixmapValue &value) const
+ {
+ QMap<PropertySheetPixmapValue, QPixmap>::const_iterator it = m_cache.constFind(value);
+ if (it != m_cache.constEnd())
+ return it.value();
+
+ QPixmap pix = QPixmap(value.path());
+ m_cache.insert(value, pix);
+ return pix;
+ }
+
+ void DesignerPixmapCache::clear()
+ {
+ m_cache.clear();
+ }
+
+ DesignerPixmapCache::DesignerPixmapCache(QObject *parent)
+ : QObject(parent)
+ {
+ }
+
+ QIcon DesignerIconCache::icon(const PropertySheetIconValue &value) const
+ {
+ QMap<PropertySheetIconValue, QIcon>::const_iterator it = m_cache.constFind(value);
+ if (it != m_cache.constEnd())
+ return it.value();
+
+ QIcon icon;
+ QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> paths = value.paths();
+ QMapIterator<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> itPath(paths);
+ while (itPath.hasNext()) {
+ QPair<QIcon::Mode, QIcon::State> pair = itPath.next().key();
+ icon.addPixmap(m_pixmapCache->pixmap(itPath.value()), pair.first, pair.second);
+ }
+ m_cache.insert(value, icon);
+ return icon;
+ }
+
+ void DesignerIconCache::clear()
+ {
+ m_cache.clear();
+ }
+
+ DesignerIconCache::DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent)
+ : QObject(parent),
+ m_pixmapCache(pixmapCache)
+ {
+
+ }
+
+ PropertySheetStringValue::PropertySheetStringValue(const QString &value,
+ bool translatable, const QString &disambiguation, const QString &comment)
+ : m_value(value), m_translatable(translatable), m_disambiguation(disambiguation), m_comment(comment)
+ { }
+
+ QString PropertySheetStringValue::value() const
+ {
+ return m_value;
+ }
+
+ void PropertySheetStringValue::setValue(const QString &value)
+ {
+ m_value = value;
+ }
+
+ bool PropertySheetStringValue::translatable() const
+ {
+ return m_translatable;
+ }
+
+ void PropertySheetStringValue::setTranslatable(bool translatable)
+ {
+ m_translatable = translatable;
+ }
+
+ QString PropertySheetStringValue::disambiguation() const
+ {
+ return m_disambiguation;
+ }
+
+ void PropertySheetStringValue::setDisambiguation(const QString &disambiguation)
+ {
+ m_disambiguation = disambiguation;
+ }
+
+ QString PropertySheetStringValue::comment() const
+ {
+ return m_comment;
+ }
+
+ void PropertySheetStringValue::setComment(const QString &comment)
+ {
+ m_comment = comment;
+ }
+
+ bool PropertySheetStringValue::equals(const PropertySheetStringValue &rhs) const
+ {
+ return (m_value == rhs.m_value) && (m_translatable == rhs.m_translatable)
+ && (m_disambiguation == rhs.m_disambiguation) && (m_comment == rhs.m_comment);
+ }
+
+ PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence &value,
+ bool translatable, const QString &disambiguation, const QString &comment)
+ : m_value(value),
+ m_standardKey(QKeySequence::UnknownKey),
+ m_translatable(translatable),
+ m_disambiguation(disambiguation),
+ m_comment(comment)
+ { }
+
+ PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey,
+ bool translatable, const QString &disambiguation, const QString &comment)
+ : m_value(QKeySequence(standardKey)),
+ m_standardKey(standardKey),
+ m_translatable(translatable),
+ m_disambiguation(disambiguation),
+ m_comment(comment)
+ { }
+
+ QKeySequence PropertySheetKeySequenceValue::value() const
+ {
+ return m_value;
+ }
+
+ void PropertySheetKeySequenceValue::setValue(const QKeySequence &value)
+ {
+ m_value = value;
+ m_standardKey = QKeySequence::UnknownKey;
+ }
+
+ QKeySequence::StandardKey PropertySheetKeySequenceValue::standardKey() const
+ {
+ return m_standardKey;
+ }
+
+ void PropertySheetKeySequenceValue::setStandardKey(const QKeySequence::StandardKey &standardKey)
+ {
+ m_value = QKeySequence(standardKey);
+ m_standardKey = standardKey;
+ }
+
+ bool PropertySheetKeySequenceValue::isStandardKey() const
+ {
+ return m_standardKey != QKeySequence::UnknownKey;
+ }
+
+ QString PropertySheetKeySequenceValue::comment() const
+ {
+ return m_comment;
+ }
+
+ void PropertySheetKeySequenceValue::setComment(const QString &comment)
+ {
+ m_comment = comment;
+ }
+
+ QString PropertySheetKeySequenceValue::disambiguation() const
+ {
+ return m_disambiguation;
+ }
+
+ void PropertySheetKeySequenceValue::setDisambiguation(const QString &disambiguation)
+ {
+ m_disambiguation = disambiguation;
+ }
+
+ bool PropertySheetKeySequenceValue::translatable() const
+ {
+ return m_translatable;
+ }
+
+ void PropertySheetKeySequenceValue::setTranslatable(bool translatable)
+ {
+ m_translatable = translatable;
+ }
+
+ bool PropertySheetKeySequenceValue::equals(const PropertySheetKeySequenceValue &rhs) const
+ {
+ return (m_value == rhs.m_value) && (m_standardKey == rhs.m_standardKey)
+ && (m_translatable == rhs.m_translatable) && (m_disambiguation == rhs.m_disambiguation) && (m_comment == rhs.m_comment);
+ }
+
+ class StateMap
+ {
+ public:
+ StateMap()
+ {
+ m_stateToFlag.insert(qMakePair(QIcon::Normal, QIcon::Off), 0x01);
+ m_stateToFlag.insert(qMakePair(QIcon::Normal, QIcon::On), 0x02);
+ m_stateToFlag.insert(qMakePair(QIcon::Disabled, QIcon::Off), 0x04);
+ m_stateToFlag.insert(qMakePair(QIcon::Disabled, QIcon::On), 0x08);
+ m_stateToFlag.insert(qMakePair(QIcon::Active, QIcon::Off), 0x10);
+ m_stateToFlag.insert(qMakePair(QIcon::Active, QIcon::On), 0x20);
+ m_stateToFlag.insert(qMakePair(QIcon::Selected, QIcon::Off), 0x40);
+ m_stateToFlag.insert(qMakePair(QIcon::Selected, QIcon::On), 0x80);
+
+ m_flagToState.insert(0x01, qMakePair(QIcon::Normal, QIcon::Off));
+ m_flagToState.insert(0x02, qMakePair(QIcon::Normal, QIcon::On));
+ m_flagToState.insert(0x04, qMakePair(QIcon::Disabled, QIcon::Off));
+ m_flagToState.insert(0x08, qMakePair(QIcon::Disabled, QIcon::On));
+ m_flagToState.insert(0x10, qMakePair(QIcon::Active, QIcon::Off));
+ m_flagToState.insert(0x20, qMakePair(QIcon::Active, QIcon::On));
+ m_flagToState.insert(0x40, qMakePair(QIcon::Selected, QIcon::Off));
+ m_flagToState.insert(0x80, qMakePair(QIcon::Selected, QIcon::On));
+ }
+ uint flag(const QPair<QIcon::Mode, QIcon::State> &pair) const
+ {
+ return m_stateToFlag.value(pair);
+ }
+ QPair<QIcon::Mode, QIcon::State> state(uint flag) const
+ {
+ return m_flagToState.value(flag);
+ }
+ private:
+ QMap<QPair<QIcon::Mode, QIcon::State>, uint > m_stateToFlag;
+ QMap<uint, QPair<QIcon::Mode, QIcon::State> > m_flagToState;
+ };
+
+ Q_GLOBAL_STATIC(StateMap, stateMap)
+
+ uint PropertySheetIconValue::mask() const
+ {
+ uint flags = 0;
+ QMapIterator<ModeStateKey, PropertySheetPixmapValue> itPath(m_paths);
+ while (itPath.hasNext())
+ flags |= stateMap()->flag(itPath.next().key());
+ return flags;
+ }
+
+ uint PropertySheetIconValue::compare(const PropertySheetIconValue &other) const
+ {
+ uint diffMask = mask() | other.mask();
+ for (int i = 0; i < 8; i++) {
+ uint flag = 1 << i;
+ if (diffMask & flag) { // if state is set in both icons, compare the values
+ const ModeStateKey state = stateMap()->state(flag);
+ if (pixmap(state.first, state.second) == other.pixmap(state.first, state.second))
+ diffMask &= ~flag;
+ }
+ }
+ return diffMask;
+ }
+
+ void PropertySheetIconValue::assign(const PropertySheetIconValue &other, uint mask)
+ {
+ for (int i = 0; i < 8; i++) {
+ uint flag = 1 << i;
+ if (mask & flag) {
+ const ModeStateKey state = stateMap()->state(flag);
+ setPixmap(state.first, state.second, other.pixmap(state.first, state.second));
+ }
+ }
+ }
+
+ PropertySheetIconValue::ModeStateToPixmapMap PropertySheetIconValue::paths() const
+ {
+ return m_paths;
+ }
+
+ QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand *createTextPropertyCommand(const QString &propertyName, const QString &text, QObject *object, QDesignerFormWindowInterface *fw)
+ {
+ if (text.isEmpty()) {
+ ResetPropertyCommand *cmd = new ResetPropertyCommand(fw);
+ cmd->init(object, propertyName);
+ return cmd;
+ }
+ SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+ cmd->init(object, propertyName, text);
+ return cmd;
+ }
+
+ QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget)
+ {
+ QAction *action = 0;
+ if (const QDesignerTaskMenuExtension *taskMenu = qt_extension<QDesignerTaskMenuExtension*>(core->extensionManager(), managedWidget)) {
+ action = taskMenu->preferredEditAction();
+ if (!action) {
+ const QList<QAction *> actions = taskMenu->taskActions();
+ if (!actions.isEmpty())
+ action = actions.first();
+ }
+ }
+ if (!action) {
+ if (const QDesignerTaskMenuExtension *taskMenu = qobject_cast<QDesignerTaskMenuExtension *>(
+ core->extensionManager()->extension(managedWidget, QLatin1String("QDesignerInternalTaskMenuExtension")))) {
+ action = taskMenu->preferredEditAction();
+ if (!action) {
+ const QList<QAction *> actions = taskMenu->taskActions();
+ if (!actions.isEmpty())
+ action = actions.first();
+ }
+ }
+ }
+ return action;
+ }
+
+ QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UIC_Mode mode, QByteArray& ba, QString &errorMessage)
+ {
+ QStringList argv;
+ QString binary = QLibraryInfo::location(QLibraryInfo::BinariesPath);
+ binary += QDir::separator();
+ switch (mode) {
+ case UIC_GenerateCode:
+ binary += QLatin1String("uic");
+ break;
+ case UIC_ConvertV3:
+ binary += QLatin1String("uic3");
+ argv += QLatin1String("-convert");
+ break;
+ }
+ argv += fileName;
+ QProcess uic;
+ uic.start(binary, argv);
+ if (!uic.waitForStarted()) {
+ errorMessage = QApplication::translate("Designer", "Unable to launch %1.").arg(binary);
+ return false;
+ }
+ if (!uic.waitForFinished()) {
+ errorMessage = QApplication::translate("Designer", "%1 timed out.").arg(binary);
+ return false;
+ }
+ if (uic.exitCode()) {
+ errorMessage = QString::fromAscii(uic.readAllStandardError());
+ return false;
+ }
+ ba = uic.readAllStandardOutput();
+ return true;
+ }
+
+ QDESIGNER_SHARED_EXPORT QString qtify(const QString &name)
+ {
+ QString qname = name;
+
+ Q_ASSERT(qname.isEmpty() == false);
+
+
+ if (qname.count() > 1 && qname.at(1).isUpper()) {
+ const QChar first = qname.at(0);
+ if (first == QLatin1Char('Q') || first == QLatin1Char('K'))
+ qname.remove(0, 1);
+ }
+
+ const int len = qname.count();
+ for (int i = 0; i < len && qname.at(i).isUpper(); i++)
+ qname[i] = qname.at(i).toLower();
+
+ return qname;
+ }
+
+ // --------------- UpdateBlocker
+ UpdateBlocker::UpdateBlocker(QWidget *w) :
+ m_widget(w),
+ m_enabled(w->updatesEnabled() && w->isVisible())
+ {
+ if (m_enabled)
+ m_widget->setUpdatesEnabled(false);
+ }
+
+ UpdateBlocker::~UpdateBlocker()
+ {
+ if (m_enabled)
+ m_widget->setUpdatesEnabled(true);
+ }
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_utils_p.h b/tools/designer/src/lib/shared/qdesigner_utils_p.h
new file mode 100644
index 0000000..85b3090
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_utils_p.h
@@ -0,0 +1,482 @@
+
+/****************************************************************************
+**
+** 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 QDESIGNER_UTILS_H
+#define QDESIGNER_UTILS_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtCore/QVariant>
+#include <QtCore/QMap>
+#include <QtGui/QMainWindow>
+#include <QtGui/QIcon>
+#include <QtGui/QPixmap>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+class QDesignerFormWindowCommand;
+class DesignerIconCache;
+class FormWindowBase;
+
+
+QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message);
+
+QDESIGNER_SHARED_EXPORT void reloadIconResources(DesignerIconCache *iconCache, QObject *object);
+
+/* Flag/Enumeration helpers for the property sheet: Enumeration or flag values are returned by the property sheet
+ * as a pair of meta type and integer value.
+ * The meta type carries all the information required for the property editor and serialization
+ * by the form builders (names, etc).
+ * Note that the property editor uses unqualified names ("Cancel") while the form builder serialization (uic)
+ * requires the whole string
+ * ("QDialogButtonBox::Cancel" or "com.trolltech.qt.gui.QDialogButtonBox.StandardButton.Cancel").*/
+
+/* --------- MetaEnum: Base class representing a QMetaEnum with lookup functions
+ * in both ways. Template of int type since unsigned is more suitable for flags.
+ * The keyToValue() is ignorant of scopes, it can handle fully qualified or unqualified names. */
+
+template <class IntType>
+class MetaEnum
+{
+public:
+ typedef QMap<QString, IntType> KeyToValueMap;
+
+ MetaEnum(const QString &name, const QString &scope, const QString &separator);
+ MetaEnum() {}
+ void addKey(IntType value, const QString &name);
+
+ QString valueToKey(IntType value, bool *ok = 0) const;
+ // Ignorant of scopes.
+ IntType keyToValue(QString key, bool *ok = 0) const;
+
+ const QString &name() const { return m_name; }
+ const QString &scope() const { return m_scope; }
+ const QString &separator() const { return m_separator; }
+
+ const QStringList &keys() const { return m_keys; }
+ const KeyToValueMap &keyToValueMap() const { return m_keyToValueMap; }
+
+protected:
+ void appendQualifiedName(const QString &key, QString &target) const;
+
+private:
+ QString m_name;
+ QString m_scope;
+ QString m_separator;
+ KeyToValueMap m_keyToValueMap;
+ QStringList m_keys;
+};
+
+template <class IntType>
+MetaEnum<IntType>::MetaEnum(const QString &name, const QString &scope, const QString &separator) :
+ m_name(name),
+ m_scope(scope),
+ m_separator(separator)
+{
+}
+
+template <class IntType>
+void MetaEnum<IntType>::addKey(IntType value, const QString &name)
+{
+ m_keyToValueMap.insert(name, value);
+ m_keys.append(name);
+}
+
+template <class IntType>
+QString MetaEnum<IntType>::valueToKey(IntType value, bool *ok) const
+{
+ const QString rc = m_keyToValueMap.key(value);
+ if (ok)
+ *ok = !rc.isEmpty();
+ return rc;
+}
+
+template <class IntType>
+IntType MetaEnum<IntType>::keyToValue(QString key, bool *ok) const
+{
+ if (!m_scope.isEmpty() && key.startsWith(m_scope))
+ key.remove(0, m_scope.size() + m_separator.size());
+ const Q_TYPENAME KeyToValueMap::const_iterator it = m_keyToValueMap.find(key);
+ const bool found = it != m_keyToValueMap.constEnd();
+ if (ok)
+ *ok = found;
+ return found ? it.value() : IntType(0);
+}
+
+template <class IntType>
+void MetaEnum<IntType>::appendQualifiedName(const QString &key, QString &target) const
+{
+ if (!m_scope.isEmpty()) {
+ target += m_scope;
+ target += m_separator;
+ }
+ target += key;
+}
+
+// -------------- DesignerMetaEnum: Meta type for enumerations
+
+class QDESIGNER_SHARED_EXPORT DesignerMetaEnum : public MetaEnum<int>
+{
+public:
+ DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator);
+ DesignerMetaEnum() {}
+
+ enum SerializationMode { FullyQualified, NameOnly };
+ QString toString(int value, SerializationMode sm, bool *ok = 0) const;
+
+ QString messageToStringFailed(int value) const;
+ QString messageParseFailed(const QString &s) const;
+
+ // parse a string (ignorant of scopes)
+ int parseEnum(const QString &s, bool *ok = 0) const { return keyToValue(s, ok); }
+};
+
+// -------------- DesignerMetaFlags: Meta type for flags.
+// Note that while the handling of flags is done using unsigned integers, the actual values returned
+// by the property system are integers.
+
+class QDESIGNER_SHARED_EXPORT DesignerMetaFlags : public MetaEnum<uint>
+{
+public:
+ DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator);
+ DesignerMetaFlags() {}
+
+ enum SerializationMode { FullyQualified, NameOnly };
+ QString toString(int value, SerializationMode sm) const;
+ QStringList flags(int value) const;
+
+ QString messageParseFailed(const QString &s) const;
+ // parse a string (ignorant of scopes)
+ int parseFlags(const QString &s, bool *ok = 0) const;
+};
+
+// -------------- EnumValue: Returned by the property sheet for enumerations
+
+struct QDESIGNER_SHARED_EXPORT PropertySheetEnumValue
+{
+ PropertySheetEnumValue(int v, const DesignerMetaEnum &me);
+ PropertySheetEnumValue();
+
+ int value;
+ DesignerMetaEnum metaEnum;
+};
+
+// -------------- FlagValue: Returned by the property sheet for flags
+
+struct QDESIGNER_SHARED_EXPORT PropertySheetFlagValue
+{
+ PropertySheetFlagValue(int v, const DesignerMetaFlags &mf);
+ PropertySheetFlagValue();
+
+ int value;
+ DesignerMetaFlags metaFlags;
+};
+
+// -------------- PixmapValue: Returned by the property sheet for pixmaps
+class QDESIGNER_SHARED_EXPORT PropertySheetPixmapValue
+{
+public:
+ PropertySheetPixmapValue(const QString &path);
+ PropertySheetPixmapValue();
+
+ bool operator==(const PropertySheetPixmapValue &other) const { return compare(other) == 0; }
+ bool operator!=(const PropertySheetPixmapValue &other) const { return compare(other) != 0; }
+ bool operator<(const PropertySheetPixmapValue &other) const { return compare(other) < 0; }
+
+ // Check where a pixmap comes from
+ enum PixmapSource { LanguageResourcePixmap , ResourcePixmap, FilePixmap };
+ static PixmapSource getPixmapSource(QDesignerFormEditorInterface *core, const QString & path);
+
+ PixmapSource pixmapSource(QDesignerFormEditorInterface *core) const { return getPixmapSource(core, m_path); }
+
+ QString path() const;
+ void setPath(const QString &path); // passing the empty path resets the pixmap
+
+ int compare(const PropertySheetPixmapValue &other) const;
+
+private:
+ QString m_path;
+};
+
+// -------------- IconValue: Returned by the property sheet for icons
+
+class QDESIGNER_SHARED_EXPORT PropertySheetIconValue
+{
+ public:
+ PropertySheetIconValue(const PropertySheetPixmapValue &pixmap);
+ PropertySheetIconValue();
+
+ bool operator==(const PropertySheetIconValue &other) const { return equals(other); }
+ bool operator!=(const PropertySheetIconValue &other) const { return !equals(other); }
+ bool operator<(const PropertySheetIconValue &other) const;
+
+ PropertySheetPixmapValue pixmap(QIcon::Mode mode, QIcon::State state) const;
+ void setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &path); // passing the empty path resets the pixmap
+
+ uint mask() const;
+ uint compare(const PropertySheetIconValue &other) const;
+ void assign(const PropertySheetIconValue &other, uint mask);
+
+ typedef QPair<QIcon::Mode, QIcon::State> ModeStateKey;
+ typedef QMap<ModeStateKey, PropertySheetPixmapValue> ModeStateToPixmapMap;
+
+ ModeStateToPixmapMap paths() const;
+
+private:
+ bool equals(const PropertySheetIconValue &rhs) const;
+
+ ModeStateToPixmapMap m_paths;
+};
+
+class QDESIGNER_SHARED_EXPORT DesignerPixmapCache : public QObject
+{
+ Q_OBJECT
+public:
+ DesignerPixmapCache(QObject *parent = 0);
+ QPixmap pixmap(const PropertySheetPixmapValue &value) const;
+ void clear();
+signals:
+ void reloaded();
+private:
+ mutable QMap<PropertySheetPixmapValue, QPixmap> m_cache;
+ friend class FormWindowBase;
+};
+
+class QDESIGNER_SHARED_EXPORT DesignerIconCache : public QObject
+{
+ Q_OBJECT
+public:
+ DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent = 0);
+ QIcon icon(const PropertySheetIconValue &value) const;
+ void clear();
+signals:
+ void reloaded();
+private:
+ mutable QMap<PropertySheetIconValue, QIcon> m_cache;
+ DesignerPixmapCache *m_pixmapCache;
+ friend class FormWindowBase;
+};
+
+// -------------- StringValue: Returned by the property sheet for strings
+class QDESIGNER_SHARED_EXPORT PropertySheetStringValue
+{
+public:
+ PropertySheetStringValue(const QString &value = QString(),
+ bool translatable = true,
+ const QString &disambiguation = QString(),
+ const QString &comment = QString());
+
+ bool operator==(const PropertySheetStringValue &other) const { return equals(other); }
+ bool operator!=(const PropertySheetStringValue &other) const { return !equals(other); }
+
+ QString value() const;
+ void setValue(const QString &value);
+ bool translatable() const;
+ void setTranslatable(bool translatable);
+ QString disambiguation() const;
+ void setDisambiguation(const QString &disambiguation);
+ QString comment() const;
+ void setComment(const QString &comment);
+
+private:
+ bool equals(const PropertySheetStringValue &rhs) const;
+
+ QString m_value;
+ bool m_translatable;
+ QString m_disambiguation;
+ QString m_comment;
+};
+
+
+
+// -------------- StringValue: Returned by the property sheet for strings
+class QDESIGNER_SHARED_EXPORT PropertySheetKeySequenceValue
+{
+public:
+ PropertySheetKeySequenceValue(const QKeySequence &value = QKeySequence(),
+ bool translatable = true,
+ const QString &disambiguation = QString(),
+ const QString &comment = QString());
+ PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey,
+ bool translatable = true,
+ const QString &disambiguation = QString(),
+ const QString &comment = QString());
+
+ bool operator==(const PropertySheetKeySequenceValue &other) const { return equals(other); }
+ bool operator!=(const PropertySheetKeySequenceValue &other) const { return !equals(other); }
+
+ QKeySequence value() const;
+ void setValue(const QKeySequence &value);
+ QKeySequence::StandardKey standardKey() const;
+ void setStandardKey(const QKeySequence::StandardKey &standardKey);
+ bool isStandardKey() const;
+
+ bool translatable() const;
+ void setTranslatable(bool translatable);
+ QString disambiguation() const;
+ void setDisambiguation(const QString &disambiguation);
+ QString comment() const;
+ void setComment(const QString &comment);
+
+private:
+ bool equals(const PropertySheetKeySequenceValue &rhs) const;
+
+ QKeySequence m_value;
+ QKeySequence::StandardKey m_standardKey;
+ bool m_translatable;
+ QString m_disambiguation;
+ QString m_comment;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+
+// NOTE: Do not move this code, needed for GCC 3.3
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetEnumValue)
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetFlagValue)
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetPixmapValue)
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetIconValue)
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetStringValue)
+Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetKeySequenceValue)
+
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+
+// Create a command to change a text property (that is, create a reset property command if the text is empty)
+QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand *createTextPropertyCommand(const QString &propertyName, const QString &text, QObject *object, QDesignerFormWindowInterface *fw);
+
+// Returns preferred task menu action for managed widget
+QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget);
+
+// Convenience to run UIC
+enum UIC_Mode { UIC_GenerateCode, UIC_ConvertV3 };
+QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UIC_Mode mode, QByteArray& ba, QString &errorMessage);
+
+// Find a suitable variable name for a class.
+QDESIGNER_SHARED_EXPORT QString qtify(const QString &name);
+
+/* UpdateBlocker: Blocks the updates of the widget passed on while in scope.
+ * Does nothing if the incoming widget already has updatesEnabled==false
+ * which is important to avoid side-effects when putting it into QStackedLayout. */
+
+class QDESIGNER_SHARED_EXPORT UpdateBlocker {
+ Q_DISABLE_COPY(UpdateBlocker)
+
+public:
+ UpdateBlocker(QWidget *w);
+ ~UpdateBlocker();
+
+private:
+ QWidget *m_widget;
+ const bool m_enabled;
+};
+
+namespace Utils {
+
+inline int valueOf(const QVariant &value, bool *ok = 0)
+{
+ if (qVariantCanConvert<PropertySheetEnumValue>(value)) {
+ if (ok)
+ *ok = true;
+ return qVariantValue<PropertySheetEnumValue>(value).value;
+ }
+ else if (qVariantCanConvert<PropertySheetFlagValue>(value)) {
+ if (ok)
+ *ok = true;
+ return qVariantValue<PropertySheetFlagValue>(value).value;
+ }
+ return value.toInt(ok);
+}
+
+inline bool isObjectAncestorOf(QObject *ancestor, QObject *child)
+{
+ QObject *obj = child;
+ while (obj != 0) {
+ if (obj == ancestor)
+ return true;
+ obj = obj->parent();
+ }
+ return false;
+}
+
+inline bool isCentralWidget(QDesignerFormWindowInterface *fw, QWidget *widget)
+{
+ if (! fw || ! widget)
+ return false;
+
+ if (widget == fw->mainContainer())
+ return true;
+
+ // ### generalize for other containers
+ if (QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer())) {
+ return mw->centralWidget() == widget;
+ }
+
+ return false;
+}
+
+} // namespace Utils
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_UTILS_H
diff --git a/tools/designer/src/lib/shared/qdesigner_widget.cpp b/tools/designer/src/lib/shared/qdesigner_widget.cpp
new file mode 100644
index 0000000..6d2be17
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widget.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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_widget_p.h"
+#include "formwindowbase_p.h"
+#include "grid_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtGui/QPainter>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleOption>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+/* QDesignerDialog / QDesignerWidget are used to paint a grid on QDialog and QWidget main containers
+ * and container extension pages.
+ * The paint routines work as follows:
+ * We need to clean the background here (to make the parent grid disappear in case we are a container page
+ * and to make palette background settings take effect),
+ * which would normally break style sheets with background settings.
+ * So, we manually make the style paint after cleaning. On top comes the grid
+ * In addition, this code works around
+ * the QStyleSheetStyle setting Qt::WA_StyledBackground to false for subclasses of QWidget.
+ */
+
+QDesignerDialog::QDesignerDialog(QDesignerFormWindowInterface *fw, QWidget *parent) :
+ QDialog(parent),
+ m_formWindow(qobject_cast<qdesigner_internal::FormWindowBase*>(fw))
+{
+}
+
+void QDesignerDialog::paintEvent(QPaintEvent *e)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ opt.initFrom(this);
+ p.fillRect(e->rect(), palette().brush(backgroundRole()));
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+ if (m_formWindow && m_formWindow->gridVisible())
+ m_formWindow->designerGrid().paint(p, this, e);
+}
+
+QDesignerWidget::QDesignerWidget(QDesignerFormWindowInterface* formWindow, QWidget *parent) :
+ QWidget(parent),
+ m_formWindow(qobject_cast<qdesigner_internal::FormWindowBase*>(formWindow))
+{
+}
+
+QDesignerWidget::~QDesignerWidget()
+{
+}
+
+QDesignerFormWindowInterface* QDesignerWidget::formWindow() const
+{
+ return m_formWindow;
+}
+
+void QDesignerWidget::paintEvent(QPaintEvent *e)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ opt.initFrom(this);
+ p.fillRect(e->rect(), palette().brush(backgroundRole()));
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+ if (m_formWindow && m_formWindow->gridVisible())
+ m_formWindow->designerGrid().paint(p, this, e);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_widget_p.h b/tools/designer/src/lib/shared/qdesigner_widget_p.h
new file mode 100644
index 0000000..77d3934
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widget_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_WIDGET_H
+#define QDESIGNER_WIDGET_H
+
+#include "shared_global_p.h"
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+namespace qdesigner_internal {
+ class FormWindowBase;
+}
+
+class QDESIGNER_SHARED_EXPORT QDesignerWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit QDesignerWidget(QDesignerFormWindowInterface* formWindow, QWidget *parent = 0);
+ virtual ~QDesignerWidget();
+
+ QDesignerFormWindowInterface* formWindow() const;
+
+ void updatePixmap();
+
+ virtual QSize minimumSizeHint() const
+ { return QWidget::minimumSizeHint().expandedTo(QSize(16, 16)); }
+
+protected:
+ virtual void paintEvent(QPaintEvent *e);
+
+private:
+ qdesigner_internal::FormWindowBase* m_formWindow;
+};
+
+class QDESIGNER_SHARED_EXPORT QDesignerDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit QDesignerDialog(QDesignerFormWindowInterface *fw, QWidget *parent);
+
+ virtual QSize minimumSizeHint() const
+ { return QWidget::minimumSizeHint().expandedTo(QSize(16, 16)); }
+
+protected:
+ void paintEvent(QPaintEvent *e);
+
+private:
+ qdesigner_internal::FormWindowBase* m_formWindow;
+};
+
+class QDESIGNER_SHARED_EXPORT Line : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+public:
+ explicit Line(QWidget *parent) : QFrame(parent)
+ { setAttribute(Qt::WA_MouseNoMask); setFrameStyle(HLine | Sunken); }
+
+ inline void setOrientation(Qt::Orientation orient)
+ { setFrameShape(orient == Qt::Horizontal ? HLine : VLine); }
+
+ inline Qt::Orientation orientation() const
+ { return frameShape() == HLine ? Qt::Horizontal : Qt::Vertical; }
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_WIDGET_H
diff --git a/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp b/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp
new file mode 100644
index 0000000..5ba8ad7
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** 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::QDesignerWidgetBox
+*/
+
+#include "qdesigner_widgetbox_p.h"
+#include "qdesigner_utils_p.h"
+
+#include <ui4_p.h>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtCore/QXmlStreamReader>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+QDesignerWidgetBox::QDesignerWidgetBox(QWidget *parent, Qt::WindowFlags flags)
+ : QDesignerWidgetBoxInterface(parent, flags),
+ m_loadMode(LoadMerge)
+{
+
+}
+
+QDesignerWidgetBox::LoadMode QDesignerWidgetBox::loadMode() const
+{
+ return m_loadMode;
+}
+
+void QDesignerWidgetBox::setLoadMode(LoadMode lm)
+{
+ m_loadMode = lm;
+}
+
+// Convenience to find a widget by class name
+bool QDesignerWidgetBox::findWidget(const QDesignerWidgetBoxInterface *wbox,
+ const QString &className,
+ const QString &category,
+ Widget *widgetData)
+{
+ // Note that entry names do not necessarily match the class name
+ // (at least, not for the standard widgets), so,
+ // look in the XML for the class name of the first widget to appear
+ const QString widgetTag = QLatin1String("<widget");
+ QString pattern = QLatin1String("^<widget\\s+class\\s*=\\s*\"");
+ pattern += className;
+ pattern += QLatin1String("\".*$");
+ const QRegExp regexp(pattern);
+ Q_ASSERT(regexp.isValid());
+ const int catCount = wbox->categoryCount();
+ for (int c = 0; c < catCount; c++) {
+ const Category cat = wbox->category(c);
+ if (category.isEmpty() || cat.name() == category) {
+ const int widgetCount = cat.widgetCount();
+ for (int w = 0; w < widgetCount; w++) {
+ const Widget widget = cat.widget(w);
+ QString xml = widget.domXml(); // Erase the <ui> tag that can be present starting from 4.4
+ const int widgetTagIndex = xml.indexOf(widgetTag);
+ if (widgetTagIndex != -1) {
+ xml.remove(0, widgetTagIndex);
+ if (regexp.exactMatch(xml)) {
+ *widgetData = widget;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// Convenience to create a Dom Widget from widget box xml code.
+DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel,
+ QString *errorMessage)
+{
+ QXmlStreamReader reader(xml);
+ DomUI *ui = 0;
+
+ // The xml description must either contain a root element "ui" with a child element "widget"
+ // or "widget" as the root element (4.3 legacy)
+ const QString widgetTag = QLatin1String("widget");
+
+ while (!reader.atEnd()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement) {
+ const QStringRef name = reader.name();
+ if (ui) {
+ reader.raiseError(tr("Unexpected element <%1>").arg(name.toString()));
+ continue;
+ }
+
+ if (name.compare(QLatin1String("widget"), Qt::CaseInsensitive) == 0) { // 4.3 legacy, wrap into DomUI
+ ui = new DomUI;
+ DomWidget *widget = new DomWidget;
+ widget->read(reader);
+ ui->setElementWidget(widget);
+ } else if (name.compare(QLatin1String("ui"), Qt::CaseInsensitive) == 0) { // 4.4
+ ui = new DomUI;
+ ui->read(reader);
+ } else {
+ reader.raiseError(tr("Unexpected element <%1>").arg(name.toString()));
+ }
+ }
+ }
+
+ if (reader.hasError()) {
+ delete ui;
+ *errorMessage = tr("A parse error occurred at line %1, column %2 of the XML code "
+ "specified for the widget %3: %4\n%5")
+ .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(name)
+ .arg(reader.errorString()).arg(xml);
+ return 0;
+ }
+
+ if (!ui || !ui->elementWidget()) {
+ delete ui;
+ *errorMessage = tr("The XML code specified for the widget %1 does not contain "
+ "any widget elements.\n%2").arg(name).arg(xml);
+ return 0;
+ }
+
+ if (insertFakeTopLevel) {
+ DomWidget *fakeTopLevel = new DomWidget;
+ fakeTopLevel->setAttributeClass(QLatin1String("QWidget"));
+ QList<DomWidget *> children;
+ children.push_back(ui->takeElementWidget());
+ fakeTopLevel->setElementWidget(children);
+ ui->setElementWidget(fakeTopLevel);
+ }
+
+ return ui;
+}
+
+// Convenience to create a Dom Widget from widget box xml code.
+DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel)
+{
+ QString errorMessage;
+ DomUI *rc = xmlToUi(name, xml, insertFakeTopLevel, &errorMessage);
+ if (!rc)
+ qdesigner_internal::designerWarning(errorMessage);
+ return rc;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_widgetbox_p.h b/tools/designer/src/lib/shared/qdesigner_widgetbox_p.h
new file mode 100644
index 0000000..bec0081
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widgetbox_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 QDESIGNER_WIDGETBOX_H
+#define QDESIGNER_WIDGETBOX_H
+
+#include "shared_global_p.h"
+#include <QtDesigner/QDesignerWidgetBoxInterface>
+
+QT_BEGIN_NAMESPACE
+
+class DomUI;
+
+namespace qdesigner_internal {
+
+// A widget box with a load mode that allows for updating custom widgets.
+
+class QDESIGNER_SHARED_EXPORT QDesignerWidgetBox : public QDesignerWidgetBoxInterface
+{
+ Q_OBJECT
+public:
+ enum LoadMode { LoadMerge, LoadReplace, LoadCustomWidgetsOnly };
+
+ QDesignerWidgetBox(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+
+ LoadMode loadMode() const;
+ void setLoadMode(LoadMode lm);
+
+ virtual bool loadContents(const QString &contents) = 0;
+
+ // Convenience to access the widget box icon of a widget. Empty category
+ // matches all
+ virtual QIcon iconForWidget(const QString &className,
+ const QString &category = QString()) const = 0;
+
+ // Convenience to find a widget by class name. Empty category matches all
+ static bool findWidget(const QDesignerWidgetBoxInterface *wbox,
+ const QString &className,
+ const QString &category /* = QString() */,
+ Widget *widgetData);
+ // Convenience functions to create a DomWidget from widget box xml.
+ static DomUI *xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel, QString *errorMessage);
+ static DomUI *xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel);
+
+private:
+ LoadMode m_loadMode;
+};
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_WIDGETBOX_H
diff --git a/tools/designer/src/lib/shared/qdesigner_widgetitem.cpp b/tools/designer/src/lib/shared/qdesigner_widgetitem.cpp
new file mode 100644
index 0000000..029ee89
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widgetitem.cpp
@@ -0,0 +1,345 @@
+/****************************************************************************
+**
+** 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_widgetitem_p.h"
+#include "qdesigner_widget_p.h"
+#include "widgetfactory_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QGridLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QApplication>
+
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <private/qlayout_p.h>
+
+QT_BEGIN_NAMESPACE
+
+enum { DebugWidgetItem = 0 };
+enum { MinimumLength = 10 };
+
+// Widget item creation function to be registered as factory method with
+// QLayoutPrivate
+static QWidgetItem *createDesignerWidgetItem(const QLayout *layout, QWidget *widget)
+{
+ Qt::Orientations orientations;
+ if (qdesigner_internal::QDesignerWidgetItem::check(layout, widget, &orientations)) {
+ if (DebugWidgetItem)
+ qDebug() << "QDesignerWidgetItem: Creating on " << layout << widget << orientations;
+ return new qdesigner_internal::QDesignerWidgetItem(layout, widget, orientations);
+ }
+ if (DebugWidgetItem)
+ qDebug() << "QDesignerWidgetItem: Noncontainer: " << layout << widget;
+
+ return 0;
+}
+
+static QString sizePolicyToString(const QSizePolicy &p)
+{
+ QString rc; {
+ QTextStream str(&rc);
+ str << "Control=" << p.controlType() << " expdirs=" << p.expandingDirections()
+ << " hasHeightForWidth=" << p.hasHeightForWidth()
+ << " H: Policy=" << p.horizontalPolicy()
+ << " stretch=" << p.horizontalStretch()
+ << " V: Policy=" << p.verticalPolicy()
+ << " stretch=" << p.verticalStretch();
+ }
+ return rc;
+}
+
+// Find the layout the item is contained in, recursing over
+// child layouts
+static const QLayout *findLayoutOfItem(const QLayout *haystack, const QLayoutItem *needle)
+{
+ const int count = haystack->count();
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = haystack->itemAt(i);
+ if (item == needle)
+ return haystack;
+ if (QLayout *childLayout = item->layout())
+ if (const QLayout *containing = findLayoutOfItem(childLayout, needle))
+ return containing;
+ }
+ return 0;
+}
+
+
+namespace qdesigner_internal {
+
+// ------------------ QDesignerWidgetItem
+QDesignerWidgetItem::QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o) :
+ QWidgetItemV2(w),
+ m_orientations(o),
+ m_nonLaidOutMinSize(w->minimumSizeHint()),
+ m_nonLaidOutSizeHint(w->sizeHint()),
+ m_cachedContainingLayout(containingLayout)
+{
+ // Initialize the minimum size to prevent nonlaid-out frames/widgets
+ // from being slammed to zero
+ const QSize minimumSize = w->minimumSize();
+ if (!minimumSize.isEmpty())
+ m_nonLaidOutMinSize = minimumSize;
+ expand(&m_nonLaidOutMinSize);
+ expand(&m_nonLaidOutSizeHint);
+ w->installEventFilter(this);
+ connect(containingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
+ if (DebugWidgetItem )
+ qDebug() << "QDesignerWidgetItem" << w << sizePolicyToString(w->sizePolicy()) << m_nonLaidOutMinSize << m_nonLaidOutSizeHint;
+}
+
+void QDesignerWidgetItem::expand(QSize *s) const
+{
+ // Expand the size if its too small
+ if (m_orientations & Qt::Horizontal && s->width() <= 0)
+ s->setWidth(MinimumLength);
+ if (m_orientations & Qt::Vertical && s->height() <= 0)
+ s->setHeight(MinimumLength);
+}
+
+QSize QDesignerWidgetItem::minimumSize() const
+{
+ // Just track the size in case we are laid-out or stretched.
+ const QSize baseMinSize = QWidgetItemV2::minimumSize();
+ QWidget * w = constWidget();
+ if (w->layout() || subjectToStretch(containingLayout(), w)) {
+ m_nonLaidOutMinSize = baseMinSize;
+ return baseMinSize;
+ }
+ // Nonlaid out: Maintain last laid-out size
+ const QSize rc = baseMinSize.expandedTo(m_nonLaidOutMinSize);
+ if (DebugWidgetItem > 1)
+ qDebug() << "minimumSize" << constWidget() << baseMinSize << rc;
+ return rc;
+}
+
+QSize QDesignerWidgetItem::sizeHint() const
+{
+ // Just track the size in case we are laid-out or stretched.
+ const QSize baseSizeHint = QWidgetItemV2::sizeHint();
+ QWidget * w = constWidget();
+ if (w->layout() || subjectToStretch(containingLayout(), w)) {
+ m_nonLaidOutSizeHint = baseSizeHint;
+ return baseSizeHint;
+ }
+ // Nonlaid out: Maintain last laid-out size
+ const QSize rc = baseSizeHint.expandedTo(m_nonLaidOutSizeHint);
+ if (DebugWidgetItem > 1)
+ qDebug() << "sizeHint" << constWidget() << baseSizeHint << rc;
+ return rc;
+}
+
+bool QDesignerWidgetItem::subjectToStretch(const QLayout *layout, QWidget *w)
+{
+ if (!layout)
+ return false;
+ // Are we under some stretch factor?
+ if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
+ const int index = bl->indexOf(w);
+ Q_ASSERT(index != -1);
+ return bl->stretch(index) != 0;
+ }
+ if (const QGridLayout *cgl = qobject_cast<const QGridLayout *>(layout)) {
+ QGridLayout *gl = const_cast<QGridLayout *>(cgl);
+ const int index = cgl->indexOf(w);
+ Q_ASSERT(index != -1);
+ int row, column, rowSpan, columnSpan;
+ gl->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
+ const int rend = row + rowSpan;
+ const int cend = column + columnSpan;
+ for (int r = row; r < rend; r++)
+ if (cgl->rowStretch(r) != 0)
+ return true;
+ for (int c = column; c < cend; c++)
+ if (cgl->columnStretch(c) != 0)
+ return true;
+ }
+ return false;
+}
+
+/* Return the orientations mask for a layout, specifying
+ * in which directions squeezing should be prevented. */
+static Qt::Orientations layoutOrientation(const QLayout *layout)
+{
+ if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
+ const QBoxLayout::Direction direction = bl->direction();
+ return direction == QBoxLayout::LeftToRight || direction == QBoxLayout::RightToLeft ? Qt::Horizontal : Qt::Vertical;
+ }
+ if (qobject_cast<const QFormLayout*>(layout))
+ return Qt::Vertical;
+ return Qt::Horizontal|Qt::Vertical;
+}
+
+// Check for a non-container extension container
+bool QDesignerWidgetItem::isContainer(const QDesignerFormEditorInterface *core, QWidget *w)
+{
+ if (!WidgetFactory::isFormEditorObject(w))
+ return false;
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ const int widx = wdb->indexOfObject(w);
+ if (widx == -1 || !wdb->item(widx)->isContainer())
+ return false;
+ if (qt_extension<QDesignerContainerExtension*>(core->extensionManager(), w))
+ return false;
+ return true;
+}
+
+bool QDesignerWidgetItem::check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations)
+{
+ // Check for form-editor non-containerextension-containers (QFrame, etc)
+ // within laid-out form editor widgets. No check for managed() here as we
+ // want container pages and widgets in the process of being morphed as
+ // well. Avoid nested layouts (as the effective stretch cannot be easily
+ // computed and may mess things up). Won't work for Q3 Group boxes.
+ if (ptrToOrientations)
+ *ptrToOrientations = 0;
+
+ const QObject *layoutParent = layout->parent();
+ if (!layoutParent || !layoutParent->isWidgetType() || !WidgetFactory::isFormEditorObject(layoutParent))
+ return false;
+
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w);
+ if (!fw || !isContainer(fw->core(), w))
+ return false;
+
+ // If it is a box, restrict to its orientation
+ if (ptrToOrientations)
+ *ptrToOrientations = layoutOrientation(layout);
+
+ return true;
+}
+
+QSize QDesignerWidgetItem::nonLaidOutMinSize() const
+{
+ return m_nonLaidOutMinSize;
+}
+
+void QDesignerWidgetItem::setNonLaidOutMinSize(const QSize &s)
+{
+ if (DebugWidgetItem > 1)
+ qDebug() << "setNonLaidOutMinSize" << constWidget() << s;
+ m_nonLaidOutMinSize = s;
+}
+
+QSize QDesignerWidgetItem::nonLaidOutSizeHint() const
+{
+ return m_nonLaidOutSizeHint;
+}
+
+void QDesignerWidgetItem::setNonLaidOutSizeHint(const QSize &s)
+{
+ if (DebugWidgetItem > 1)
+ qDebug() << "setNonLaidOutSizeHint" << constWidget() << s;
+ m_nonLaidOutSizeHint = s;
+}
+
+void QDesignerWidgetItem::install()
+{
+ QLayoutPrivate::widgetItemFactoryMethod = createDesignerWidgetItem;
+}
+
+void QDesignerWidgetItem::deinstall()
+{
+ QLayoutPrivate::widgetItemFactoryMethod = 0;
+}
+
+const QLayout *QDesignerWidgetItem::containingLayout() const
+{
+ if (!m_cachedContainingLayout) {
+ if (QWidget *parentWidget = constWidget()->parentWidget())
+ if (QLayout *parentLayout = parentWidget->layout()) {
+ m_cachedContainingLayout = findLayoutOfItem(parentLayout, this);
+ if (m_cachedContainingLayout)
+ connect(m_cachedContainingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
+ }
+ if (DebugWidgetItem)
+ qDebug() << Q_FUNC_INFO << " found " << m_cachedContainingLayout << " after reparenting " << constWidget();
+ }
+ return m_cachedContainingLayout;
+}
+
+void QDesignerWidgetItem::layoutChanged()
+{
+ if (DebugWidgetItem)
+ qDebug() << Q_FUNC_INFO;
+ m_cachedContainingLayout = 0;
+}
+
+bool QDesignerWidgetItem::eventFilter(QObject * /* watched */, QEvent *event)
+{
+ if (event->type() == QEvent::ParentChange)
+ layoutChanged();
+ return false;
+}
+
+// ------------------ QDesignerWidgetItemInstaller
+
+int QDesignerWidgetItemInstaller::m_instanceCount = 0;
+
+QDesignerWidgetItemInstaller::QDesignerWidgetItemInstaller()
+{
+ if (m_instanceCount++ == 0) {
+ if (DebugWidgetItem)
+ qDebug() << "QDesignerWidgetItemInstaller: installing";
+ QDesignerWidgetItem::install();
+ }
+}
+
+QDesignerWidgetItemInstaller::~QDesignerWidgetItemInstaller()
+{
+ if (--m_instanceCount == 0) {
+ if (DebugWidgetItem)
+ qDebug() << "QDesignerWidgetItemInstaller: deinstalling";
+ QDesignerWidgetItem::deinstall();
+ }
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qdesigner_widgetitem_p.h b/tools/designer/src/lib/shared/qdesigner_widgetitem_p.h
new file mode 100644
index 0000000..1d8ff3e
--- /dev/null
+++ b/tools/designer/src/lib/shared/qdesigner_widgetitem_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 DESIGNERWIDGETITEM_H
+#define DESIGNERWIDGETITEM_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QLayoutItem>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+// QDesignerWidgetItem: A Layout Item that is used for non-containerextension-
+// containers (QFrame, etc) on Designer forms. It prevents its widget
+// from being slammed to size 0 if the widget has no layout:
+// Pre 4.5, this item ensured only that QWidgets and QFrames were not squeezed
+// to size 0 since they have an invalid size hint when non-laid out.
+// Since 4.5, the item is used for every non-containerextension-container.
+// In case the container has itself a layout, it merely tracks the minimum
+// size. If the container has no layout and is not subject to some stretch
+// factor, it will return the last valid size. The effect is that after
+// breaking a layout on a container within a layout, it just maintains its
+// last size and is not slammed to 0,0. In addition, it can be resized.
+// The class keeps track of the containing layout by tracking widget reparent
+// and destroyed slots as Designer will for example re-create grid layouts to
+// shrink them.
+
+class QDESIGNER_SHARED_EXPORT QDesignerWidgetItem : public QObject, public QWidgetItemV2 {
+ Q_DISABLE_COPY(QDesignerWidgetItem)
+ Q_OBJECT
+public:
+ explicit QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o = Qt::Horizontal|Qt::Vertical);
+
+ const QLayout *containingLayout() const;
+
+ inline QWidget *constWidget() const { return const_cast<QDesignerWidgetItem*>(this)->widget(); }
+
+ virtual QSize minimumSize() const;
+ virtual QSize sizeHint() const;
+
+ // Resize: Takes effect if the contained widget does not have a layout
+ QSize nonLaidOutMinSize() const;
+ void setNonLaidOutMinSize(const QSize &s);
+
+ QSize nonLaidOutSizeHint() const;
+ void setNonLaidOutSizeHint(const QSize &s);
+
+ // Check whether a QDesignerWidgetItem should be installed
+ static bool check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations = 0);
+
+ // Register itself using QLayoutPrivate's widget item factory method hook
+ static void install();
+ static void deinstall();
+
+ // Check for a non-container extension container
+ static bool isContainer(const QDesignerFormEditorInterface *core, QWidget *w);
+
+ static bool subjectToStretch(const QLayout *layout, QWidget *w);
+
+ virtual bool eventFilter(QObject * watched, QEvent * event);
+
+private slots:
+ void layoutChanged();
+
+private:
+ void expand(QSize *s) const;
+ bool subjectToStretch() const;
+
+ const Qt::Orientations m_orientations;
+ mutable QSize m_nonLaidOutMinSize;
+ mutable QSize m_nonLaidOutSizeHint;
+ mutable const QLayout *m_cachedContainingLayout;
+};
+
+// Helper class that ensures QDesignerWidgetItem is installed while an
+// instance is in scope.
+
+class QDESIGNER_SHARED_EXPORT QDesignerWidgetItemInstaller {
+ Q_DISABLE_COPY(QDesignerWidgetItemInstaller)
+
+public:
+ QDesignerWidgetItemInstaller();
+ ~QDesignerWidgetItemInstaller();
+
+private:
+ static int m_instanceCount;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/qlayout_widget.cpp b/tools/designer/src/lib/shared/qlayout_widget.cpp
new file mode 100644
index 0000000..c0986ce
--- /dev/null
+++ b/tools/designer/src/lib/shared/qlayout_widget.cpp
@@ -0,0 +1,2103 @@
+/****************************************************************************
+**
+** 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$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlayout_widget_p.h"
+#include "qdesigner_utils_p.h"
+#include "layout_p.h"
+#include "layoutinfo_p.h"
+#include "invisible_widget_p.h"
+#include "qdesigner_widgetitem_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+
+#include <QtGui/QPainter>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QGridLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/qevent.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QMap>
+#include <QtCore/QStack>
+#include <QtCore/QPair>
+#include <QtCore/QSet>
+
+enum { ShiftValue = 1 };
+enum { debugLayout = 0 };
+enum { FormLayoutColumns = 2 };
+enum { indicatorSize = 2 };
+// Grid/form Helpers: get info (overloads to make templates work)
+
+namespace { // Do not use static, will break HP-UX due to templates
+
+QT_USE_NAMESPACE
+
+// overloads to make templates over QGridLayout/QFormLayout work
+inline int gridRowCount(const QGridLayout *gridLayout)
+{
+ return gridLayout->rowCount();
+}
+
+inline int gridColumnCount(const QGridLayout *gridLayout)
+{
+ return gridLayout->columnCount();
+}
+
+// QGridLayout/QFormLayout Helpers: get item position (overloads to make templates work)
+inline void getGridItemPosition(QGridLayout *gridLayout, int index,
+ int *row, int *column, int *rowspan, int *colspan)
+{
+ gridLayout->getItemPosition(index, row, column, rowspan, colspan);
+}
+
+QRect gridItemInfo(QGridLayout *grid, int index)
+{
+ int row, column, rowSpan, columnSpan;
+ // getItemPosition is not const, grmbl..
+ grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan);
+ return QRect(column, row, columnSpan, rowSpan);
+}
+
+inline int gridRowCount(const QFormLayout *formLayout) { return formLayout->rowCount(); }
+inline int gridColumnCount(const QFormLayout *) { return FormLayoutColumns; }
+
+inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan)
+{
+ qdesigner_internal::getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan);
+}
+
+QRect gridItemInfo(const QFormLayout *form, int index)
+{
+ int row;
+ int column;
+ int colspan;
+ qdesigner_internal::getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan);
+ return QRect(column, row, colspan, 1);
+}
+} // namespace anonymous
+
+QT_BEGIN_NAMESPACE
+
+static const char *objectNameC = "objectName";
+static const char *sizeConstraintC = "sizeConstraint";
+
+/* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell.
+ * Should not be used on a grid as it causes resizing inconsistencies */
+namespace qdesigner_internal {
+ class PaddingSpacerItem : public QSpacerItem {
+ public:
+ PaddingSpacerItem() : QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) {}
+ virtual Qt::Orientations expandingDirections () const { return Qt::Vertical | Qt::Horizontal; }
+ };
+}
+
+static inline QSpacerItem *createGridSpacer()
+{
+ return new QSpacerItem(0, 0);
+}
+
+static inline QSpacerItem *createFormSpacer()
+{
+ return new qdesigner_internal::PaddingSpacerItem;
+}
+
+// QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout
+template <class GridLikeLayout>
+static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
+{
+ const int count = gl.count();
+ str << "Grid: " << gl.objectName() << gridRowCount(&gl) << " rows x " << gridColumnCount(&gl)
+ << " cols " << count << " items\n";
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = gl.itemAt(i);
+ str << "Item " << i << item << item->widget() << gridItemInfo(const_cast<GridLikeLayout *>(&gl), i) << " empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) << "\n";
+ }
+ return str;
+}
+
+static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); }
+static inline QDebug operator<<(QDebug str, const QFormLayout &fl) { return debugGridLikeLayout(str, fl); }
+
+static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
+{
+ // Spanning can never be empty
+ if (fl->itemAt(row, QFormLayout::SpanningRole))
+ return false;
+ return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole));
+}
+
+static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
+{
+ if (restrictionArea.x() >= FormLayoutColumns)
+ return false;
+ // Try to find empty rows
+ const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height());
+ for (int r = restrictionArea.y(); r < bottomCheckRow; r++)
+ if (isEmptyFormLayoutRow(formLayout, r))
+ return true;
+ return false;
+}
+
+// recreate a managed layout (which does not automagically remove
+// empty rows/columns like grid or form layout) in case it needs to shrink
+
+static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
+{
+ const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt);
+ qdesigner_internal::LayoutProperties properties;
+ const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties);
+ qdesigner_internal::LayoutInfo::deleteLayout(core, w);
+ QLayout *rc = core->widgetFactory()->createLayout(w, 0, t);
+ properties.toPropertySheet(core, rc, mask, true);
+ return rc;
+}
+
+// QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index
+template <class GridLikeLayout>
+int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
+{
+ Q_ASSERT(gridLayout);
+ const int count = gridLayout->count();
+ for (int index = 0; index < count; index++) {
+ int row, column, rowspan, colspan;
+ getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan);
+ if (at_row >= row && at_row < (row + rowspan)
+ && at_column >= column && at_column < (column + colspan)) {
+ return index;
+ }
+ }
+ return -1;
+}
+// QGridLayout/QFormLayout Helpers: remove dummy spacers on form/grid
+template <class GridLikeLayout>
+static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
+{
+ // check if there are any items in the way. Should be only spacers
+ // Unique out items that span rows/columns.
+ QVector<int> indexesToBeRemoved;
+ indexesToBeRemoved.reserve(grid->count());
+ const int rightColumn = area.x() + area.width();
+ const int bottomRow = area.y() + area.height();
+ for (int c = area.x(); c < rightColumn; c++)
+ for (int r = area.y(); r < bottomRow; r++) {
+ const int index = findGridItemAt(grid, r ,c);
+ if (index != -1)
+ if (QLayoutItem *item = grid->itemAt(index)) {
+ if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) {
+ if (indexesToBeRemoved.indexOf(index) == -1)
+ indexesToBeRemoved.push_back(index);
+ } else {
+ return false;
+ }
+ }
+ }
+ // remove, starting from last
+ if (!indexesToBeRemoved.empty()) {
+ qStableSort(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
+ for (int i = indexesToBeRemoved.size() - 1; i >= 0; i--)
+ delete grid->takeAt(indexesToBeRemoved[i]);
+ }
+ return true;
+}
+
+namespace qdesigner_internal {
+// --------- LayoutProperties
+
+LayoutProperties::LayoutProperties()
+{
+ clear();
+}
+
+void LayoutProperties::clear()
+{
+ qFill(m_margins, m_margins + MarginCount, 0);
+ qFill(m_marginsChanged, m_marginsChanged + MarginCount, false);
+ qFill(m_spacings, m_spacings + SpacingsCount, 0);
+ qFill(m_spacingsChanged, m_spacingsChanged + SpacingsCount, false);
+
+ m_objectName = QVariant();
+ m_objectNameChanged = false;
+ m_sizeConstraint = QVariant(QLayout::SetDefaultConstraint);
+ m_sizeConstraintChanged = false;
+
+ m_fieldGrowthPolicyChanged = m_rowWrapPolicyChanged = m_labelAlignmentChanged = m_formAlignmentChanged = false;
+ m_fieldGrowthPolicy = m_rowWrapPolicy = m_formAlignment = QVariant();
+
+ m_boxStretchChanged = m_gridRowStretchChanged = m_gridColumnStretchChanged = m_gridRowMinimumHeightChanged = false;
+ m_boxStretch = m_gridRowStretch = m_gridColumnStretch = m_gridRowMinimumHeight = QVariant();
+}
+
+int LayoutProperties::visibleProperties(const QLayout *layout)
+{
+ // Grid like layout have 2 spacings.
+ const bool isFormLayout = qobject_cast<const QFormLayout*>(layout);
+ const bool isGridLike = qobject_cast<const QGridLayout*>(layout) || isFormLayout;
+ int rc = ObjectNameProperty|LeftMarginProperty|TopMarginProperty|RightMarginProperty|BottomMarginProperty|
+ SizeConstraintProperty;
+
+ rc |= isGridLike ? (HorizSpacingProperty|VertSpacingProperty) : SpacingProperty;
+ if (isFormLayout) {
+ rc |= FieldGrowthPolicyProperty|RowWrapPolicyProperty|LabelAlignmentProperty|FormAlignmentProperty;
+ } else {
+ if (isGridLike) {
+ rc |= GridRowStretchProperty|GridColumnStretchProperty|GridRowMinimumHeightProperty|GridColumnMinimumWidthProperty;
+ } else {
+ rc |= BoxStretchProperty;
+ }
+ }
+ return rc;
+}
+
+static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"};
+static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" };
+static const char *fieldGrowthPolicyPropertyC = "fieldGrowthPolicy";
+static const char *rowWrapPolicyPropertyC = "rowWrapPolicy";
+static const char *labelAlignmentPropertyC = "labelAlignment";
+static const char *formAlignmentPropertyC = "formAlignment";
+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";
+
+static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
+{
+ const int sheetIndex = sheet->indexOf(name);
+ if (sheetIndex == -1)
+ return false;
+ *value = sheet->property(sheetIndex).toInt();
+ *changed = sheet->isChanged(sheetIndex);
+ return true;
+}
+
+static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name,
+ QVariant *value, bool *changed, int *returnMask)
+{
+ if (mask & flag) {
+ const int sIndex = sheet->indexOf(name);
+ if (sIndex != -1) {
+ *value = sheet->property(sIndex);
+ *changed = sheet->isChanged(sIndex);
+ *returnMask |= flag;
+ }
+ }
+}
+
+int LayoutProperties::fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask)
+{
+ int rc = 0;
+ const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l);
+ Q_ASSERT(sheet);
+ // name
+ if (mask & ObjectNameProperty) {
+ const int nameIndex = sheet->indexOf(QLatin1String(objectNameC));
+ Q_ASSERT(nameIndex != -1);
+ m_objectName = sheet->property(nameIndex);
+ m_objectNameChanged = sheet->isChanged(nameIndex);
+ rc |= ObjectNameProperty;
+ }
+ // -- Margins
+ const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty};
+ for (int i = 0; i < MarginCount; i++)
+ if (mask & marginFlags[i])
+ if (intValueFromSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins + i, m_marginsChanged + i))
+ rc |= marginFlags[i];
+
+ const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty};
+ for (int i = 0; i < SpacingsCount; i++)
+ if (mask & spacingFlags[i])
+ if (intValueFromSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings + i, m_spacingsChanged + i))
+ rc |= spacingFlags[i];
+ // sizeConstraint, flags
+ variantPropertyFromSheet(mask, SizeConstraintProperty, sheet, QLatin1String(sizeConstraintC), &m_sizeConstraint, &m_sizeConstraintChanged, &rc);
+ variantPropertyFromSheet(mask, FieldGrowthPolicyProperty, sheet, QLatin1String(fieldGrowthPolicyPropertyC), &m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc);
+ variantPropertyFromSheet(mask, RowWrapPolicyProperty, sheet, QLatin1String(rowWrapPolicyPropertyC), &m_rowWrapPolicy, &m_rowWrapPolicyChanged, &rc);
+ variantPropertyFromSheet(mask, LabelAlignmentProperty, sheet, QLatin1String(labelAlignmentPropertyC), &m_labelAlignment, &m_labelAlignmentChanged, &rc);
+ variantPropertyFromSheet(mask, FormAlignmentProperty, sheet, QLatin1String(formAlignmentPropertyC), &m_formAlignment, &m_formAlignmentChanged, &rc);
+ variantPropertyFromSheet(mask, BoxStretchProperty, sheet, QLatin1String(boxStretchPropertyC), &m_boxStretch, & m_boxStretchChanged, &rc);
+ variantPropertyFromSheet(mask, GridRowStretchProperty, sheet, QLatin1String(gridRowStretchPropertyC), &m_gridRowStretch, &m_gridRowStretchChanged, &rc);
+ variantPropertyFromSheet(mask, GridColumnStretchProperty, sheet, QLatin1String(gridColumnStretchPropertyC), &m_gridColumnStretch, &m_gridColumnStretchChanged, &rc);
+ variantPropertyFromSheet(mask, GridRowMinimumHeightProperty, sheet, QLatin1String(gridRowMinimumHeightPropertyC), &m_gridRowMinimumHeight, &m_gridRowMinimumHeightChanged, &rc);
+ variantPropertyFromSheet(mask, GridColumnMinimumWidthProperty, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), &m_gridColumnMinimumWidth, &m_gridColumnMinimumWidthChanged, &rc);
+ return rc;
+}
+
+static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
+
+{
+
+ const int sheetIndex = sheet->indexOf(name);
+ if (sheetIndex == -1) {
+ qWarning() << " LayoutProperties: Attempt to set property " << name << " that does not exist for the layout.";
+ return false;
+ }
+ sheet->setProperty(sheetIndex, QVariant(value));
+ if (applyChanged)
+ sheet->setChanged(sheetIndex, changed);
+ return true;
+}
+
+static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name,
+ const QVariant &value, bool changed, int *returnMask)
+{
+ if (mask & flag) {
+ const int sIndex = sheet->indexOf(name);
+ if (sIndex != -1) {
+ sheet->setProperty(sIndex, value);
+ if (applyChanged)
+ sheet->setChanged(sIndex, changed);
+ *returnMask |= flag;
+ }
+ }
+}
+
+int LayoutProperties::toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask, bool applyChanged) const
+{
+ int rc = 0;
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l);
+ Q_ASSERT(sheet);
+ // name
+ if (mask & ObjectNameProperty) {
+ const int nameIndex = sheet->indexOf(QLatin1String(objectNameC));
+ Q_ASSERT(nameIndex != -1);
+ sheet->setProperty(nameIndex, m_objectName);
+ if (applyChanged)
+ sheet->setChanged(nameIndex, m_objectNameChanged);
+ rc |= ObjectNameProperty;
+ }
+ // margins
+ const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty};
+ for (int i = 0; i < MarginCount; i++)
+ if (mask & marginFlags[i])
+ if (intValueToSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins[i], m_marginsChanged[i], applyChanged))
+ rc |= marginFlags[i];
+
+ const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty};
+ for (int i = 0; i < SpacingsCount; i++)
+ if (mask & spacingFlags[i])
+ if (intValueToSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings[i], m_spacingsChanged[i], applyChanged))
+ rc |= spacingFlags[i];
+ // sizeConstraint
+ variantPropertyToSheet(mask, SizeConstraintProperty, applyChanged, sheet, QLatin1String(sizeConstraintC), m_sizeConstraint, m_sizeConstraintChanged, &rc);
+ variantPropertyToSheet(mask, FieldGrowthPolicyProperty, applyChanged, sheet, QLatin1String(fieldGrowthPolicyPropertyC), m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc);
+ variantPropertyToSheet(mask, RowWrapPolicyProperty, applyChanged, sheet, QLatin1String(rowWrapPolicyPropertyC), m_rowWrapPolicy, m_rowWrapPolicyChanged, &rc);
+ variantPropertyToSheet(mask, LabelAlignmentProperty, applyChanged, sheet, QLatin1String(labelAlignmentPropertyC), m_labelAlignment, m_labelAlignmentChanged, &rc);
+ variantPropertyToSheet(mask, FormAlignmentProperty, applyChanged, sheet, QLatin1String(formAlignmentPropertyC), m_formAlignment, m_formAlignmentChanged, &rc);
+ variantPropertyToSheet(mask, BoxStretchProperty, applyChanged, sheet, QLatin1String(boxStretchPropertyC), m_boxStretch, m_boxStretchChanged, &rc);
+ variantPropertyToSheet(mask, GridRowStretchProperty, applyChanged, sheet, QLatin1String(gridRowStretchPropertyC), m_gridRowStretch, m_gridRowStretchChanged, &rc);
+ variantPropertyToSheet(mask, GridColumnStretchProperty, applyChanged, sheet, QLatin1String(gridColumnStretchPropertyC), m_gridColumnStretch, m_gridColumnStretchChanged, &rc);
+ variantPropertyToSheet(mask, GridRowMinimumHeightProperty, applyChanged, sheet, QLatin1String(gridRowMinimumHeightPropertyC), m_gridRowMinimumHeight, m_gridRowMinimumHeightChanged, &rc);
+ variantPropertyToSheet(mask, GridColumnMinimumWidthProperty, applyChanged, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), m_gridColumnMinimumWidth, m_gridColumnMinimumWidthChanged, &rc);
+ return rc;
+}
+
+// ---------------- LayoutHelper
+LayoutHelper::LayoutHelper()
+{
+}
+
+LayoutHelper::~LayoutHelper()
+{
+}
+
+int LayoutHelper::indexOf(const QLayout *lt, const QWidget *widget)
+{
+ if (!lt)
+ return -1;
+
+ const int itemCount = lt->count();
+ for (int i = 0; i < itemCount; i++)
+ if (lt->itemAt(i)->widget() == widget)
+ return i;
+ return -1;
+}
+
+QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const
+{
+ const int index = indexOf(lt, widget);
+ if (index == -1) {
+ qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt;
+ return QRect(0, 0, 1, 1);
+ }
+ return itemInfo(lt, index);
+}
+
+ // ---------------- BoxLayoutHelper
+ class BoxLayoutHelper : public LayoutHelper {
+ public:
+ BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {}
+
+ virtual QRect itemInfo(QLayout *lt, int index) const;
+ virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
+ virtual void removeWidget(QLayout *lt, QWidget *widget);
+ virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
+
+ virtual void pushState(const QDesignerFormEditorInterface *, const QWidget *);
+ virtual void popState(const QDesignerFormEditorInterface *, QWidget *);
+
+ virtual bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const { return false; }
+ virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) {}
+
+ // Helper for restoring layout states
+ typedef QVector <QLayoutItem *> LayoutItemVector;
+ static LayoutItemVector disassembleLayout(QLayout *lt);
+ static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w);
+
+ private:
+ typedef QVector<QWidget *> BoxLayoutState;
+
+ static BoxLayoutState state(const QBoxLayout*lt);
+
+ QStack<BoxLayoutState> m_states;
+ const Qt::Orientation m_orientation;
+ };
+
+ QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const
+ {
+ return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1);
+ }
+
+ void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
+ {
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
+ Q_ASSERT(boxLayout);
+ boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w);
+ }
+
+ void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
+ {
+ QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
+ Q_ASSERT(boxLayout);
+ boxLayout->removeWidget(widget);
+ }
+
+ void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
+ {
+ bool ok = false;
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) {
+ const int index = boxLayout->indexOf(before);
+ if (index != -1) {
+ const bool visible = before->isVisible();
+ delete boxLayout->takeAt(index);
+ if (visible)
+ before->hide();
+ before->setParent(0);
+ boxLayout->insertWidget(index, after);
+ ok = true;
+ }
+ }
+ if (!ok)
+ qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
+ }
+
+ BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt)
+ {
+ BoxLayoutState rc;
+ if (const int count = lt->count()) {
+ rc.reserve(count);
+ for (int i = 0; i < count; i++)
+ if (QWidget *w = lt->itemAt(i)->widget())
+ rc.push_back(w);
+ }
+ return rc;
+ }
+
+ void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w)
+ {
+ const QBoxLayout *boxLayout = qobject_cast<const QBoxLayout *>(LayoutInfo::managedLayout(core, w));
+ Q_ASSERT(boxLayout);
+ m_states.push(state(boxLayout));
+ }
+
+ QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
+ {
+ const LayoutItemVector::const_iterator cend = lv.constEnd();
+ for (LayoutItemVector::const_iterator it = lv.constBegin(); it != cend; ++it)
+ if ( (*it)->widget() == w)
+ return *it;
+
+ return 0;
+ }
+
+ BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt)
+ {
+ // Take items
+ const int count = lt->count();
+ if (count == 0)
+ return LayoutItemVector();
+ LayoutItemVector rc;
+ rc.reserve(count);
+ for (int i = count - 1; i >= 0; i--)
+ rc.push_back(lt->takeAt(i));
+ return rc;
+ }
+
+ void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w)
+ {
+ QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w));
+ Q_ASSERT(boxLayout);
+ const BoxLayoutState savedState = m_states.pop();
+ const BoxLayoutState currentState = state(boxLayout);
+ // Check for equality/empty. Note that this will currently
+ // always trigger as box layouts do not have a state apart from
+ // the order and there is no layout order editor yet.
+ if (savedState == state(boxLayout))
+ return;
+
+ const int count = savedState.size();
+ Q_ASSERT(count == currentState.size());
+ // Take items and reassemble in saved order
+ const LayoutItemVector items = disassembleLayout(boxLayout);
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = findItemOfWidget(items, savedState[i]);
+ Q_ASSERT(item);
+ boxLayout->addItem(item);
+ }
+ }
+
+ // Grid Layout state. Datatypically store the state of a GridLayout as a map of
+ // widgets to QRect(columns, rows) and size. Used to store the state for undo operations
+ // that do not change the widgets within the layout; also provides some manipulation
+ // functions and ability to apply the state to a layout provided its widgets haven't changed.
+ struct GridLayoutState {
+ GridLayoutState();
+
+ void fromLayout(QGridLayout *l);
+ void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const;
+
+ void insertRow(int row);
+ void insertColumn(int column);
+
+ bool simplify(const QRect &r, bool testOnly);
+ void removeFreeRow(int row);
+ void removeFreeColumn(int column);
+
+
+ // State of a cell in one dimension
+ enum DimensionCellState {
+ Free,
+ Spanned, // Item spans it
+ Occupied // Item bordering on it
+ };
+ // Horiontal, Vertical pair of state
+ typedef QPair<DimensionCellState, DimensionCellState> CellState;
+ typedef QVector<CellState> CellStates;
+
+ // Figure out states of a cell and return as a flat vector of
+ // [column1, column2,...] (address as row * columnCount + col)
+ static CellStates cellStates(const QList<QRect> &rects, int numRows, int numColumns);
+
+ typedef QMap<QWidget *, QRect> WidgetItemMap;
+ WidgetItemMap widgetItemMap;
+ int rowCount;
+ int colCount;
+ };
+
+ static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) {
+ return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free;
+ }
+
+ static inline QDebug operator<<(QDebug str, const GridLayoutState &gs)
+ {
+ str << "GridLayoutState: " << gs.rowCount << " rows x " << gs.colCount
+ << " cols " << gs.widgetItemMap.size() << " items\n";
+
+ const GridLayoutState::WidgetItemMap::const_iterator wcend = gs.widgetItemMap.constEnd();
+ for (GridLayoutState::WidgetItemMap::const_iterator it = gs.widgetItemMap.constBegin(); it != wcend; ++it)
+ str << "Item " << it.key() << it.value() << '\n';
+ return str;
+ }
+
+ GridLayoutState::GridLayoutState() :
+ rowCount(0),
+ colCount(0)
+ {
+ }
+
+ GridLayoutState::CellStates GridLayoutState::cellStates(const QList<QRect> &rects, int numRows, int numColumns)
+ {
+ CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free));
+ const QList<QRect>::const_iterator rcend = rects.constEnd();
+ for (QList<QRect>::const_iterator it = rects.constBegin(); it != rcend; ++it) {
+ const int leftColumn = it->x();
+ const int topRow = it->y();
+ const int rightColumn = leftColumn + it->width() - 1;
+ const int bottomRow = topRow + it->height() - 1;
+ for (int r = topRow; r <= bottomRow; r++)
+ for (int c = leftColumn; c <= rightColumn; c++) {
+ const int flatIndex = r * numColumns + c;
+ // Bordering horizontally?
+ DimensionCellState &horizState = rc[flatIndex].first;
+ if (c == leftColumn || c == rightColumn) {
+ horizState = Occupied;
+ } else {
+ if (horizState < Spanned)
+ horizState = Spanned;
+ }
+ // Bordering vertically?
+ DimensionCellState &vertState = rc[flatIndex].second;
+ if (r == topRow || r == bottomRow) {
+ vertState = Occupied;
+ } else {
+ if (vertState < Spanned)
+ vertState = Spanned;
+ }
+ }
+ }
+ if (debugLayout) {
+ qDebug() << "GridLayoutState::cellStates: " << numRows << " x " << numColumns;
+ for (int r = 0; r < numRows; r++)
+ for (int c = 0; c < numColumns; c++)
+ qDebug() << " Row: " << r << " column: " << c << rc[r * numColumns + c];
+ }
+ return rc;
+ }
+
+ void GridLayoutState::fromLayout(QGridLayout *l)
+ {
+ rowCount = l->rowCount();
+ colCount = l->columnCount();
+ const int count = l->count();
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = l->itemAt(i);
+ if (!LayoutInfo::isEmptyItem(item))
+ widgetItemMap.insert(item->widget(), gridItemInfo(l, i));
+ }
+ }
+
+ void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
+ {
+ typedef QMap<QLayoutItem *, QRect> LayoutItemRectMap;
+ QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w));
+ Q_ASSERT(grid);
+ if (debugLayout)
+ qDebug() << ">GridLayoutState::applyToLayout" << *this << *grid;
+ const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount;
+ // Build a map of existing items to rectangles via widget map, delete spacers
+ LayoutItemRectMap itemMap;
+ while (grid->count()) {
+ QLayoutItem *item = grid->takeAt(0);
+ if (!LayoutInfo::isEmptyItem(item)) {
+ QWidget *itemWidget = item->widget();
+ const WidgetItemMap::const_iterator it = widgetItemMap.constFind(itemWidget);
+ if (it == widgetItemMap.constEnd())
+ qFatal("GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.",
+ itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData());
+ itemMap.insert(item, it.value());
+ } else {
+ delete item;
+ }
+ }
+ Q_ASSERT(itemMap.size() == widgetItemMap.size());
+ // recreate if shrink
+ if (shrink)
+ grid = static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid));
+
+ // Add widgets items
+ const LayoutItemRectMap::const_iterator icend = itemMap.constEnd();
+ for (LayoutItemRectMap::const_iterator it = itemMap.constBegin(); it != icend; ++it) {
+ const QRect info = it.value();
+ grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width());
+ }
+ // create spacers
+ const CellStates cs = cellStates(itemMap.values(), rowCount, colCount);
+ for (int r = 0; r < rowCount; r++)
+ for (int c = 0; c < colCount; c++)
+ if (needsSpacerItem(cs[r * colCount + c]))
+ grid->addItem(createGridSpacer(), r, c);
+ grid->activate();
+ if (debugLayout)
+ qDebug() << "<GridLayoutState::applyToLayout" << *grid;
+ }
+
+ void GridLayoutState::insertRow(int row)
+ {
+ rowCount++;
+ const WidgetItemMap::iterator iend = widgetItemMap.end();
+ for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
+ const int topRow = it.value().y();
+ if (topRow >= row) {
+ it.value().translate(0, 1);
+ } else { //Over it: Does it span it -> widen?
+ const int rowSpan = it.value().height();
+ if (rowSpan > 1 && topRow + rowSpan > row)
+ it.value().setHeight(rowSpan + 1);
+ }
+ }
+ }
+
+ void GridLayoutState::insertColumn(int column)
+ {
+ colCount++;
+ const WidgetItemMap::iterator iend = widgetItemMap.end();
+ for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
+ const int leftColumn = it.value().x();
+ if (leftColumn >= column) {
+ it.value().translate(1, 0);
+ } else { // Left of it: Does it span it -> widen?
+ const int colSpan = it.value().width();
+ if (colSpan > 1 && leftColumn + colSpan > column)
+ it.value().setWidth(colSpan + 1);
+ }
+ }
+ }
+
+ // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink
+ // spanning items).
+ // 'AB.C.' 'ABC'
+ // 'DDDD.' ==> 'DDD'
+ // 'EF.G.' 'EFG'
+ bool GridLayoutState::simplify(const QRect &r, bool testOnly)
+ {
+ // figure out free rows/columns.
+ QVector<bool> occupiedRows(rowCount, false);
+ QVector<bool> occupiedColumns(colCount, false);
+ // Mark everything outside restriction rectangle as occupied
+ const int restrictionLeftColumn = r.x();
+ const int restrictionRightColumn = restrictionLeftColumn + r.width();
+ const int restrictionTopRow = r.y();
+ const int restrictionBottomRow = restrictionTopRow + r.height();
+ if (restrictionLeftColumn > 0 || restrictionRightColumn < colCount ||
+ restrictionTopRow > 0 || restrictionBottomRow < rowCount) {
+ for (int r = 0; r < rowCount; r++)
+ if (r < restrictionTopRow || r >= restrictionBottomRow)
+ occupiedRows[r] = true;
+ for (int c = 0; c < colCount; c++)
+ if (c < restrictionLeftColumn || c >= restrictionRightColumn)
+ occupiedColumns[c] = true;
+ }
+ // figure out free fields and tick off occupied rows and columns
+ const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount);
+ for (int r = 0; r < rowCount; r++)
+ for (int c = 0; c < colCount; c++) {
+ const CellState &state = cs[r * colCount + c];
+ if (state.first == Occupied)
+ occupiedColumns[c] = true;
+ if (state.second == Occupied)
+ occupiedRows[r] = true;
+ }
+ // Any free rows/columns?
+ if (occupiedRows.indexOf(false) == -1 && occupiedColumns.indexOf(false) == -1)
+ return false;
+ if (testOnly)
+ return true;
+ // remove rows
+ for (int r = rowCount - 1; r >= 0; r--)
+ if (!occupiedRows[r])
+ removeFreeRow(r);
+ // remove columns
+ for (int c = colCount - 1; c >= 0; c--)
+ if (!occupiedColumns[c])
+ removeFreeColumn(c);
+ return true;
+ }
+
+ void GridLayoutState::removeFreeRow(int removeRow)
+ {
+ const WidgetItemMap::iterator iend = widgetItemMap.end();
+ for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
+ const int r = it.value().y();
+ Q_ASSERT(r != removeRow); // Free rows only
+ if (r < removeRow) { // Does the item span it? - shrink it
+ const int rowSpan = it.value().height();
+ if (rowSpan > 1) {
+ const int bottomRow = r + rowSpan;
+ if (bottomRow > removeRow)
+ it.value().setHeight(rowSpan - 1);
+ }
+ } else
+ if (r > removeRow) // Item below it? - move.
+ it.value().translate(0, -1);
+ }
+ rowCount--;
+ }
+
+ void GridLayoutState::removeFreeColumn(int removeColumn)
+ {
+ const WidgetItemMap::iterator iend = widgetItemMap.end();
+ for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
+ const int c = it.value().x();
+ Q_ASSERT(c != removeColumn); // Free columns only
+ if (c < removeColumn) { // Does the item span it? - shrink it
+ const int colSpan = it.value().width();
+ if (colSpan > 1) {
+ const int rightColumn = c + colSpan;
+ if (rightColumn > removeColumn)
+ it.value().setWidth(colSpan - 1);
+ }
+ } else
+ if (c > removeColumn) // Item to the right of it? - move.
+ it.value().translate(-1, 0);
+ }
+ colCount--;
+ }
+
+ // ---------------- GridLayoutHelper
+ class GridLayoutHelper : public LayoutHelper {
+ public:
+ GridLayoutHelper() {}
+
+ virtual QRect itemInfo(QLayout *lt, int index) const;
+ virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
+ virtual void removeWidget(QLayout *lt, QWidget *widget);
+ virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
+
+ virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout);
+ virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout);
+
+ virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const;
+ virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea);
+
+ static void insertRow(QGridLayout *grid, int row);
+
+ private:
+ QStack<GridLayoutState> m_states;
+ };
+
+ void GridLayoutHelper::insertRow(QGridLayout *grid, int row)
+ {
+ GridLayoutState state;
+ state.fromLayout(grid);
+ state.insertRow(row);
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid);
+ state.applyToLayout(fw->core(), grid->parentWidget());
+ }
+
+ QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const
+ {
+ QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
+ Q_ASSERT(grid);
+ return gridItemInfo(grid, index);
+ }
+
+ void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
+ {
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
+ Q_ASSERT(gridLayout);
+ // check if there are any items. Should be only spacers, else something is wrong
+ const int row = info.y();
+ int column = info.x();
+ int colSpan = info.width();
+ int rowSpan = info.height();
+ // If not empty: A multiselection was dropped on an empty item, insert row
+ // and spread items along new row
+ if (!removeEmptyCellsOnGrid(gridLayout, info)) {
+ int freeColumn = -1;
+ colSpan = rowSpan = 1;
+ // First look to the right for a free column
+ const int columnCount = gridLayout->columnCount();
+ for (int c = column; c < columnCount; c++) {
+ const int idx = findGridItemAt(gridLayout, row, c);
+ if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) {
+ freeColumn = c;
+ break;
+ }
+ }
+ if (freeColumn != -1) {
+ removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1));
+ column = freeColumn;
+ } else {
+ GridLayoutHelper::insertRow(gridLayout, row);
+ column = 0;
+ }
+ }
+ gridLayout->addWidget(w, row , column, rowSpan, colSpan);
+ }
+
+ void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
+ {
+ QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
+ Q_ASSERT(gridLayout);
+ const int index = gridLayout->indexOf(widget);
+ if (index == -1) {
+ qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
+ return;
+ }
+ // delete old item and pad with by spacer items
+ int row, column, rowspan, colspan;
+ gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan);
+ delete gridLayout->takeAt(index);
+ const int rightColumn = column + colspan;
+ const int bottomRow = row + rowspan;
+ for (int c = column; c < rightColumn; c++)
+ for (int r = row; r < bottomRow; r++)
+ gridLayout->addItem(createGridSpacer(), r, c);
+ }
+
+ void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
+ {
+ bool ok = false;
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) {
+ const int index = gridLayout->indexOf(before);
+ if (index != -1) {
+ int row, column, rowSpan, columnSpan;
+ gridLayout->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
+ const bool visible = before->isVisible();
+ delete gridLayout->takeAt(index);
+ if (visible)
+ before->hide();
+ before->setParent(0);
+ gridLayout->addWidget(after, row, column, rowSpan, columnSpan);
+ ok = true;
+ }
+ }
+ if (!ok)
+ qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
+ }
+
+ void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
+ {
+ QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(gridLayout);
+ GridLayoutState gs;
+ gs.fromLayout(gridLayout);
+ m_states.push(gs);
+ }
+
+ void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
+ {
+ Q_ASSERT(!m_states.empty());
+ const GridLayoutState state = m_states.pop();
+ state.applyToLayout(core, widgetWithManagedLayout);
+ }
+
+ bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
+ {
+ QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(gridLayout);
+ GridLayoutState gs;
+ gs.fromLayout(gridLayout);
+ return gs.simplify(restrictionArea, true);
+ }
+
+ void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
+ {
+ QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(gridLayout);
+ if (debugLayout)
+ qDebug() << ">GridLayoutHelper::simplify" << *gridLayout;
+ GridLayoutState gs;
+ gs.fromLayout(gridLayout);
+ if (gs.simplify(restrictionArea, false))
+ gs.applyToLayout(core, widgetWithManagedLayout);
+ if (debugLayout)
+ qDebug() << "<GridLayoutHelper::simplify" << *gridLayout;
+ }
+
+ // ---------------- FormLayoutHelper
+ class FormLayoutHelper : public LayoutHelper {
+ public:
+ typedef QPair<QWidget *, QWidget *> WidgetPair;
+ typedef QVector<WidgetPair> FormLayoutState;
+
+ FormLayoutHelper() {}
+
+ virtual QRect itemInfo(QLayout *lt, int index) const;
+ virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
+ virtual void removeWidget(QLayout *lt, QWidget *widget);
+ virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
+
+ virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout);
+ virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout);
+
+ virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const;
+ virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &);
+
+ private:
+ static FormLayoutState state(const QFormLayout *lt);
+
+ QStack<FormLayoutState> m_states;
+ };
+
+ QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const
+ {
+ QFormLayout *form = qobject_cast<QFormLayout *>(lt);
+ Q_ASSERT(form);
+ int row, column, colspan;
+ getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan);
+ return QRect(column, row, colspan, 1);
+ }
+
+ void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
+ {
+ if (debugLayout)
+ qDebug() << "FormLayoutHelper::insertWidget:" << w << info;
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
+ Q_ASSERT(formLayout);
+ // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection
+ // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row
+ const bool insert = !removeEmptyCellsOnGrid(formLayout, info);
+ formLayoutAddWidget(formLayout, w, info, insert);
+ QLayoutSupport::createEmptyCells(formLayout);
+ }
+
+ void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
+ {
+ QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
+ Q_ASSERT(formLayout);
+ const int index = formLayout->indexOf(widget);
+ if (index == -1) {
+ qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
+ return;
+ }
+ // delete old item and pad with by spacer items
+ int row, column, colspan;
+ getFormLayoutItemPosition(formLayout, index, &row, &column, 0, &colspan);
+ if (debugLayout)
+ qDebug() << "FormLayoutHelper::removeWidget: #" << index << widget << " at " << row << column << colspan;
+ delete formLayout->takeAt(index);
+ if (colspan > 1 || column == 0)
+ formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer());
+ if (colspan > 1 || column == 1)
+ formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer());
+ }
+
+ void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
+ {
+ bool ok = false;
+ QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
+ if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) {
+ const int index = formLayout->indexOf(before);
+ if (index != -1) {
+ int row;
+ QFormLayout::ItemRole role;
+ formLayout->getItemPosition (index, &row, &role);
+ const bool visible = before->isVisible();
+ delete formLayout->takeAt(index);
+ if (visible)
+ before->hide();
+ before->setParent(0);
+ formLayout->setWidget(row, role, after);
+ ok = true;
+ }
+ }
+ if (!ok)
+ qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
+ }
+
+ FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt)
+ {
+ const int rowCount = lt->rowCount();
+ if (rowCount == 0)
+ return FormLayoutState();
+ FormLayoutState rc(rowCount, WidgetPair(0, 0));
+ const int count = lt->count();
+ int row, column, colspan;
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = lt->itemAt(i);
+ if (!LayoutInfo::isEmptyItem(item)) {
+ QWidget *w = item->widget();
+ Q_ASSERT(w);
+ getFormLayoutItemPosition(lt, i, &row, &column, 0, &colspan);
+ if (colspan > 1 || column == 0)
+ rc[row].first = w;
+ if (colspan > 1 || column == 1)
+ rc[row].second = w;
+ }
+ }
+ if (debugLayout) {
+ qDebug() << "FormLayoutHelper::state: " << rowCount;
+ for (int r = 0; r < rowCount; r++)
+ qDebug() << " Row: " << r << rc[r].first << rc[r].second;
+ }
+ return rc;
+ }
+
+ void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
+ {
+ QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(formLayout);
+ m_states.push(state(formLayout));
+ }
+
+ void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
+ {
+ QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(!m_states.empty() && formLayout);
+
+ const FormLayoutState storedState = m_states.pop();
+ const FormLayoutState currentState = state(formLayout);
+ if (currentState == storedState)
+ return;
+ const int rowCount = storedState.size();
+ // clear out, shrink if required, but maintain items via map, pad spacers
+ const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout);
+ if (rowCount < formLayout->rowCount())
+ formLayout = static_cast<QFormLayout*>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout ));
+ for (int r = 0; r < rowCount; r++) {
+ QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second };
+ const bool spanning = widgets[0] != 0 && widgets[0] == widgets[1];
+ if (spanning) {
+ formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]);
+ } else {
+ for (int c = 0; c < FormLayoutColumns; c++) {
+ const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
+ if (widgets[c]) {
+ Q_ASSERT(BoxLayoutHelper::findItemOfWidget(items, widgets[c]));
+ formLayout->setWidget(r, role, widgets[c]);
+ } else {
+ formLayout->setItem(r, role, createFormSpacer());
+ }
+ }
+ }
+ }
+ }
+
+ bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
+ {
+ const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(formLayout);
+ return canSimplifyFormLayout(formLayout, restrictionArea);
+ }
+
+ void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
+ {
+ typedef QPair<QLayoutItem*, QLayoutItem*> LayoutItemPair;
+ typedef QVector<LayoutItemPair> LayoutItemPairs;
+
+ QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
+ Q_ASSERT(formLayout);
+ if (debugLayout)
+ qDebug() << "FormLayoutHelper::simplify";
+ // Transform into vector of item pairs
+ const int rowCount = formLayout->rowCount();
+ LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0));
+ for (int i = formLayout->count() - 1; i >= 0; i--) {
+ int row, col,colspan;
+ getFormLayoutItemPosition(formLayout, i, &row, &col, 0, &colspan);
+ if (colspan > 1) {
+ pairs[row].first = pairs[row].second = formLayout->takeAt(i);
+ } else {
+ if (col == 0)
+ pairs[row].first = formLayout->takeAt(i);
+ else
+ pairs[row].second = formLayout->takeAt(i);
+ }
+ }
+ // Weed out empty ones
+ const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height());
+ for (int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--)
+ if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) {
+ delete pairs[r].first;
+ delete pairs[r].second;
+ pairs.remove(r);
+ }
+ const int simpleRowCount = pairs.size();
+ if (simpleRowCount < rowCount)
+ formLayout = static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout));
+ // repopulate
+ for (int r = 0; r < simpleRowCount; r++) {
+ const bool spanning = pairs[r].first == pairs[r].second;
+ if (spanning) {
+ formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first);
+ } else {
+ formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first);
+ formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second);
+ }
+ }
+ }
+
+LayoutHelper *LayoutHelper::createLayoutHelper(int type)
+{
+ LayoutHelper *rc = 0;
+ switch (type) {
+ case LayoutInfo::HBox:
+ rc = new BoxLayoutHelper(Qt::Horizontal);
+ break;
+ case LayoutInfo::VBox:
+ rc = new BoxLayoutHelper(Qt::Vertical);
+ break;
+ case LayoutInfo::Grid:
+ rc = new GridLayoutHelper;
+ break;
+ case LayoutInfo::Form:
+ return new FormLayoutHelper;
+ default:
+ break;
+ }
+ Q_ASSERT(rc);
+ return rc;
+}
+
+// ---- QLayoutSupport (LayoutDecorationExtension)
+QLayoutSupport::QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent) :
+ QObject(parent),
+ m_formWindow(formWindow),
+ m_helper(helper),
+ m_widget(widget),
+ m_currentIndex(-1),
+ m_currentInsertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode)
+{
+}
+
+QLayout * QLayoutSupport::layout() const
+{
+ return LayoutInfo::managedLayout(m_formWindow->core(), m_widget);
+}
+
+void QLayoutSupport::hideIndicator(Indicator i)
+{
+ if (m_indicators[i])
+ m_indicators[i]->hide();
+}
+
+void QLayoutSupport::showIndicator(Indicator i, const QRect &geometry, const QPalette &p)
+{
+ if (!m_indicators[i])
+ m_indicators[i] = new qdesigner_internal::InvisibleWidget(m_widget);
+ QWidget *indicator = m_indicators[i];
+ indicator->setAutoFillBackground(true);
+ indicator->setPalette(p);
+ indicator->setGeometry(geometry);
+ indicator->show();
+ indicator->raise();
+}
+
+QLayoutSupport::~QLayoutSupport()
+{
+ delete m_helper;
+ for (int i = 0; i < NumIndicators; i++)
+ if (m_indicators[i])
+ m_indicators[i]->deleteLater();
+}
+
+QGridLayout * QLayoutSupport::gridLayout() const
+{
+ return qobject_cast<QGridLayout*>(LayoutInfo::managedLayout(m_formWindow->core(), m_widget));
+}
+
+QRect QLayoutSupport::itemInfo(int index) const
+{
+ return m_helper->itemInfo(LayoutInfo::managedLayout(m_formWindow->core(), m_widget), index);
+}
+
+void QLayoutSupport::setInsertMode(InsertMode im)
+{
+ m_currentInsertMode = im;
+}
+
+void QLayoutSupport::setCurrentCell(const QPair<int, int> &cell)
+{
+ m_currentCell = cell;
+}
+
+void QLayoutSupport::adjustIndicator(const QPoint &pos, int index)
+{
+ if (index == -1) { // first item goes anywhere
+ hideIndicator(LeftIndicator);
+ hideIndicator(TopIndicator);
+ hideIndicator(RightIndicator);
+ hideIndicator(BottomIndicator);
+ return;
+ }
+ m_currentIndex = index;
+ m_currentInsertMode = QDesignerLayoutDecorationExtension::InsertWidgetMode;
+
+ QLayoutItem *item = layout()->itemAt(index);
+ const QRect g = extendedGeometry(index);
+ // ### cleanup
+ if (LayoutInfo::isEmptyItem(item)) {
+ // Empty grid/form cell. Draw a rectangle
+ QPalette redPalette;
+ redPalette.setColor(QPalette::Window, Qt::red);
+
+ showIndicator(LeftIndicator, QRect(g.x(), g.y(), indicatorSize, g.height()), redPalette);
+ showIndicator(TopIndicator, QRect(g.x(), g.y(), g.width(), indicatorSize), redPalette);
+ showIndicator(RightIndicator, QRect(g.right(), g.y(), indicatorSize, g.height()), redPalette);
+ showIndicator(BottomIndicator, QRect(g.x(), g.bottom(), g.width(), indicatorSize), redPalette);
+ setCurrentCellFromIndicatorOnEmptyCell(m_currentIndex);
+ } else {
+ // Append/Insert. Draw a bar left/right or above/below
+ QPalette bluePalette;
+ bluePalette.setColor(QPalette::Window, Qt::blue);
+ hideIndicator(LeftIndicator);
+ hideIndicator(TopIndicator);
+
+ const int fromRight = g.right() - pos.x();
+ const int fromBottom = g.bottom() - pos.y();
+
+ const int fromLeft = pos.x() - g.x();
+ const int fromTop = pos.y() - g.y();
+
+ const int fromLeftRight = qMin(fromRight, fromLeft );
+ const int fromBottomTop = qMin(fromBottom, fromTop);
+
+ const Qt::Orientation indicatorOrientation = fromLeftRight < fromBottomTop ? Qt::Vertical : Qt::Horizontal;
+
+ if (supportsIndicatorOrientation(indicatorOrientation)) {
+ const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size());
+ switch (indicatorOrientation) {
+ case Qt::Vertical: {
+ hideIndicator(BottomIndicator);
+ const bool closeToLeft = fromLeftRight == fromLeft;
+ showIndicator(RightIndicator, QRect(closeToLeft ? g.x() : g.right() + 1 - indicatorSize, 0, indicatorSize, r.height()), bluePalette);
+
+ const int incr = closeToLeft ? 0 : +1;
+ setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr);
+ }
+ break;
+ case Qt::Horizontal: {
+ hideIndicator(RightIndicator);
+ const bool closeToTop = fromBottomTop == fromTop;
+ showIndicator(BottomIndicator, QRect(r.x(), closeToTop ? g.y() : g.bottom() + 1 - indicatorSize, r.width(), indicatorSize), bluePalette);
+
+ const int incr = closeToTop ? 0 : +1;
+ setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr);
+ }
+ break;
+ }
+ } else {
+ hideIndicator(RightIndicator);
+ hideIndicator(BottomIndicator);
+ } // can handle indicatorOrientation
+ }
+}
+
+int QLayoutSupport::indexOf(QLayoutItem *i) const
+{
+ const QLayout *lt = layout();
+ if (!lt)
+ return -1;
+
+ int index = 0;
+
+ while (QLayoutItem *item = lt->itemAt(index)) {
+ if (item == i)
+ return index;
+
+ ++index;
+ }
+
+ return -1;
+}
+
+int QLayoutSupport::indexOf(QWidget *widget) const
+{
+ const QLayout *lt = layout();
+ if (!lt)
+ return -1;
+
+ int index = 0;
+ while (QLayoutItem *item = lt->itemAt(index)) {
+ if (item->widget() == widget)
+ return index;
+
+ ++index;
+ }
+
+ return -1;
+}
+
+QList<QWidget*> QLayoutSupport::widgets(QLayout *layout) const
+{
+ if (!layout)
+ return QList<QWidget*>();
+
+ QList<QWidget*> lst;
+ int index = 0;
+ while (QLayoutItem *item = layout->itemAt(index)) {
+ ++index;
+
+ QWidget *widget = item->widget();
+ if (widget && formWindow()->isManaged(widget))
+ lst.append(widget);
+ }
+
+ return lst;
+}
+
+int QLayoutSupport::findItemAt(QGridLayout *gridLayout, int at_row, int at_column)
+{
+ return findGridItemAt(gridLayout, at_row, at_column);
+}
+
+// Quick check whether simplify should be enabled for grids. May return false positives.
+// Note: Calculating the occupied area does not work as spanning items may also be simplified.
+
+bool QLayoutSupport::canSimplifyQuickCheck(const QGridLayout *gl)
+{
+ if (!gl)
+ return false;
+ const int colCount = gl->columnCount();
+ const int rowCount = gl->rowCount();
+ if (colCount < 2 || rowCount < 2)
+ return false;
+ // try to find a spacer.
+ const int count = gl->count();
+ for (int index = 0; index < count; index++)
+ if (LayoutInfo::isEmptyItem(gl->itemAt(index)))
+ return true;
+ return false;
+}
+
+bool QLayoutSupport::canSimplifyQuickCheck(const QFormLayout *fl)
+{
+ return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767)));
+}
+
+// remove dummy spacers
+bool QLayoutSupport::removeEmptyCells(QGridLayout *grid, const QRect &area)
+{
+ return removeEmptyCellsOnGrid(grid, area);
+}
+
+void QLayoutSupport::createEmptyCells(QGridLayout *gridLayout)
+{
+ Q_ASSERT(gridLayout);
+ GridLayoutState gs;
+ gs.fromLayout(gridLayout);
+
+ const GridLayoutState::CellStates cs = GridLayoutState::cellStates(gs.widgetItemMap.values(), gs.rowCount, gs.colCount);
+ for (int c = 0; c < gs.colCount; c++)
+ for (int r = 0; r < gs.rowCount; r++)
+ if (needsSpacerItem(cs[r * gs.colCount + c])) {
+ const int existingItemIndex = findItemAt(gridLayout, r, c);
+ if (existingItemIndex == -1)
+ gridLayout->addItem(createGridSpacer(), r, c);
+ }
+}
+
+bool QLayoutSupport::removeEmptyCells(QFormLayout *formLayout, const QRect &area)
+{
+ return removeEmptyCellsOnGrid(formLayout, area);
+}
+
+void QLayoutSupport::createEmptyCells(QFormLayout *formLayout)
+{
+ // No spanning items here..
+ if (const int rowCount = formLayout->rowCount())
+ for (int c = 0; c < FormLayoutColumns; c++)
+ for (int r = 0; r < rowCount; r++)
+ if (findGridItemAt(formLayout, r, c) == -1)
+ formLayout->setItem(r, c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole, createFormSpacer());
+}
+
+int QLayoutSupport::findItemAt(const QPoint &pos) const
+{
+ if (!layout())
+ return -1;
+
+ const QLayout *lt = layout();
+ const int count = lt->count();
+
+ if (count == 0)
+ return -1;
+
+ int best = -1;
+ int bestIndex = -1;
+
+ for (int index = 0; index < count; index++) {
+ QLayoutItem *item = lt->itemAt(index);
+ bool visible = true;
+ // When dragging widgets within layout, the source widget is invisible and must not be hit
+ if (const QWidget *w = item->widget())
+ visible = w->isVisible();
+ if (visible) {
+ const QRect g = item->geometry();
+
+ const int dist = (g.center() - pos).manhattanLength();
+ if (best == -1 || dist < best) {
+ best = dist;
+ bestIndex = index;
+ }
+ }
+ }
+ return bestIndex;
+}
+
+// ------------ QBoxLayoutSupport (LayoutDecorationExtension)
+namespace {
+class QBoxLayoutSupport: public QLayoutSupport
+{
+public:
+ QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = 0);
+
+ virtual void insertWidget(QWidget *widget, const QPair<int, int> &cell);
+ virtual void removeWidget(QWidget *widget);
+ virtual void simplify() {}
+ virtual void insertRow(int /*row*/) {}
+ virtual void insertColumn(int /*column*/) {}
+
+ virtual int findItemAt(int /*at_row*/, int /*at_column*/) const { return -1; }
+
+private:
+ virtual void setCurrentCellFromIndicatorOnEmptyCell(int index);
+ virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment);
+ virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const;
+ virtual QRect extendedGeometry(int index) const;
+
+ const Qt::Orientation m_orientation;
+};
+
+void QBoxLayoutSupport::removeWidget(QWidget *widget)
+{
+ QLayout *lt = layout();
+ const int index = lt->indexOf(widget);
+ // Adjust the current cell in case a widget was dragged within the same layout to a position
+ // of higher index, which happens as follows:
+ // Drag start: The widget is hidden
+ // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated
+ QPair<int, int> currCell = currentCell();
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ if (currCell.second > 0 && index < currCell.second ) {
+ currCell.second--;
+ setCurrentCell(currCell);
+ }
+ break;
+ case Qt::Vertical:
+ if (currCell.first > 0 && index < currCell.first) {
+ currCell.first--;
+ setCurrentCell(currCell);
+ }
+ break;
+ }
+ helper()->removeWidget(lt, widget);
+}
+
+QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) :
+ QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent),
+ m_orientation(orientation)
+{
+}
+
+void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index)
+{
+ qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index;
+ setCurrentCell(qMakePair(0, 0));
+}
+
+void QBoxLayoutSupport::insertWidget(QWidget *widget, const QPair<int, int> &cell)
+{
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget);
+ break;
+ case Qt::Vertical:
+ helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget);
+ break;
+ }
+}
+
+void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment)
+{
+ if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical) {
+ setCurrentCell(qMakePair(0, index + increment));
+ } else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal) {
+ setCurrentCell(qMakePair(index + increment, 0));
+ }
+}
+
+bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const
+{
+ return m_orientation != indicatorOrientation;
+}
+
+QRect QBoxLayoutSupport::extendedGeometry(int index) const
+{
+ QLayoutItem *item = layout()->itemAt(index);
+ // start off with item geometry
+ QRect g = item->geometry();
+
+ const QRect info = itemInfo(index);
+
+ // On left border: extend to widget border
+ if (info.x() == 0) {
+ QPoint topLeft = g.topLeft();
+ topLeft.rx() = layout()->geometry().left();
+ g.setTopLeft(topLeft);
+ }
+
+ // On top border: extend to widget border
+ if (info.y() == 0) {
+ QPoint topLeft = g.topLeft();
+ topLeft.ry() = layout()->geometry().top();
+ g.setTopLeft(topLeft);
+ }
+
+ // is this the last item?
+ const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
+ if (index < box->count() -1)
+ return g; // Nope.
+
+ // extend to widget border
+ QPoint bottomRight = g.bottomRight();
+ switch (m_orientation) {
+ case Qt::Vertical:
+ bottomRight.ry() = layout()->geometry().bottom();
+ break;
+ case Qt::Horizontal:
+ bottomRight.rx() = layout()->geometry().right();
+ break;
+ }
+ g.setBottomRight(bottomRight);
+ return g;
+}
+
+// -------------- Base class for QGridLayout-like support classes (LayoutDecorationExtension)
+template <class GridLikeLayout>
+class GridLikeLayoutSupportBase: public QLayoutSupport
+{
+public:
+
+ GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0) :
+ QLayoutSupport(formWindow, widget, helper, parent) {}
+
+ void insertWidget(QWidget *widget, const QPair<int, int> &cell);
+ virtual void removeWidget(QWidget *widget) { helper()->removeWidget(layout(), widget); }
+ virtual int findItemAt(int row, int column) const;
+
+protected:
+ GridLikeLayout *gridLikeLayout() const {
+ return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget()));
+ }
+
+private:
+
+ virtual void setCurrentCellFromIndicatorOnEmptyCell(int index);
+ virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment);
+ virtual bool supportsIndicatorOrientation(Qt::Orientation) const { return true; }
+
+ virtual QRect extendedGeometry(int index) const;
+
+ // Overwrite to check the insertion position (if there are limits)
+ virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {}
+};
+
+template <class GridLikeLayout>
+void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(int index)
+{
+ GridLikeLayout *grid = gridLikeLayout();
+ Q_ASSERT(grid);
+
+ setInsertMode(InsertWidgetMode);
+ int row, column, rowspan, colspan;
+
+ getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan);
+ setCurrentCell(qMakePair(row, column));
+}
+
+template <class GridLikeLayout>
+void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) {
+ const QRect info = itemInfo(index);
+ switch (indicatorOrientation) {
+ case Qt::Vertical: {
+ setInsertMode(InsertColumnMode);
+ int row = info.top();
+ int column = increment ? info.right() + 1 : info.left();
+ checkCellForInsertion(&row, &column);
+ setCurrentCell(qMakePair(row , column));
+ }
+ break;
+ case Qt::Horizontal: {
+ setInsertMode(InsertRowMode);
+ int row = increment ? info.bottom() + 1 : info.top();
+ int column = info.left();
+ checkCellForInsertion(&row, &column);
+ setCurrentCell(qMakePair(row, column));
+ }
+ break;
+ }
+}
+
+template <class GridLikeLayout>
+void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(QWidget *widget, const QPair<int, int> &cell)
+{
+ helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget);
+}
+
+template <class GridLikeLayout>
+int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(int at_row, int at_column) const
+{
+ GridLikeLayout *grid = gridLikeLayout();
+ Q_ASSERT(grid);
+ return findGridItemAt(grid, at_row, at_column);
+}
+
+template <class GridLikeLayout>
+QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(int index) const
+{
+ QLayoutItem *item = layout()->itemAt(index);
+ // start off with item geometry
+ QRect g = item->geometry();
+
+ const QRect info = itemInfo(index);
+
+ // On left border: extend to widget border
+ if (info.x() == 0) {
+ QPoint topLeft = g.topLeft();
+ topLeft.rx() = layout()->geometry().left();
+ g.setTopLeft(topLeft);
+ }
+
+ // On top border: extend to widget border
+ if (info.y() == 0) {
+ QPoint topLeft = g.topLeft();
+ topLeft.ry() = layout()->geometry().top();
+ g.setTopLeft(topLeft);
+ }
+ const GridLikeLayout *grid = gridLikeLayout();
+ Q_ASSERT(grid);
+
+ // extend to widget border
+ QPoint bottomRight = g.bottomRight();
+ if (gridRowCount(grid) == info.y())
+ bottomRight.ry() = layout()->geometry().bottom();
+ if (gridColumnCount(grid) == info.x())
+ bottomRight.rx() = layout()->geometry().right();
+ g.setBottomRight(bottomRight);
+ return g;
+}
+
+// -------------- QGridLayoutSupport (LayoutDecorationExtension)
+class QGridLayoutSupport: public GridLikeLayoutSupportBase<QGridLayout>
+{
+public:
+
+ QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0);
+
+ virtual void simplify();
+ virtual void insertRow(int row);
+ virtual void insertColumn(int column);
+
+private:
+};
+
+QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
+ GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget, new GridLayoutHelper, parent)
+{
+}
+
+void QGridLayoutSupport::insertRow(int row)
+{
+ QGridLayout *grid = gridLayout();
+ Q_ASSERT(grid);
+ GridLayoutHelper::insertRow(grid, row);
+}
+
+void QGridLayoutSupport::insertColumn(int column)
+{
+ QGridLayout *grid = gridLayout();
+ Q_ASSERT(grid);
+ GridLayoutState state;
+ state.fromLayout(grid);
+ state.insertColumn(column);
+ state.applyToLayout(formWindow()->core(), widget());
+}
+
+void QGridLayoutSupport::simplify()
+{
+ QGridLayout *grid = gridLayout();
+ Q_ASSERT(grid);
+ GridLayoutState state;
+ state.fromLayout(grid);
+
+ const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount);
+ if (state.simplify(fullArea, false))
+ state.applyToLayout(formWindow()->core(), widget());
+}
+
+// -------------- QFormLayoutSupport (LayoutDecorationExtension)
+class QFormLayoutSupport: public GridLikeLayoutSupportBase<QFormLayout>
+{
+public:
+ QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0);
+
+ virtual void simplify() {}
+ virtual void insertRow(int /*row*/) {}
+ virtual void insertColumn(int /*column*/) {}
+
+private:
+ virtual void checkCellForInsertion(int * row, int *col) const;
+};
+
+QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
+ GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget, new FormLayoutHelper, parent)
+{
+}
+
+void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const
+{
+ if (*col >= FormLayoutColumns) { // Clamp to 2 columns
+ *col = 1;
+ (*row)++;
+ }
+}
+} // anonymous namespace
+
+QLayoutSupport *QLayoutSupport::createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent)
+{
+ const QLayout *layout = LayoutInfo::managedLayout(formWindow->core(), widget);
+ Q_ASSERT(layout);
+ QLayoutSupport *rc = 0;
+ switch (LayoutInfo::layoutType(formWindow->core(), layout)) {
+ case LayoutInfo::HBox:
+ rc = new QBoxLayoutSupport(formWindow, widget, Qt::Horizontal, parent);
+ break;
+ case LayoutInfo::VBox:
+ rc = new QBoxLayoutSupport(formWindow, widget, Qt::Vertical, parent);
+ break;
+ case LayoutInfo::Grid:
+ rc = new QGridLayoutSupport(formWindow, widget, parent);
+ break;
+ case LayoutInfo::Form:
+ rc = new QFormLayoutSupport(formWindow, widget, parent);
+ break;
+ default:
+ break;
+ }
+ Q_ASSERT(rc);
+ return rc;
+}
+} // namespace qdesigner_internal
+
+// -------------- QLayoutWidget
+QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent)
+ : QWidget(parent), m_formWindow(formWindow),
+ m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0)
+{
+}
+
+void QLayoutWidget::paintEvent(QPaintEvent*)
+{
+ if (m_formWindow->currentTool() != 0)
+ return;
+
+ // only draw red borders if we're editting widgets
+
+ QPainter p(this);
+
+ QMap<int, QMap<int, bool> > excludedRowsForColumn;
+ QMap<int, QMap<int, bool> > excludedColumnsForRow;
+
+ QLayout *lt = layout();
+ QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
+ if (lt) {
+ if (const int count = lt->count()) {
+ p.setPen(QPen(QColor(255, 0, 0, 35), 1));
+ for (int i = 0; i < count; i++) {
+ QLayoutItem *item = lt->itemAt(i);
+ if (grid) {
+ int row, column, rowSpan, columnSpan;
+ grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan);
+ QMap<int, bool> rows;
+ QMap<int, bool> columns;
+ for (int i = rowSpan; i > 1; i--)
+ rows[row + i - 2] = true;
+ for (int i = columnSpan; i > 1; i--)
+ columns[column + i - 2] = true;
+
+ while (rowSpan > 0) {
+ excludedColumnsForRow[row + rowSpan - 1].unite(columns);
+ rowSpan--;
+ }
+ while (columnSpan > 0) {
+ excludedRowsForColumn[column + columnSpan - 1].unite(rows);
+ columnSpan--;
+ }
+ }
+ if (item->spacerItem()) {
+ const QRect geometry = item->geometry();
+ if (!geometry.isNull())
+ p.drawRect(geometry.adjusted(1, 1, -2, -2));
+ }
+ }
+ }
+ }
+ if (grid) {
+ p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1));
+ const int rowCount = grid->rowCount();
+ const int columnCount = grid->columnCount();
+ for (int i = 0; i < rowCount; i++) {
+ for (int j = 0; j < columnCount; j++) {
+ const QRect cellRect = grid->cellRect(i, j);
+ if (j < columnCount - 1 && excludedColumnsForRow.value(i).value(j, false) == false) {
+ const double y0 = (i == 0)
+ ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0;
+ const double y1 = (i == rowCount - 1)
+ ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
+ const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
+ p.drawLine(QPointF(x, y0), QPointF(x, y1));
+ }
+ if (i < rowCount - 1 && excludedRowsForColumn.value(j).value(i, false) == false) {
+ const double x0 = (j == 0)
+ ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0;
+ const double x1 = (j == columnCount - 1)
+ ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
+ const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
+ p.drawLine(QPointF(x0, y), QPointF(x1, y));
+ }
+ }
+ }
+ }
+ p.setPen(QPen(QColor(255, 0, 0, 128), 1));
+ p.drawRect(0, 0, width() - 1, height() - 1);
+}
+
+bool QLayoutWidget::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::LayoutRequest: {
+ (void) QWidget::event(e);
+ // Magic: We are layouted, but the parent is not..
+ if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) {
+ resize(layout()->totalMinimumSize().expandedTo(size()));
+ }
+
+ update();
+
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ return QWidget::event(e);
+}
+
+int QLayoutWidget::layoutLeftMargin() const
+{
+ if (m_leftMargin < 0 && layout()) {
+ int margin;
+ layout()->getContentsMargins(&margin, 0, 0, 0);
+ return margin;
+ }
+ return m_leftMargin;
+}
+
+void QLayoutWidget::setLayoutLeftMargin(int layoutMargin)
+{
+ m_leftMargin = layoutMargin;
+ if (layout()) {
+ int newMargin = m_leftMargin;
+ if (newMargin >= 0 && newMargin < ShiftValue)
+ newMargin = ShiftValue;
+ int left, top, right, bottom;
+ layout()->getContentsMargins(&left, &top, &right, &bottom);
+ layout()->setContentsMargins(newMargin, top, right, bottom);
+ }
+}
+
+int QLayoutWidget::layoutTopMargin() const
+{
+ if (m_topMargin < 0 && layout()) {
+ int margin;
+ layout()->getContentsMargins(0, &margin, 0, 0);
+ return margin;
+ }
+ return m_topMargin;
+}
+
+void QLayoutWidget::setLayoutTopMargin(int layoutMargin)
+{
+ m_topMargin = layoutMargin;
+ if (layout()) {
+ int newMargin = m_topMargin;
+ if (newMargin >= 0 && newMargin < ShiftValue)
+ newMargin = ShiftValue;
+ int left, top, right, bottom;
+ layout()->getContentsMargins(&left, &top, &right, &bottom);
+ layout()->setContentsMargins(left, newMargin, right, bottom);
+ }
+}
+
+int QLayoutWidget::layoutRightMargin() const
+{
+ if (m_rightMargin < 0 && layout()) {
+ int margin;
+ layout()->getContentsMargins(0, 0, &margin, 0);
+ return margin;
+ }
+ return m_rightMargin;
+}
+
+void QLayoutWidget::setLayoutRightMargin(int layoutMargin)
+{
+ m_rightMargin = layoutMargin;
+ if (layout()) {
+ int newMargin = m_rightMargin;
+ if (newMargin >= 0 && newMargin < ShiftValue)
+ newMargin = ShiftValue;
+ int left, top, right, bottom;
+ layout()->getContentsMargins(&left, &top, &right, &bottom);
+ layout()->setContentsMargins(left, top, newMargin, bottom);
+ }
+}
+
+int QLayoutWidget::layoutBottomMargin() const
+{
+ if (m_bottomMargin < 0 && layout()) {
+ int margin;
+ layout()->getContentsMargins(0, 0, 0, &margin);
+ return margin;
+ }
+ return m_bottomMargin;
+}
+
+void QLayoutWidget::setLayoutBottomMargin(int layoutMargin)
+{
+ m_bottomMargin = layoutMargin;
+ if (layout()) {
+ int newMargin = m_bottomMargin;
+ if (newMargin >= 0 && newMargin < ShiftValue)
+ newMargin = ShiftValue;
+ int left, top, right, bottom;
+ layout()->getContentsMargins(&left, &top, &right, &bottom);
+ layout()->setContentsMargins(left, top, right, newMargin);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qlayout_widget_p.h b/tools/designer/src/lib/shared/qlayout_widget_p.h
new file mode 100644
index 0000000..7856088
--- /dev/null
+++ b/tools/designer/src/lib/shared/qlayout_widget_p.h
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** 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 QLAYOUT_WIDGET_H
+#define QLAYOUT_WIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerLayoutDecorationExtension>
+
+#include <QtCore/QPointer>
+#include <QtCore/QVariant>
+#include <QtGui/QWidget>
+#include <QtGui/QLayout>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerFormEditorInterface;
+class QGridLayout;
+class QFormLayout;
+
+namespace qdesigner_internal {
+// ---- LayoutProperties: Helper struct that stores all layout-relevant properties
+// with functions to retrieve and apply to property sheets. Can be used to store the state
+// for undo commands and while rebuilding layouts.
+struct QDESIGNER_SHARED_EXPORT LayoutProperties
+{
+ LayoutProperties();
+ void clear();
+
+ enum Margins { LeftMargin, TopMargin, RightMargin, BottomMargin, MarginCount };
+ enum Spacings { Spacing, HorizSpacing, VertSpacing, SpacingsCount };
+
+ enum PropertyMask {
+ ObjectNameProperty = 0x1,
+ LeftMarginProperty = 0x2, TopMarginProperty = 0x4, RightMarginProperty = 0x8, BottomMarginProperty = 0x10,
+ SpacingProperty = 0x20, HorizSpacingProperty = 0x40, VertSpacingProperty = 0x80,
+ SizeConstraintProperty = 0x100,
+ FieldGrowthPolicyProperty = 0x200, RowWrapPolicyProperty = 0x400, LabelAlignmentProperty = 0x0800, FormAlignmentProperty = 0x1000,
+ BoxStretchProperty = 0x2000, GridRowStretchProperty = 0x4000, GridColumnStretchProperty = 0x8000,
+ GridRowMinimumHeightProperty = 0x10000, GridColumnMinimumWidthProperty = 0x20000,
+ AllProperties = 0xFFFF};
+
+ // return a PropertyMask of visible properties
+ static int visibleProperties(const QLayout *layout);
+
+ // Retrieve from /apply to sheet: A property mask is returned indicating the properties found in the sheet
+ int fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask = AllProperties);
+ int toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask = AllProperties, bool applyChanged = true) const;
+
+ int m_margins[MarginCount];
+ bool m_marginsChanged[MarginCount];
+
+ int m_spacings[SpacingsCount];
+ bool m_spacingsChanged[SpacingsCount];
+
+ QVariant m_objectName; // receives a PropertySheetStringValue
+ bool m_objectNameChanged;
+ QVariant m_sizeConstraint;
+ bool m_sizeConstraintChanged;
+
+ bool m_fieldGrowthPolicyChanged;
+ QVariant m_fieldGrowthPolicy;
+ bool m_rowWrapPolicyChanged;
+ QVariant m_rowWrapPolicy;
+ bool m_labelAlignmentChanged;
+ QVariant m_labelAlignment;
+ bool m_formAlignmentChanged;
+ QVariant m_formAlignment;
+
+ bool m_boxStretchChanged;
+ QVariant m_boxStretch;
+
+ bool m_gridRowStretchChanged;
+ QVariant m_gridRowStretch;
+
+ bool m_gridColumnStretchChanged;
+ QVariant m_gridColumnStretch;
+
+ bool m_gridRowMinimumHeightChanged;
+ QVariant m_gridRowMinimumHeight;
+
+ bool m_gridColumnMinimumWidthChanged;
+ QVariant m_gridColumnMinimumWidth;
+};
+
+// -- LayoutHelper: For use with the 'insert widget'/'delete widget' command,
+// able to store and restore states.
+// This could become part of 'QDesignerLayoutDecorationExtensionV2',
+// but to keep any existing old extensions working, it is provided as
+// separate class with a factory function.
+class LayoutHelper {
+protected:
+ LayoutHelper();
+
+public:
+ virtual ~LayoutHelper();
+
+ static LayoutHelper *createLayoutHelper(int type);
+
+ static int indexOf(const QLayout *lt, const QWidget *widget);
+
+ // Return area of an item (x == columns)
+ QRect itemInfo(QLayout *lt, const QWidget *widget) const;
+
+ virtual QRect itemInfo(QLayout *lt, int index) const = 0;
+ virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w) = 0;
+ virtual void removeWidget(QLayout *lt, QWidget *widget) = 0;
+ // Since 4.5: The 'morphing' feature requires an API for replacing widgets on layouts.
+ virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) = 0;
+
+ // Simplify a grid, remove empty columns, rows within the rectangle
+ // The DeleteWidget command restricts the area to be simplified.
+ virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const = 0;
+ virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) = 0;
+
+ // Push and pop a state. Can be used for implementing undo for
+ // simplify/row, column insertion commands, provided that
+ // the widgets remain the same.
+ virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) = 0;
+ virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) = 0;
+};
+
+// Base class for layout decoration extensions.
+class QDESIGNER_SHARED_EXPORT QLayoutSupport: public QObject, public QDesignerLayoutDecorationExtension
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerLayoutDecorationExtension)
+
+protected:
+ QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0);
+
+public:
+ virtual ~QLayoutSupport();
+
+ inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; }
+
+ // DecorationExtension V2
+ LayoutHelper* helper() const { return m_helper; }
+
+ // DecorationExtension
+ virtual int currentIndex() const { return m_currentIndex; }
+
+ virtual InsertMode currentInsertMode() const { return m_currentInsertMode; }
+
+ virtual QPair<int, int> currentCell() const { return m_currentCell; }
+
+ virtual int findItemAt(const QPoint &pos) const;
+ virtual int indexOf(QWidget *widget) const;
+ virtual int indexOf(QLayoutItem *item) const;
+
+ virtual void adjustIndicator(const QPoint &pos, int index);
+
+ virtual QList<QWidget*> widgets(QLayout *layout) const;
+
+ // Pad empty cells with dummy spacers. Called by layouting commands.
+ static void createEmptyCells(QGridLayout *gridLayout);
+ // remove dummy spacers in the area. Returns false if there are non-empty items in the way
+ static bool removeEmptyCells(QGridLayout *gridLayout, const QRect &area);
+ static void createEmptyCells(QFormLayout *formLayout); // ditto.
+ static bool removeEmptyCells(QFormLayout *formLayout, const QRect &area);
+
+ // grid helpers: find item index
+ static int findItemAt(QGridLayout *, int row, int column);
+ // grid helpers: Quick check whether simplify should be enabled for grids. May return false positives.
+ static bool canSimplifyQuickCheck(const QGridLayout *);
+ static bool canSimplifyQuickCheck(const QFormLayout *fl);
+ // Factory function, create layout support according to layout type of widget
+ static QLayoutSupport *createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0);
+
+protected:
+ // figure out insertion position and mode from indicator on empty cell if supported
+ virtual void setCurrentCellFromIndicatorOnEmptyCell(int index) = 0;
+ // figure out insertion position and mode from indicator
+ virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) = 0;
+
+ // Overwrite to return the extended geometry of an item, that is,
+ // if it is a border item, include the widget border for the indicator to work correctly
+ virtual QRect extendedGeometry(int index) const = 0;
+ virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const = 0;
+
+ QRect itemInfo(int index) const;
+ QLayout *layout() const;
+ QGridLayout *gridLayout() const;
+ QWidget *widget() const { return m_widget; }
+
+ void setInsertMode(InsertMode im);
+ void setCurrentCell(const QPair<int, int> &cell);
+
+private:
+ enum Indicator { LeftIndicator, TopIndicator, RightIndicator, BottomIndicator, NumIndicators };
+
+ void hideIndicator(Indicator i);
+ void showIndicator(Indicator i, const QRect &geometry, const QPalette &);
+
+ QDesignerFormWindowInterface *m_formWindow;
+ LayoutHelper* m_helper;
+
+ QPointer<QWidget> m_widget;
+ QPointer<QWidget> m_indicators[NumIndicators];
+ int m_currentIndex;
+ InsertMode m_currentInsertMode;
+ QPair<int, int> m_currentCell;
+};
+} // namespace qdesigner_internal
+
+// Red layout widget.
+class QDESIGNER_SHARED_EXPORT QLayoutWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ explicit QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent = 0);
+
+ int layoutLeftMargin() const;
+ void setLayoutLeftMargin(int layoutMargin);
+
+ int layoutTopMargin() const;
+ void setLayoutTopMargin(int layoutMargin);
+
+ int layoutRightMargin() const;
+ void setLayoutRightMargin(int layoutMargin);
+
+ int layoutBottomMargin() const;
+ void setLayoutBottomMargin(int layoutMargin);
+
+ inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; }
+
+protected:
+ virtual bool event(QEvent *e);
+ virtual void paintEvent(QPaintEvent *e);
+
+private:
+ QDesignerFormWindowInterface *m_formWindow;
+ int m_leftMargin;
+ int m_topMargin;
+ int m_rightMargin;
+ int m_bottomMargin;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_WIDGET_H
diff --git a/tools/designer/src/lib/shared/qscripthighlighter.cpp b/tools/designer/src/lib/shared/qscripthighlighter.cpp
new file mode 100644
index 0000000..3f1d638
--- /dev/null
+++ b/tools/designer/src/lib/shared/qscripthighlighter.cpp
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** 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 "qscripthighlighter_p.h"
+
+#include <QtCore/QSet>
+
+QT_BEGIN_NAMESPACE
+
+static const QSet<QString> &qscriptKeywords() {
+ static QSet<QString> keywords;
+ if (keywords.empty()) {
+ keywords.insert(QLatin1String("Infinity"));
+ keywords.insert(QLatin1String("NaN"));
+ keywords.insert(QLatin1String("abstract"));
+ 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("constructor"));
+ keywords.insert(QLatin1String("continue"));
+ keywords.insert(QLatin1String("debugger"));
+ keywords.insert(QLatin1String("default"));
+ keywords.insert(QLatin1String("delete"));
+ keywords.insert(QLatin1String("do"));
+ keywords.insert(QLatin1String("double"));
+ keywords.insert(QLatin1String("else"));
+ keywords.insert(QLatin1String("enum"));
+ keywords.insert(QLatin1String("export"));
+ keywords.insert(QLatin1String("extends"));
+ keywords.insert(QLatin1String("false"));
+ keywords.insert(QLatin1String("final"));
+ keywords.insert(QLatin1String("finally"));
+ keywords.insert(QLatin1String("float"));
+ keywords.insert(QLatin1String("for"));
+ keywords.insert(QLatin1String("function"));
+ keywords.insert(QLatin1String("goto"));
+ keywords.insert(QLatin1String("if"));
+ keywords.insert(QLatin1String("implements"));
+ keywords.insert(QLatin1String("import"));
+ keywords.insert(QLatin1String("in"));
+ 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("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("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("typeof"));
+ keywords.insert(QLatin1String("undefined"));
+ keywords.insert(QLatin1String("var"));
+ keywords.insert(QLatin1String("void"));
+ keywords.insert(QLatin1String("volatile"));
+ keywords.insert(QLatin1String("while"));
+ keywords.insert(QLatin1String("with")); // end
+ }
+ return keywords;
+}
+
+static QSet<QChar> alphaChars() {
+ QSet<QChar> rc;
+ const QString alpha = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ foreach (QChar chr, alpha)
+ rc.insert(chr);
+ return rc;
+}
+
+namespace qdesigner_internal {
+
+QScriptHighlighter::QScriptHighlighter(QTextDocument *parent)
+ : QSyntaxHighlighter(parent)
+{
+ m_numberFormat.setForeground(Qt::blue);
+ m_stringFormat.setForeground(Qt::darkGreen);
+ m_typeFormat.setForeground(Qt::darkMagenta);
+ m_keywordFormat.setForeground(Qt::darkYellow);
+ m_labelFormat.setForeground(Qt::darkRed);
+ m_commentFormat.setForeground(Qt::red);
+ //m_commentFormat.setFontFamily("times");
+ m_commentFormat.setFontItalic(true);
+ m_preProcessorFormat.setForeground(Qt::darkBlue);
+}
+
+void QScriptHighlighter::highlightBlock(const QString &text)
+{
+ // states
+ enum {
+ StateStandard,
+ StateCommentStart1,
+ StateCCommentStart2,
+ StateCppCommentStart2,
+ StateCComment,
+ StateCppComment,
+ StateCCommentEnd1,
+ StateCCommentEnd2,
+ StateStringStart,
+ StateString,
+ StateStringEnd,
+ StateString2Start,
+ StateString2,
+ StateString2End,
+ StateNumber,
+ StatePreProcessor,
+ NumStates
+ };
+ // tokens
+ enum {
+ InputAlpha,
+ InputNumber,
+ InputAsterix,
+ InputSlash,
+ InputParen,
+ InputSpace,
+ InputHash,
+ InputQuotation,
+ InputApostrophe,
+ InputSep,
+ NumInputs
+ };
+
+ static const uchar table[NumStates][NumInputs] = {
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard
+ { StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // CppCommentStart2
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment
+ { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment
+ { StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1
+ { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart
+ { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start
+ { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2
+ { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End
+ { StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber
+ { StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor
+ };
+
+ QString buffer;
+ buffer.reserve(text.length());
+ QTextCharFormat emptyFormat;
+
+ int state = StateStandard;
+ const int previousState = previousBlockState();
+ if (previousState != -1)
+ state = previousState;
+
+ if (text.isEmpty()) {
+ setCurrentBlockState(previousState);
+ return;
+ }
+
+ int input = -1;
+ int i = 0;
+ bool lastWasBackSlash = false;
+ bool makeLastStandard = false;
+
+ static const QSet<QChar> alphabeth = alphaChars();
+ static const QString mathChars = QString::fromLatin1("xXeE");
+ static const QString numbers = QString::fromLatin1("0123456789");
+ bool questionMark = false;
+ QChar lastChar;
+ QString firstWord;
+ forever {
+ const QChar c = text.at(i);
+
+ if (lastWasBackSlash) {
+ input = InputSep;
+ } else {
+ switch (c.toLatin1()) {
+ case '*':
+ input = InputAsterix;
+ break;
+ case '/':
+ input = InputSlash;
+ break;
+ case '(': case '[': case '{':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ )
+ //blockData->parentheses << Parenthesis(Parenthesis::Open, c, i);
+ break;
+ case ')': case ']': case '}':
+ input = InputParen;
+ if (state == StateStandard
+ || state == StateNumber
+ || state == StatePreProcessor
+ || state == StateCCommentEnd2
+ || state == StateCCommentEnd1
+ || state == StateString2End
+ || state == StateStringEnd
+ ) {
+ //blockData->parentheses << Parenthesis(Parenthesis::Closed, c, i);
+ }
+ break;
+ case '#':
+ input = InputHash;
+ break;
+ case '"':
+ input = InputQuotation;
+ break;
+ case '\'':
+ input = InputApostrophe;
+ break;
+ case ' ':
+ input = InputSpace;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '0':
+ if (alphabeth.contains(lastChar)
+ && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))) {
+ input = InputAlpha;
+ } else {
+ if (input == InputAlpha && numbers.contains(lastChar))
+ input = InputAlpha;
+ else
+ input = InputNumber;
+ }
+ break;
+ case ':': {
+ input = InputAlpha;
+ QChar nextChar = QLatin1Char(' ');
+ if (i < text.length() - 1)
+ nextChar = text.at(i + 1);
+ if (state == StateStandard && !questionMark &&
+ lastChar != QLatin1Char(':') && nextChar != QLatin1Char(':')) {
+ for (int j = 0; j < i; ++j) {
+ if (format(j) == emptyFormat)
+ setFormat(j, 1, m_labelFormat);
+ }
+ }
+ break;
+ }
+ default: {
+ if (!questionMark && c == QLatin1Char('?'))
+ questionMark = true;
+ if (c.isLetter() || c == QLatin1Char('_'))
+ input = InputAlpha;
+ else
+ input = InputSep;
+ } break;
+ }
+ }
+
+ lastWasBackSlash = !lastWasBackSlash && c == QLatin1Char('\\');
+
+ if (input == InputAlpha)
+ buffer += c;
+
+ state = table[state][input];
+
+ switch (state) {
+ case StateStandard: {
+ setFormat(i, 1, emptyFormat);
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ if (!buffer.isEmpty() && input != InputAlpha ) {
+ highlightKeyword(i, buffer);
+ buffer.clear();
+ }
+ } break;
+ case StateCommentStart1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = true;
+ buffer.resize(0);
+ break;
+ case StateCCommentStart2:
+ setFormat(i - 1, 2, m_commentFormat);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCppCommentStart2:
+ setFormat(i - 1, 2, m_commentFormat);
+ makeLastStandard = false;
+ buffer.resize(0);
+ break;
+ case StateCComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_commentFormat);
+ buffer.resize(0);
+ break;
+ case StateCppComment:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_commentFormat);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd1:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_commentFormat);
+ buffer.resize(0);
+ break;
+ case StateCCommentEnd2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_commentFormat);
+ buffer.resize(0);
+ break;
+ case StateStringStart:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_stringFormat);
+ buffer.resize(0);
+ break;
+ case StateStringEnd:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2Start:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateString2:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_stringFormat);
+ buffer.resize(0);
+ break;
+ case StateString2End:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, emptyFormat);
+ buffer.resize(0);
+ break;
+ case StateNumber:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat( i, 1, m_numberFormat);
+ buffer.resize(0);
+ break;
+ case StatePreProcessor:
+ if (makeLastStandard)
+ setFormat(i - 1, 1, emptyFormat);
+ makeLastStandard = false;
+ setFormat(i, 1, m_preProcessorFormat);
+ buffer.resize(0);
+ break;
+ }
+
+ lastChar = c;
+ i++;
+ if (i >= text.length())
+ break;
+ }
+
+ highlightKeyword(text.length(), buffer);
+
+ if (state == StateCComment
+ || state == StateCCommentEnd1
+ || state == StateCCommentStart2
+ ) {
+ state = StateCComment;
+ } else if (state == StateString) {
+ state = StateString;
+ } else if (state == StateString2) {
+ state = StateString2;
+ } else {
+ state = StateStandard;
+ }
+
+ setCurrentBlockState(state);
+}
+
+void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer)
+{
+ if (buffer.isEmpty())
+ return;
+
+ if (buffer.at(0) == QLatin1Char('Q')) {
+ setFormat(currentPos - buffer.length(), buffer.length(), m_typeFormat);
+ } else {
+ if (qscriptKeywords().contains(buffer)) {
+ setFormat(currentPos - buffer.length(), buffer.length(), m_keywordFormat);
+ }
+ }
+}
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qscripthighlighter_p.h b/tools/designer/src/lib/shared/qscripthighlighter_p.h
new file mode 100644
index 0000000..9530ba2
--- /dev/null
+++ b/tools/designer/src/lib/shared/qscripthighlighter_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** 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 QSCRIPTSYNTAXHIGHLIGHTER_H
+#define QSCRIPTSYNTAXHIGHLIGHTER_H
+
+#include <QtGui/QSyntaxHighlighter>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+class QScriptHighlighter : public QSyntaxHighlighter
+{
+public:
+ explicit QScriptHighlighter(QTextDocument *parent);
+ virtual void highlightBlock(const QString &text);
+
+private:
+ void highlightKeyword(int currentPos, const QString &buffer);
+
+ QTextCharFormat m_numberFormat;
+ QTextCharFormat m_stringFormat;
+ QTextCharFormat m_typeFormat;
+ QTextCharFormat m_keywordFormat;
+ QTextCharFormat m_labelFormat;
+ QTextCharFormat m_commentFormat;
+ QTextCharFormat m_preProcessorFormat;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/qsimpleresource.cpp b/tools/designer/src/lib/shared/qsimpleresource.cpp
new file mode 100644
index 0000000..8d29002
--- /dev/null
+++ b/tools/designer/src/lib/shared/qsimpleresource.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** 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 "qsimpleresource_p.h"
+#include "widgetfactory_p.h"
+
+#include <formscriptrunner_p.h>
+#include <properties_p.h>
+#include <ui4_p.h>
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <script_p.h>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerCustomWidgetInterface>
+#include <QtDesigner/extrainfo.h>
+
+#include <QtGui/QIcon>
+#include <QtGui/QWidget>
+#include <QtGui/QAction>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ typedef QList<DomWidgetData*> DomWidgetDataList;
+ typedef QList<DomProperty*> DomPropertyList;
+ typedef QList<QDesignerCustomWidgetInterface *> CustomWidgetInterfaces;
+}
+
+namespace qdesigner_internal {
+
+bool QSimpleResource::m_warningsEnabled = true;
+
+QSimpleResource::QSimpleResource(QDesignerFormEditorInterface *core) :
+ QAbstractFormBuilder(),
+ m_core(core)
+{
+ QString workingDirectory = QDir::homePath();
+ workingDirectory += QDir::separator();
+ workingDirectory += QLatin1String(".designer");
+ setWorkingDirectory(QDir(workingDirectory));
+ // Disable scripting in the editors.
+ formScriptRunner()-> setOptions(QFormScriptRunner::DisableScripts);
+}
+
+QSimpleResource::~QSimpleResource()
+{
+
+}
+
+QBrush QSimpleResource::setupBrush(DomBrush *brush)
+{
+ return QAbstractFormBuilder::setupBrush(brush);
+}
+
+DomBrush *QSimpleResource::saveBrush(const QBrush &brush)
+{
+ return QAbstractFormBuilder::saveBrush(brush);
+}
+
+QIcon QSimpleResource::nameToIcon(const QString &filePath, const QString &qrcPath)
+{
+ Q_UNUSED(filePath)
+ Q_UNUSED(qrcPath)
+ qWarning() << "QSimpleResource::nameToIcon() is obsoleted";
+ return QIcon();
+}
+
+QString QSimpleResource::iconToFilePath(const QIcon &pm) const
+{
+ Q_UNUSED(pm)
+ qWarning() << "QSimpleResource::iconToFilePath() is obsoleted";
+ return QString();
+}
+
+QString QSimpleResource::iconToQrcPath(const QIcon &pm) const
+{
+ Q_UNUSED(pm)
+ qWarning() << "QSimpleResource::iconToQrcPath() is obsoleted";
+ return QString();
+}
+
+QPixmap QSimpleResource::nameToPixmap(const QString &filePath, const QString &qrcPath)
+{
+ Q_UNUSED(filePath)
+ Q_UNUSED(qrcPath)
+ qWarning() << "QSimpleResource::nameToPixmap() is obsoleted";
+ return QPixmap();
+}
+
+QString QSimpleResource::pixmapToFilePath(const QPixmap &pm) const
+{
+ Q_UNUSED(pm)
+ qWarning() << "QSimpleResource::pixmapToFilePath() is obsoleted";
+ return QString();
+}
+
+QString QSimpleResource::pixmapToQrcPath(const QPixmap &pm) const
+{
+ Q_UNUSED(pm)
+ qWarning() << "QSimpleResource::pixmapToQrcPath() is obsoleted";
+ return QString();
+}
+
+DomScript *QSimpleResource::createScript(const QString &script, ScriptSource source)
+{
+ if (script.isEmpty())
+ return 0;
+ DomScript *domScript = new DomScript();
+ switch (source) {
+ case ScriptExtension:
+ domScript->setAttributeSource(QLatin1String("extension"));
+ break;
+ case ScriptDesigner:
+ domScript->setAttributeSource(QLatin1String("designer"));
+ break;
+ case ScriptCustomWidgetPlugin:
+ domScript->setAttributeSource(QLatin1String("customwidgetplugin"));
+ break;
+ }
+ domScript->setAttributeLanguage(QLatin1String("Qt Script"));
+ domScript->setText(script);
+ return domScript;
+}
+
+// Add a script to a list of DomScripts unless empty
+void QSimpleResource::addScript(const QString &script, ScriptSource source, DomScripts &domScripts)
+{
+ if (DomScript *domScript = createScript(script, source)) {
+ domScripts += domScript;
+ }
+}
+
+void QSimpleResource::addExtensionDataToDOM(QAbstractFormBuilder *afb,
+ QDesignerFormEditorInterface *core,
+ DomWidget *ui_widget, QWidget *widget)
+{
+ QExtensionManager *emgr = core->extensionManager();
+ if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(emgr, widget)) {
+ extra->saveWidgetExtraInfo(ui_widget);
+ }
+ if (QDesignerScriptExtension *scriptExt = qt_extension<QDesignerScriptExtension*>(emgr, widget)) {
+ // Add internal state
+ const QVariantMap data = scriptExt->data();
+ if (!data.empty()) {
+ // Convert the map to a DomState.
+ // We pass on the widget for property introspection. Thus, non-designable properties
+ // that have to be converted using QMetaObject (enums and the like) will work.
+ DomPropertyList properties;
+ const QVariantMap::const_iterator vcend = data.constEnd();
+ for (QVariantMap::const_iterator it = data.constBegin(); it != vcend; ++it) {
+ if (DomProperty *prop = variantToDomProperty(afb, widget->metaObject(), it.key(), it.value()))
+ properties += prop;
+ }
+ if (!properties.empty()) {
+ DomWidgetData *domData = new DomWidgetData;
+ domData->setElementProperty(properties);
+ DomWidgetDataList domDataList;
+ domDataList += domData;
+ ui_widget->setElementWidgetData(domDataList);
+ }
+
+ }
+ // Add script
+ const QString script = scriptExt->script();
+ if (!script.isEmpty()) {
+ DomScripts domScripts = ui_widget->elementScript();
+ addScript(script, ScriptExtension, domScripts);
+ ui_widget->setElementScript(domScripts);
+ }
+ }
+}
+
+void QSimpleResource::applyExtensionDataFromDOM(QAbstractFormBuilder *afb,
+ QDesignerFormEditorInterface *core,
+ DomWidget *ui_widget, QWidget *widget, bool applyState)
+{
+ QExtensionManager *emgr = core->extensionManager();
+ if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(emgr, widget)) {
+ extra->loadWidgetExtraInfo(ui_widget);
+ }
+ if (applyState) {
+ if (QDesignerScriptExtension *scriptExt = qt_extension<QDesignerScriptExtension*>(emgr, widget)) {
+ // Apply the state.
+ // We pass on the widget for property introspection. Thus, non-designable properties
+ // that have to be converted using QMetaObject (enums and the like) will work.
+ QVariantMap data;
+ DomWidgetDataList domDataList = ui_widget->elementWidgetData();
+ if (!domDataList.empty()) {
+ foreach (const DomWidgetData *domData, domDataList) {
+ const DomPropertyList properties = domData->elementProperty();
+ foreach(const DomProperty *prop, properties) {
+ const QVariant vprop = domPropertyToVariant(afb, widget->metaObject(), prop);
+ if (vprop.type() != QVariant::Invalid)
+ data.insert(prop->attributeName(), vprop);
+ }
+ }
+ }
+ scriptExt->setData(data);
+ }
+ }
+}
+
+QString QSimpleResource::customWidgetScript(QDesignerFormEditorInterface *core, QObject *object)
+{
+ return customWidgetScript(core, qdesigner_internal::WidgetFactory::classNameOf(core, object));
+}
+
+bool QSimpleResource::hasCustomWidgetScript(QDesignerFormEditorInterface *, QObject *)
+{
+ return false;
+}
+
+QString QSimpleResource::customWidgetScript(QDesignerFormEditorInterface *, const QString &)
+{
+ return QString();
+}
+
+bool QSimpleResource::setWarningsEnabled(bool warningsEnabled)
+{
+ const bool rc = m_warningsEnabled;
+ m_warningsEnabled = warningsEnabled;
+ return rc;
+}
+
+bool QSimpleResource::warningsEnabled()
+{
+ return m_warningsEnabled;
+}
+
+// ------------ FormBuilderClipboard
+
+FormBuilderClipboard::FormBuilderClipboard(QWidget *w)
+{
+ m_widgets += w;
+}
+
+bool FormBuilderClipboard::empty() const
+{
+ return m_widgets.empty() && m_actions.empty();
+}
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/qsimpleresource_p.h b/tools/designer/src/lib/shared/qsimpleresource_p.h
new file mode 100644
index 0000000..8d45c3c
--- /dev/null
+++ b/tools/designer/src/lib/shared/qsimpleresource_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 QSIMPLERESOURCE_H
+#define QSIMPLERESOURCE_H
+
+#include "shared_global_p.h"
+#include "abstractformbuilder.h"
+
+QT_BEGIN_NAMESPACE
+
+class DomScript;
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT QSimpleResource : public QAbstractFormBuilder
+{
+public:
+ explicit QSimpleResource(QDesignerFormEditorInterface *core);
+ virtual ~QSimpleResource();
+
+ QBrush setupBrush(DomBrush *brush);
+ DomBrush *saveBrush(const QBrush &brush);
+
+ inline QDesignerFormEditorInterface *core() const
+ { return m_core; }
+
+ // Query extensions for additional data
+ static void addExtensionDataToDOM(QAbstractFormBuilder *afb,
+ QDesignerFormEditorInterface *core,
+ DomWidget *ui_widget, QWidget *widget);
+ static void applyExtensionDataFromDOM(QAbstractFormBuilder *afb,
+ QDesignerFormEditorInterface *core,
+ DomWidget *ui_widget, QWidget *widget,
+ bool applyState);
+ // Enable warnings while saving. Turn off for backups.
+ static bool setWarningsEnabled(bool warningsEnabled);
+ static bool warningsEnabled();
+ // Return the script returned by the CustomWidget codeTemplate API
+ static QString customWidgetScript(QDesignerFormEditorInterface *core, QObject *object);
+ static QString customWidgetScript(QDesignerFormEditorInterface *core, const QString &className);
+ static bool hasCustomWidgetScript(QDesignerFormEditorInterface *core, QObject *object);
+
+protected:
+ virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath);
+ virtual QString iconToFilePath(const QIcon &pm) const;
+ virtual QString iconToQrcPath(const QIcon &pm) const;
+ virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath);
+ virtual QString pixmapToFilePath(const QPixmap &pm) const;
+ virtual QString pixmapToQrcPath(const QPixmap &pm) const;
+
+ enum ScriptSource { ScriptDesigner, ScriptExtension, ScriptCustomWidgetPlugin };
+ static DomScript*createScript(const QString &script, ScriptSource source);
+ typedef QList<DomScript*> DomScripts;
+ static void addScript(const QString &script, ScriptSource source, DomScripts &domScripts);
+
+private:
+ static bool m_warningsEnabled;
+ QDesignerFormEditorInterface *m_core;
+};
+
+// Contents of clipboard for formbuilder copy and paste operations
+// (Actions and widgets)
+struct QDESIGNER_SHARED_EXPORT FormBuilderClipboard {
+ typedef QList<QAction*> ActionList;
+
+ FormBuilderClipboard() {}
+ FormBuilderClipboard(QWidget *w);
+
+ bool empty() const;
+
+ QWidgetList m_widgets;
+ ActionList m_actions;
+};
+
+// Base class for a form builder used in the editor that
+// provides copy and paste.(move into base interface)
+class QDESIGNER_SHARED_EXPORT QEditorFormBuilder : public QSimpleResource
+{
+public:
+ explicit QEditorFormBuilder(QDesignerFormEditorInterface *core) : QSimpleResource(core) {}
+
+ virtual bool copy(QIODevice *dev, const FormBuilderClipboard &selection) = 0;
+ virtual DomUI *copy(const FormBuilderClipboard &selection) = 0;
+
+ // A widget parent needs to be specified, otherwise, the widget factory cannot locate the form window via parent
+ // and thus is not able to construct special widgets (QLayoutWidget).
+ virtual FormBuilderClipboard paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent = 0) = 0;
+ virtual FormBuilderClipboard paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent = 0) = 0;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/qtresourceeditordialog.cpp b/tools/designer/src/lib/shared/qtresourceeditordialog.cpp
new file mode 100644
index 0000000..adddf72
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourceeditordialog.cpp
@@ -0,0 +1,2226 @@
+/****************************************************************************
+**
+** 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 "abstractsettings_p.h"
+#include "abstractformeditor.h"
+#include "qtresourceeditordialog_p.h"
+#include "ui_qtresourceeditordialog.h"
+#include "qtresourcemodel_p.h"
+#include "iconloader_p.h"
+
+#include <abstractdialoggui_p.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtXml/QDomDocument>
+#include <QtGui/QMenu>
+#include <QtGui/QHeaderView>
+#include <QtGui/QInputDialog>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+#include <QtGui/QStandardItemModel>
+
+QT_BEGIN_NAMESPACE
+
+static const char *rccRootTag = "RCC";
+static const char *rccTag = "qresource";
+static const char *rccFileTag = "file";
+static const char *rccAliasAttribute = "alias";
+static const char *rccPrefixAttribute = "prefix";
+static const char *rccLangAttribute = "lang";
+static const char *SplitterPosition = "SplitterPosition";
+static const char *Geometry = "Geometry";
+static const char *QrcDialogC = "QrcDialog";
+
+static QString msgOverwrite(const QString &fname)
+{
+ return QApplication::translate("QtResourceEditorDialog", "%1 already exists.\nDo you want to replace it?", 0, QApplication::UnicodeUTF8).arg(fname);
+}
+
+static QString msgTagMismatch(const QString &got, const QString &expected)
+{
+ return QApplication::translate("QtResourceEditorDialog", "The file does not appear to be a resource file; element '%1' was found where '%2' was expected.").arg(got).arg(expected);
+}
+
+namespace {
+
+// below 3 data classes should be derived from QSharedData and made implicit shared class
+struct QtResourceFileData {
+ QString path;
+ QString alias;
+ bool operator==(const QtResourceFileData &other) const {
+ if (path == other.path && alias == other.alias)
+ return true;
+ return false;
+ }
+};
+
+struct QtResourcePrefixData {
+ QString prefix;
+ QString language;
+ QList<QtResourceFileData> resourceFileList;
+ bool operator==(const QtResourcePrefixData &other) const {
+ if (prefix == other.prefix && language == other.language && resourceFileList == other.resourceFileList)
+ return true;
+ return false;
+ }
+};
+
+struct QtQrcFileData {
+ QString qrcPath;
+ QList<QtResourcePrefixData> resourceList;
+ bool operator==(const QtQrcFileData &other) const {
+ if (qrcPath == other.qrcPath && resourceList == other.resourceList)
+ return true;
+ return false;
+ }
+};
+
+bool loadResourceFileData(const QDomElement &fileElem, QtResourceFileData *fileData, QString *errorMessage)
+{
+ if (!fileData)
+ return false;
+
+ if (fileElem.tagName() != QLatin1String(rccFileTag)) {
+ *errorMessage = msgTagMismatch(fileElem.tagName(), QLatin1String(rccFileTag));
+ return false;
+ }
+
+ QtResourceFileData &data = *fileData;
+
+ data.path = fileElem.text();
+ data.alias = fileElem.attribute(QLatin1String(rccAliasAttribute));
+
+ return true;
+}
+
+static bool loadResourcePrefixData(const QDomElement &prefixElem, QtResourcePrefixData *prefixData, QString *errorMessage)
+{
+ if (!prefixData)
+ return false;
+
+ if (prefixElem.tagName() != QLatin1String(rccTag)) {
+ *errorMessage = msgTagMismatch(prefixElem.tagName(), QLatin1String(rccTag));
+ return false;
+ }
+
+ QtResourcePrefixData &data = *prefixData;
+
+ data.prefix = prefixElem.attribute(QLatin1String(rccPrefixAttribute));
+ data.language = prefixElem.attribute(QLatin1String(rccLangAttribute));
+ QDomElement fileElem = prefixElem.firstChildElement();
+ while (!fileElem.isNull()) {
+ QtResourceFileData fileData;
+ if (!loadResourceFileData(fileElem, &fileData, errorMessage))
+ return false;
+ data.resourceFileList.append(fileData);
+ fileElem = fileElem.nextSiblingElement();
+ }
+ return true;
+}
+
+static bool loadQrcFileData(const QDomDocument &doc, const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage)
+{
+ if (!qrcFileData)
+ return false;
+
+ QtQrcFileData &data = *qrcFileData;
+
+ QDomElement docElem = doc.documentElement();
+ if (docElem.tagName() != QLatin1String(rccRootTag)) {
+ *errorMessage = msgTagMismatch(docElem.tagName(), QLatin1String(rccRootTag));
+ return false;
+ }
+
+ QDomElement prefixElem = docElem.firstChildElement();
+ while (!prefixElem.isNull()) {
+ QtResourcePrefixData prefixData;
+ if (!loadResourcePrefixData(prefixElem, &prefixData, errorMessage))
+ return false;
+ data.resourceList.append(prefixData);
+ prefixElem = prefixElem.nextSiblingElement();
+ }
+
+ data.qrcPath = path;
+
+ return true;
+}
+
+QDomElement saveResourceFileData(QDomDocument &doc, const QtResourceFileData &fileData)
+{
+ QDomElement fileElem = doc.createElement(QLatin1String(rccFileTag));
+ if (!fileData.alias.isEmpty())
+ fileElem.setAttribute(QLatin1String(rccAliasAttribute), fileData.alias);
+
+ QDomText textElem = doc.createTextNode(fileData.path);
+ fileElem.appendChild(textElem);
+
+ return fileElem;
+}
+
+QDomElement saveResourcePrefixData(QDomDocument &doc, const QtResourcePrefixData &prefixData)
+{
+ QDomElement prefixElem = doc.createElement(QLatin1String(rccTag));
+ if (!prefixData.prefix.isEmpty())
+ prefixElem.setAttribute(QLatin1String(rccPrefixAttribute), prefixData.prefix);
+ if (!prefixData.language.isEmpty())
+ prefixElem.setAttribute(QLatin1String(rccLangAttribute), prefixData.language);
+
+ QListIterator<QtResourceFileData> itFile(prefixData.resourceFileList);
+ while (itFile.hasNext()) {
+ QDomElement fileElem = saveResourceFileData(doc, itFile.next());
+ prefixElem.appendChild(fileElem);
+ }
+
+ return prefixElem;
+}
+
+QDomDocument saveQrcFileData(const QtQrcFileData &qrcFileData)
+{
+ QDomDocument doc;
+ QDomElement docElem = doc.createElement(QLatin1String(rccRootTag));
+ QListIterator<QtResourcePrefixData> itPrefix(qrcFileData.resourceList);
+ while (itPrefix.hasNext()) {
+ QDomElement prefixElem = saveResourcePrefixData(doc, itPrefix.next());
+
+ docElem.appendChild(prefixElem);
+ }
+ doc.appendChild(docElem);
+
+ return doc;
+}
+// --------------- QtResourceFile
+class QtResourceFile {
+public:
+ friend class QtQrcManager;
+
+ QString path() const { return m_path; }
+ QString alias() const { return m_alias; }
+ QString fullPath() const { return m_fullPath; }
+private:
+ QtResourceFile() {}
+
+ QString m_path;
+ QString m_alias;
+ QString m_fullPath;
+};
+
+class QtResourcePrefix {
+public:
+ friend class QtQrcManager;
+
+ QString prefix() const { return m_prefix; }
+ QString language() const { return m_language; }
+ QList<QtResourceFile *> resourceFiles() const { return m_resourceFiles; }
+private:
+ QtResourcePrefix() {}
+
+ QString m_prefix;
+ QString m_language;
+ QList<QtResourceFile *> m_resourceFiles;
+
+};
+// ------------------- QtQrcFile
+class QtQrcFile {
+public:
+ friend class QtQrcManager;
+
+ QString path() const { return m_path; }
+ QString fileName() const { return m_fileName; }
+ QList<QtResourcePrefix *> resourcePrefixList() const { return m_resourcePrefixes; }
+ QtQrcFileData initialState() const { return m_initialState; }
+
+private:
+ QtQrcFile() { }
+
+ void setPath(const QString &path) {
+ m_path = path;
+ QFileInfo fi(path);
+ m_fileName = fi.fileName();
+ }
+
+ QString m_path;
+ QString m_fileName;
+ QList<QtResourcePrefix *> m_resourcePrefixes;
+ QtQrcFileData m_initialState;
+};
+
+// ------------------ QtQrcManager
+class QtQrcManager : public QObject
+{
+ Q_OBJECT
+public:
+ QtQrcManager(QObject *parent = 0);
+ ~QtQrcManager();
+
+ QList<QtQrcFile *> qrcFiles() const;
+
+ // helpers
+ QtQrcFile *qrcFileOf(const QString &path) const;
+ QtQrcFile *qrcFileOf(QtResourcePrefix *resourcePrefix) const;
+ QtQrcFile *qrcFileOf(QtResourceFile *resourceFile) const;
+ QtResourcePrefix *resourcePrefixOf(QtResourceFile *resourceFile) const;
+
+ QtQrcFile *importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile = 0);
+ void exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const;
+
+ QList<QtResourceFile *> resourceFilesOf(const QString &resourceFullPath) const;
+ QIcon icon(const QString &resourceFullPath) const;
+ bool exists(const QString &resourceFullPath) const;
+ bool exists(QtQrcFile *qrcFile) const;
+
+ QtQrcFile *prevQrcFile(QtQrcFile *qrcFile) const;
+ QtQrcFile *nextQrcFile(QtQrcFile *qrcFile) const;
+ QtResourcePrefix *prevResourcePrefix(QtResourcePrefix *resourcePrefix) const;
+ QtResourcePrefix *nextResourcePrefix(QtResourcePrefix *resourcePrefix) const;
+ QtResourceFile *prevResourceFile(QtResourceFile *resourceFile) const;
+ QtResourceFile *nextResourceFile(QtResourceFile *resourceFile) const;
+
+ void clear();
+
+public slots:
+
+ QtQrcFile *insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile = 0, bool newFile = false);
+ void moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile);
+ void setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState);
+ void removeQrcFile(QtQrcFile *qrcFile);
+
+ QtResourcePrefix *insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix,
+ const QString &language, QtResourcePrefix *beforeResourcePrefix = 0);
+ void moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix); // the same qrc file???
+ void changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix);
+ void changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage);
+ void removeResourcePrefix(QtResourcePrefix *resourcePrefix);
+
+ QtResourceFile *insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path,
+ const QString &alias, QtResourceFile *beforeResourceFile = 0);
+ void moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile); // the same prefix???
+ void changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias);
+ void removeResourceFile(QtResourceFile *resourceFile);
+
+signals:
+ void qrcFileInserted(QtQrcFile *qrcFile);
+ void qrcFileMoved(QtQrcFile *qrcFile, QtQrcFile *oldBeforeQrcFile);
+ void qrcFileRemoved(QtQrcFile *qrcFile);
+
+ void resourcePrefixInserted(QtResourcePrefix *resourcePrefix);
+ void resourcePrefixMoved(QtResourcePrefix *resourcePrefix, QtResourcePrefix *oldBeforeResourcePrefix);
+ void resourcePrefixChanged(QtResourcePrefix *resourcePrefix, const QString &oldPrefix);
+ void resourceLanguageChanged(QtResourcePrefix *resourcePrefix, const QString &oldLanguage);
+ void resourcePrefixRemoved(QtResourcePrefix *resourcePrefix);
+
+ void resourceFileInserted(QtResourceFile *resourceFile);
+ void resourceFileMoved(QtResourceFile *resourceFile, QtResourceFile *oldBeforeResourceFile);
+ void resourceAliasChanged(QtResourceFile *resourceFile, const QString &oldAlias);
+ void resourceFileRemoved(QtResourceFile *resourceFile);
+private:
+
+ QList<QtQrcFile *> m_qrcFiles;
+ QMap<QString, QtQrcFile *> m_pathToQrc;
+ QMap<QtQrcFile *, bool> m_qrcFileToExists;
+ QMap<QtResourcePrefix *, QtQrcFile *> m_prefixToQrc;
+ QMap<QtResourceFile *, QtResourcePrefix *> m_fileToPrefix;
+ QMap<QString, QList<QtResourceFile *> > m_fullPathToResourceFiles;
+ QMap<QString, QIcon> m_fullPathToIcon;
+ QMap<QString, bool> m_fullPathToExists;
+};
+
+QtQrcManager::QtQrcManager(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+QtQrcManager::~QtQrcManager()
+{
+ clear();
+}
+
+QList<QtQrcFile *> QtQrcManager::qrcFiles() const
+{
+ return m_qrcFiles;
+}
+
+QtQrcFile *QtQrcManager::qrcFileOf(const QString &path) const
+{
+ return m_pathToQrc.value(path);
+}
+
+QtQrcFile *QtQrcManager::qrcFileOf(QtResourcePrefix *resourcePrefix) const
+{
+ return m_prefixToQrc.value(resourcePrefix);
+}
+
+QtQrcFile *QtQrcManager::qrcFileOf(QtResourceFile *resourceFile) const
+{
+ return qrcFileOf(resourcePrefixOf(resourceFile));
+}
+
+QtResourcePrefix *QtQrcManager::resourcePrefixOf(QtResourceFile *resourceFile) const
+{
+ return m_fileToPrefix.value(resourceFile);
+}
+
+QtQrcFile *QtQrcManager::importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile)
+{
+ QtQrcFile *qrcFile = insertQrcFile(qrcFileData.qrcPath, beforeQrcFile);
+ if (!qrcFile)
+ return 0;
+ QListIterator<QtResourcePrefixData> itPrefix(qrcFileData.resourceList);
+ while (itPrefix.hasNext()) {
+ const QtResourcePrefixData &prefixData = itPrefix.next();
+ QtResourcePrefix *resourcePrefix = insertResourcePrefix(qrcFile, prefixData.prefix, prefixData.language, 0);
+ QListIterator<QtResourceFileData> itFile(prefixData.resourceFileList);
+ while (itFile.hasNext()) {
+ const QtResourceFileData &fileData = itFile.next();
+ insertResourceFile(resourcePrefix, fileData.path, fileData.alias, 0);
+ }
+ }
+ setInitialState(qrcFile, qrcFileData);
+ return qrcFile;
+}
+
+void QtQrcManager::exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const
+{
+ if (!qrcFileData)
+ return;
+
+ if (!qrcFile)
+ return;
+
+ QtQrcFileData &data = *qrcFileData;
+
+ QList<QtResourcePrefixData> resourceList;
+
+ QList<QtResourcePrefix *> resourcePrefixes = qrcFile->resourcePrefixList();
+ QListIterator<QtResourcePrefix *> itPrefix(resourcePrefixes);
+ while (itPrefix.hasNext()) {
+ QList<QtResourceFileData> resourceFileList;
+
+ QtResourcePrefix *prefix = itPrefix.next();
+
+ QList<QtResourceFile *> resourceFiles = prefix->resourceFiles();
+ QListIterator<QtResourceFile *> itFile(resourceFiles);
+ while (itFile.hasNext()) {
+ QtResourceFile *file = itFile.next();
+ QtResourceFileData fileData;
+ fileData.path = file->path();
+ fileData.alias = file->alias();
+ resourceFileList << fileData;
+ }
+ QtResourcePrefixData prefixData;
+ prefixData.prefix = prefix->prefix();
+ prefixData.language = prefix->language();
+ prefixData.resourceFileList = resourceFileList;
+
+ resourceList << prefixData;
+ }
+ data = QtQrcFileData();
+ data.qrcPath = qrcFile->path();
+ data.resourceList = resourceList;
+}
+
+QList<QtResourceFile *> QtQrcManager::resourceFilesOf(const QString &resourcePath) const
+{
+ return m_fullPathToResourceFiles.value(resourcePath);
+}
+
+QIcon QtQrcManager::icon(const QString &resourceFullPath) const
+{
+ return m_fullPathToIcon.value(resourceFullPath);
+}
+
+bool QtQrcManager::exists(const QString &resourceFullPath) const
+{
+ return m_fullPathToExists.value(resourceFullPath, false);
+}
+
+bool QtQrcManager::exists(QtQrcFile *qrcFile) const
+{
+ return m_qrcFileToExists.value(qrcFile, false);
+}
+
+QtQrcFile *QtQrcManager::prevQrcFile(QtQrcFile *qrcFile) const
+{
+ if (!qrcFile)
+ return 0;
+ const int idx = m_qrcFiles.indexOf(qrcFile);
+ if (idx <= 0)
+ return 0;
+ return m_qrcFiles.at(idx - 1);
+}
+
+QtQrcFile *QtQrcManager::nextQrcFile(QtQrcFile *qrcFile) const
+{
+ if (!qrcFile)
+ return 0;
+ const int idx = m_qrcFiles.indexOf(qrcFile);
+ if (idx < 0 || idx == m_qrcFiles.size() - 1)
+ return 0;
+ return m_qrcFiles.at(idx + 1);
+}
+
+QtResourcePrefix *QtQrcManager::prevResourcePrefix(QtResourcePrefix *resourcePrefix) const
+{
+ if (!resourcePrefix)
+ return 0;
+ QList<QtResourcePrefix *> prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList();
+ const int idx = prefixes.indexOf(resourcePrefix);
+ if (idx <= 0)
+ return 0;
+ return prefixes.at(idx - 1);
+}
+
+QtResourcePrefix *QtQrcManager::nextResourcePrefix(QtResourcePrefix *resourcePrefix) const
+{
+ if (!resourcePrefix)
+ return 0;
+ QList<QtResourcePrefix *> prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList();
+ const int idx = prefixes.indexOf(resourcePrefix);
+ if (idx < 0 || idx == prefixes.size() - 1)
+ return 0;
+ return prefixes.at(idx + 1);
+}
+
+QtResourceFile *QtQrcManager::prevResourceFile(QtResourceFile *resourceFile) const
+{
+ if (!resourceFile)
+ return 0;
+ QList<QtResourceFile *> files = resourcePrefixOf(resourceFile)->resourceFiles();
+ const int idx = files.indexOf(resourceFile);
+ if (idx <= 0)
+ return 0;
+ return files.at(idx - 1);
+}
+
+QtResourceFile *QtQrcManager::nextResourceFile(QtResourceFile *resourceFile) const
+{
+ if (!resourceFile)
+ return 0;
+ QList<QtResourceFile *> files = resourcePrefixOf(resourceFile)->resourceFiles();
+ const int idx = files.indexOf(resourceFile);
+ if (idx < 0 || idx == files.size() - 1)
+ return 0;
+ return files.at(idx + 1);
+}
+
+void QtQrcManager::clear()
+{
+ QList<QtQrcFile *> oldQrcFiles = qrcFiles();
+ QListIterator<QtQrcFile *> it(oldQrcFiles);
+ while (it.hasNext())
+ removeQrcFile(it.next());
+}
+
+QtQrcFile *QtQrcManager::insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile, bool newFile)
+{
+ if (m_pathToQrc.contains(path))
+ return 0;
+
+ int idx = m_qrcFiles.indexOf(beforeQrcFile);
+ if (idx < 0)
+ idx = m_qrcFiles.size();
+
+ QtQrcFile *qrcFile = new QtQrcFile();
+ qrcFile->setPath(path);
+
+ m_qrcFiles.insert(idx, qrcFile);
+ m_pathToQrc[path] = qrcFile;
+
+ const QFileInfo fi(path);
+ m_qrcFileToExists[qrcFile] = fi.exists() || newFile;
+
+ emit qrcFileInserted(qrcFile);
+ return qrcFile;
+}
+
+void QtQrcManager::moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile)
+{
+ if (qrcFile == beforeQrcFile)
+ return;
+
+ const int idx = m_qrcFiles.indexOf(qrcFile);
+ if (idx < 0)
+ return;
+
+ int beforeIdx = m_qrcFiles.indexOf(beforeQrcFile);
+ if (beforeIdx < 0)
+ beforeIdx = m_qrcFiles.size();
+
+ if (idx == beforeIdx - 1) // the same position, nothing changes
+ return;
+
+ QtQrcFile *oldBefore = 0;
+ if (idx < m_qrcFiles.size() - 1)
+ oldBefore = m_qrcFiles.at(idx + 1);
+
+ m_qrcFiles.removeAt(idx);
+ if (idx < beforeIdx)
+ beforeIdx -= 1;
+
+ m_qrcFiles.insert(beforeIdx, qrcFile);
+
+ emit qrcFileMoved(qrcFile, oldBefore);
+}
+
+void QtQrcManager::setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState)
+{
+ qrcFile->m_initialState = initialState;
+}
+
+void QtQrcManager::removeQrcFile(QtQrcFile *qrcFile)
+{
+ const int idx = m_qrcFiles.indexOf(qrcFile);
+ if (idx < 0)
+ return;
+
+ QList<QtResourcePrefix *> resourcePrefixes = qrcFile->resourcePrefixList();
+ QListIterator<QtResourcePrefix *> it(resourcePrefixes);
+ while (it.hasNext())
+ removeResourcePrefix(it.next());
+
+ emit qrcFileRemoved(qrcFile);
+
+ m_qrcFiles.removeAt(idx);
+ m_pathToQrc.remove(qrcFile->path());
+ m_qrcFileToExists.remove(qrcFile);
+ delete qrcFile;
+}
+
+QtResourcePrefix *QtQrcManager::insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix,
+ const QString &language, QtResourcePrefix *beforeResourcePrefix)
+{
+ if (!qrcFile)
+ return 0;
+
+ int idx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix);
+ if (idx < 0)
+ idx = qrcFile->m_resourcePrefixes.size();
+
+ QtResourcePrefix *resourcePrefix = new QtResourcePrefix();
+ resourcePrefix->m_prefix = prefix;
+ resourcePrefix->m_language = language;
+
+ qrcFile->m_resourcePrefixes.insert(idx, resourcePrefix);
+ m_prefixToQrc[resourcePrefix] = qrcFile;
+
+ emit resourcePrefixInserted(resourcePrefix);
+ return resourcePrefix;
+}
+
+void QtQrcManager::moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix)
+{
+ if (resourcePrefix == beforeResourcePrefix)
+ return;
+
+ QtQrcFile *qrcFile = qrcFileOf(resourcePrefix);
+ if (!qrcFile)
+ return;
+
+ if (beforeResourcePrefix && qrcFileOf(beforeResourcePrefix) != qrcFile)
+ return;
+
+ const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix);
+
+ int beforeIdx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix);
+ if (beforeIdx < 0)
+ beforeIdx = qrcFile->m_resourcePrefixes.size();
+
+ if (idx == beforeIdx - 1) // the same position, nothing changes
+ return;
+
+ QtResourcePrefix *oldBefore = 0;
+ if (idx < qrcFile->m_resourcePrefixes.size() - 1)
+ oldBefore = qrcFile->m_resourcePrefixes.at(idx + 1);
+
+ qrcFile->m_resourcePrefixes.removeAt(idx);
+ if (idx < beforeIdx)
+ beforeIdx -= 1;
+
+ qrcFile->m_resourcePrefixes.insert(beforeIdx, resourcePrefix);
+
+ emit resourcePrefixMoved(resourcePrefix, oldBefore);
+}
+
+void QtQrcManager::changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix)
+{
+ if (!resourcePrefix)
+ return;
+
+ const QString oldPrefix = resourcePrefix->m_prefix;
+ if (oldPrefix == newPrefix)
+ return;
+
+ resourcePrefix->m_prefix = newPrefix;
+
+ emit resourcePrefixChanged(resourcePrefix, oldPrefix);
+}
+
+void QtQrcManager::changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage)
+{
+ if (!resourcePrefix)
+ return;
+
+ const QString oldLanguage = resourcePrefix->m_language;
+ if (oldLanguage == newLanguage)
+ return;
+
+ resourcePrefix->m_language = newLanguage;
+
+ emit resourceLanguageChanged(resourcePrefix, oldLanguage);
+}
+
+void QtQrcManager::removeResourcePrefix(QtResourcePrefix *resourcePrefix)
+{
+ QtQrcFile *qrcFile = qrcFileOf(resourcePrefix);
+ if (!qrcFile)
+ return;
+
+ const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix);
+
+ QList<QtResourceFile *> resourceFiles = resourcePrefix->resourceFiles();
+ QListIterator<QtResourceFile *> it(resourceFiles);
+ while (it.hasNext())
+ removeResourceFile(it.next());
+
+ emit resourcePrefixRemoved(resourcePrefix);
+
+ qrcFile->m_resourcePrefixes.removeAt(idx);
+ m_prefixToQrc.remove(resourcePrefix);
+ delete resourcePrefix;
+}
+
+QtResourceFile *QtQrcManager::insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path,
+ const QString &alias, QtResourceFile *beforeResourceFile)
+{
+ if (!resourcePrefix)
+ return 0;
+
+ int idx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile);
+ if (idx < 0)
+ idx = resourcePrefix->m_resourceFiles.size();
+
+ QtResourceFile *resourceFile = new QtResourceFile();
+ resourceFile->m_path = path;
+ resourceFile->m_alias = alias;
+ const QFileInfo fi(qrcFileOf(resourcePrefix)->path());
+ const QDir dir(fi.absolutePath());
+ const QString fullPath = dir.absoluteFilePath(path);
+ resourceFile->m_fullPath = fullPath;
+
+ resourcePrefix->m_resourceFiles.insert(idx, resourceFile);
+ m_fileToPrefix[resourceFile] = resourcePrefix;
+ m_fullPathToResourceFiles[fullPath].append(resourceFile);
+ if (!m_fullPathToIcon.contains(fullPath)) {
+ m_fullPathToIcon[fullPath] = QIcon(fullPath);
+ const QFileInfo fullInfo(fullPath);
+ m_fullPathToExists[fullPath] = fullInfo.exists();
+ }
+
+ emit resourceFileInserted(resourceFile);
+ return resourceFile;
+}
+
+void QtQrcManager::moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile)
+{
+ if (resourceFile == beforeResourceFile)
+ return;
+
+ QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile);
+ if (!resourcePrefix)
+ return;
+
+ if (beforeResourceFile && resourcePrefixOf(beforeResourceFile) != resourcePrefix)
+ return;
+
+ const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile);
+
+ int beforeIdx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile);
+ if (beforeIdx < 0)
+ beforeIdx = resourcePrefix->m_resourceFiles.size();
+
+ if (idx == beforeIdx - 1) // the same position, nothing changes
+ return;
+
+ QtResourceFile *oldBefore = 0;
+ if (idx < resourcePrefix->m_resourceFiles.size() - 1)
+ oldBefore = resourcePrefix->m_resourceFiles.at(idx + 1);
+
+ resourcePrefix->m_resourceFiles.removeAt(idx);
+ if (idx < beforeIdx)
+ beforeIdx -= 1;
+
+ resourcePrefix->m_resourceFiles.insert(beforeIdx, resourceFile);
+
+ emit resourceFileMoved(resourceFile, oldBefore);
+}
+
+void QtQrcManager::changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias)
+{
+ if (!resourceFile)
+ return;
+
+ const QString oldAlias = resourceFile->m_alias;
+ if (oldAlias == newAlias)
+ return;
+
+ resourceFile->m_alias = newAlias;
+
+ emit resourceAliasChanged(resourceFile, oldAlias);
+}
+
+void QtQrcManager::removeResourceFile(QtResourceFile *resourceFile)
+{
+ QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile);
+ if (!resourcePrefix)
+ return;
+
+ const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile);
+
+ emit resourceFileRemoved(resourceFile);
+
+ resourcePrefix->m_resourceFiles.removeAt(idx);
+ m_fileToPrefix.remove(resourceFile);
+ const QString fullPath = resourceFile->fullPath();
+ m_fullPathToResourceFiles[fullPath].removeAll(resourceFile); // optimize me
+ if (m_fullPathToResourceFiles[fullPath].isEmpty()) {
+ m_fullPathToResourceFiles.remove(fullPath);
+ m_fullPathToIcon.remove(fullPath);
+ m_fullPathToExists.remove(fullPath);
+ }
+ delete resourceFile;
+}
+
+
+
+}
+
+// ----------------- QtResourceEditorDialogPrivate
+class QtResourceEditorDialogPrivate
+{
+ QtResourceEditorDialog *q_ptr;
+ Q_DECLARE_PUBLIC(QtResourceEditorDialog)
+public:
+ QtResourceEditorDialogPrivate();
+
+ void slotQrcFileInserted(QtQrcFile *qrcFile);
+ void slotQrcFileMoved(QtQrcFile *qrcFile);
+ void slotQrcFileRemoved(QtQrcFile *qrcFile);
+
+ QStandardItem *insertResourcePrefix(QtResourcePrefix *resourcePrefix);
+
+ void slotResourcePrefixInserted(QtResourcePrefix *resourcePrefix) { insertResourcePrefix(resourcePrefix); }
+ void slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix);
+ void slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix);
+ void slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix);
+ void slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix);
+ void slotResourceFileInserted(QtResourceFile *resourceFile);
+ void slotResourceFileMoved(QtResourceFile *resourceFile);
+ void slotResourceAliasChanged(QtResourceFile *resourceFile);
+ void slotResourceFileRemoved(QtResourceFile *resourceFile);
+
+ void slotCurrentQrcFileChanged(QListWidgetItem *item);
+ void slotCurrentTreeViewItemChanged(const QModelIndex &index);
+ void slotListWidgetContextMenuRequested(const QPoint &pos);
+ void slotTreeViewContextMenuRequested(const QPoint &pos);
+ void slotTreeViewItemChanged(QStandardItem *item);
+
+ void slotNewQrcFile();
+ void slotImportQrcFile();
+ void slotRemoveQrcFile();
+ void slotMoveUpQrcFile();
+ void slotMoveDownQrcFile();
+
+ void slotNewPrefix();
+ void slotAddFiles();
+ void slotChangePrefix();
+ void slotChangeLanguage();
+ void slotChangeAlias();
+ void slotClonePrefix();
+ void slotRemove();
+ void slotMoveUp();
+ void slotMoveDown();
+
+ bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage);
+ bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData);
+ bool saveQrcFile(const QtQrcFileData &qrcFileData);
+
+ QString qrcFileText(QtQrcFile *qrcFile) const;
+
+ QMessageBox::StandardButton warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
+ QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) const;
+
+ QString browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const;
+ QString copyResourceFile(const QString &resourceFile, const QString &destPath) const;
+ QtResourceFile *getCurrentResourceFile() const;
+ QtResourcePrefix *getCurrentResourcePrefix() const;
+ void selectTreeRow(QStandardItem *item);
+ QString getSaveFileNameWithExtension(QWidget *parent,
+ const QString &title, QString dir, const QString &filter, const QString &extension) const;
+ QString qrcStartDirectory() const;
+
+ Ui::QtResourceEditorDialog m_ui;
+ QDesignerFormEditorInterface *m_core;
+ QtResourceModel *m_resourceModel;
+ QDesignerDialogGuiInterface *m_dlgGui;
+ QtQrcManager *m_qrcManager;
+ QList<QtQrcFileData> m_initialState;
+
+ QMap<QtQrcFile *, QListWidgetItem *> m_qrcFileToItem;
+ QMap<QListWidgetItem *, QtQrcFile *> m_itemToQrcFile;
+ QMap<QtResourcePrefix *, QStandardItem *> m_resourcePrefixToPrefixItem;
+ QMap<QtResourcePrefix *, QStandardItem *> m_resourcePrefixToLanguageItem;
+ QMap<QStandardItem *, QtResourcePrefix *> m_prefixItemToResourcePrefix;
+ QMap<QStandardItem *, QtResourcePrefix *> m_languageItemToResourcePrefix;
+ QMap<QtResourceFile *, QStandardItem *> m_resourceFileToPathItem;
+ QMap<QtResourceFile *, QStandardItem *> m_resourceFileToAliasItem;
+ QMap<QStandardItem *, QtResourceFile *> m_pathItemToResourceFile;
+ QMap<QStandardItem *, QtResourceFile *> m_aliasItemToResourceFile;
+
+ bool m_ignoreCurrentChanged;
+ bool m_firstQrcFileDialog;
+ QtQrcFile *m_currentQrcFile;
+
+ QAction *m_newQrcFileAction;
+ QAction *m_importQrcFileAction;
+ QAction *m_removeQrcFileAction;
+ QAction *m_moveUpQrcFileAction;
+ QAction *m_moveDownQrcFileAction;
+
+ QAction *m_newPrefixAction;
+ QAction *m_addResourceFileAction;
+ QAction *m_changePrefixAction;
+ QAction *m_changeLanguageAction;
+ QAction *m_changeAliasAction;
+ QAction *m_clonePrefixAction;
+ QAction *m_moveUpAction;
+ QAction *m_moveDownAction;
+ QAction *m_removeAction;
+
+ QStandardItemModel *m_treeModel;
+ QItemSelectionModel *m_treeSelection;
+};
+
+QtResourceEditorDialogPrivate::QtResourceEditorDialogPrivate() :
+ q_ptr(0),
+ m_core(0),
+ m_resourceModel(0),
+ m_dlgGui(0),
+ m_qrcManager(0),
+ m_ignoreCurrentChanged(false),
+ m_firstQrcFileDialog(true),
+ m_currentQrcFile(0),
+ m_newQrcFileAction(0),
+ m_importQrcFileAction(0),
+ m_removeQrcFileAction(0),
+ m_moveUpQrcFileAction(0),
+ m_moveDownQrcFileAction(0),
+ m_newPrefixAction(0),
+ m_addResourceFileAction(0),
+ m_changePrefixAction(0),
+ m_changeLanguageAction(0),
+ m_changeAliasAction(0),
+ m_clonePrefixAction(0),
+ m_moveUpAction(0),
+ m_moveDownAction(0),
+ m_removeAction(0),
+ m_treeModel(0),
+ m_treeSelection(0)
+{
+}
+
+QMessageBox::StandardButton QtResourceEditorDialogPrivate::warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton) const
+{
+ return m_dlgGui->message(q_ptr, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, title, text, buttons, defaultButton);
+}
+
+QString QtResourceEditorDialogPrivate::qrcFileText(QtQrcFile *qrcFile) const
+{
+ const QString path = qrcFile->path();
+ const QString fileName = qrcFile->fileName();
+ const QFileInfo fi(path);
+ if (fi.exists() && !fi.isWritable())
+ return QApplication::translate("QtResourceEditorDialog", "%1 [read-only]").arg(fileName);
+ if (!m_qrcManager->exists(qrcFile))
+ return QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(fileName);
+ return fileName;
+}
+
+void QtResourceEditorDialogPrivate::slotQrcFileInserted(QtQrcFile *qrcFile)
+{
+ QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem();
+ int idx = m_ui.qrcFileList->count();
+ QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile);
+ QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile);
+ if (nextItem) {
+ const int row = m_ui.qrcFileList->row(nextItem);
+ if (row >= 0)
+ idx = row;
+ }
+ const QString path = qrcFile->path();
+ QListWidgetItem *item = new QListWidgetItem(qrcFileText(qrcFile));
+ item->setToolTip(path);
+ m_ignoreCurrentChanged = true;
+ m_ui.qrcFileList->insertItem(idx, item);
+ m_ui.qrcFileList->setCurrentItem(currentItem);
+ m_ignoreCurrentChanged = false;
+ m_qrcFileToItem[qrcFile] = item;
+ m_itemToQrcFile[item] = qrcFile;
+ if (!m_qrcManager->exists(qrcFile))
+ item->setForeground(QBrush(Qt::red));
+}
+
+void QtResourceEditorDialogPrivate::slotQrcFileMoved(QtQrcFile *qrcFile)
+{
+ QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem();
+ QListWidgetItem *item = m_qrcFileToItem.value(qrcFile);
+ m_ignoreCurrentChanged = true;
+ m_ui.qrcFileList->takeItem(m_ui.qrcFileList->row(item));
+
+ int idx = m_ui.qrcFileList->count();
+ QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile);
+ QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile);
+ if (nextItem) {
+ int row = m_ui.qrcFileList->row(nextItem);
+ if (row >= 0)
+ idx = row;
+ }
+ m_ui.qrcFileList->insertItem(idx, item);
+ if (currentItem == item)
+ m_ui.qrcFileList->setCurrentItem(item);
+ m_ignoreCurrentChanged = false;
+}
+
+void QtResourceEditorDialogPrivate::slotQrcFileRemoved(QtQrcFile *qrcFile)
+{
+ QListWidgetItem *item = m_qrcFileToItem.value(qrcFile);
+ if (item == m_ui.qrcFileList->currentItem())
+ m_ui.qrcFileList->setCurrentItem(0); // this should trigger list view signal currentItemChanged(0), and slot should set m_currentQrcFile to 0
+ m_ignoreCurrentChanged = true;
+ delete item;
+ m_ignoreCurrentChanged = false;
+ m_itemToQrcFile.remove(item);
+ m_qrcFileToItem.remove(qrcFile);
+}
+
+QStandardItem *QtResourceEditorDialogPrivate::insertResourcePrefix(QtResourcePrefix *resourcePrefix)
+{
+ if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile)
+ return 0;
+
+ QtResourcePrefix *prevResourcePrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
+ QStandardItem *prevItem = m_resourcePrefixToPrefixItem.value(prevResourcePrefix);
+
+ int row = 0;
+ if (prevItem)
+ row = m_treeModel->indexFromItem(prevItem).row() + 1;
+
+ QStandardItem *prefixItem = new QStandardItem();
+ QStandardItem *languageItem = new QStandardItem();
+ QList<QStandardItem *> items;
+ items << prefixItem;
+ items << languageItem;
+ m_treeModel->insertRow(row, items);
+ const QModelIndex newIndex = m_treeModel->indexFromItem(prefixItem);
+ m_ui.resourceTreeView->setExpanded(newIndex, true);
+ prefixItem->setFlags(prefixItem->flags() | Qt::ItemIsEditable);
+ languageItem->setFlags(languageItem->flags() | Qt::ItemIsEditable);
+ m_resourcePrefixToPrefixItem[resourcePrefix] = prefixItem;
+ m_resourcePrefixToLanguageItem[resourcePrefix] = languageItem;
+ m_prefixItemToResourcePrefix[prefixItem] = resourcePrefix;
+ m_languageItemToResourcePrefix[languageItem] = resourcePrefix;
+ slotResourcePrefixChanged(resourcePrefix);
+ slotResourceLanguageChanged(resourcePrefix);
+ return prefixItem;
+}
+
+void QtResourceEditorDialogPrivate::slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix)
+{
+ QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
+ if (!prefixItem)
+ return;
+
+ QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix);
+ if (!languageItem)
+ return;
+
+ const QModelIndex index = m_treeModel->indexFromItem(prefixItem);
+ const bool expanded = m_ui.resourceTreeView->isExpanded(index);
+ m_ignoreCurrentChanged = true;
+ const QList<QStandardItem *> items = m_treeModel->takeRow(index.row());
+
+ int row = m_treeModel->rowCount();
+ QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
+ QStandardItem *nextItem = m_resourcePrefixToPrefixItem.value(nextResourcePrefix);
+ if (nextItem)
+ row = m_treeModel->indexFromItem(nextItem).row();
+ m_treeModel->insertRow(row, items);
+ m_ignoreCurrentChanged = false;
+ m_ui.resourceTreeView->setExpanded(m_treeModel->indexFromItem(items.at(0)), expanded);
+}
+
+void QtResourceEditorDialogPrivate::slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix)
+{
+ QStandardItem *item = m_resourcePrefixToPrefixItem.value(resourcePrefix);
+ if (!item)
+ return;
+
+ m_ignoreCurrentChanged = true;
+ QString prefix = resourcePrefix->prefix();
+ if (prefix.isEmpty())
+ prefix = QApplication::translate("QtResourceEditorDialog", "<no prefix>", 0, QApplication::UnicodeUTF8);
+ item->setText(prefix);
+ item->setToolTip(prefix);
+ m_ignoreCurrentChanged = false;
+}
+
+void QtResourceEditorDialogPrivate::slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix)
+{
+ QStandardItem *item = m_resourcePrefixToLanguageItem.value(resourcePrefix);
+ if (!item)
+ return;
+
+ m_ignoreCurrentChanged = true;
+ const QString language = resourcePrefix->language();
+ item->setText(language);
+ item->setToolTip(language);
+
+ m_ignoreCurrentChanged = false;
+}
+
+void QtResourceEditorDialogPrivate::slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix)
+{
+ QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
+ if (!prefixItem)
+ return;
+
+ QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix);
+ if (!languageItem)
+ return;
+
+ m_ignoreCurrentChanged = true;
+ m_treeModel->takeRow(m_treeModel->indexFromItem(prefixItem).row());
+ delete prefixItem;
+ delete languageItem;
+ m_ignoreCurrentChanged = false;
+ m_prefixItemToResourcePrefix.remove(prefixItem);
+ m_languageItemToResourcePrefix.remove(languageItem);
+ m_resourcePrefixToPrefixItem.remove(resourcePrefix);
+ m_resourcePrefixToLanguageItem.remove(resourcePrefix);
+}
+
+void QtResourceEditorDialogPrivate::slotResourceFileInserted(QtResourceFile *resourceFile)
+{
+ QtResourcePrefix *resourcePrefix = m_qrcManager->resourcePrefixOf(resourceFile);
+ if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile)
+ return;
+
+ QtResourceFile *prevResourceFile = m_qrcManager->prevResourceFile(resourceFile);
+ QStandardItem *prevItem = m_resourceFileToPathItem.value(prevResourceFile);
+
+ QStandardItem *pathItem = new QStandardItem(resourceFile->path());
+ QStandardItem *aliasItem = new QStandardItem();
+ QStandardItem *parentItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
+ QList<QStandardItem *> items;
+ items << pathItem;
+ items << aliasItem;
+
+ int row = 0;
+ if (prevItem)
+ row = m_treeModel->indexFromItem(prevItem).row() + 1;
+
+ parentItem->insertRow(row, items);
+
+ pathItem->setFlags(pathItem->flags() & ~Qt::ItemIsEditable);
+ aliasItem->setFlags(aliasItem->flags() | Qt::ItemIsEditable);
+ m_resourceFileToPathItem[resourceFile] = pathItem;
+ m_resourceFileToAliasItem[resourceFile] = aliasItem;
+ m_pathItemToResourceFile[pathItem] = resourceFile;
+ m_aliasItemToResourceFile[aliasItem] = resourceFile;
+ pathItem->setToolTip(resourceFile->path());
+ pathItem->setIcon(m_qrcManager->icon(resourceFile->fullPath()));
+ if (!m_qrcManager->exists(resourceFile->fullPath())) {
+ pathItem->setText(QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(resourceFile->path()));
+ QBrush redBrush(Qt::red);
+ pathItem->setForeground(redBrush);
+ aliasItem->setForeground(redBrush);
+ }
+ slotResourceAliasChanged(resourceFile);
+}
+
+void QtResourceEditorDialogPrivate::slotResourceFileMoved(QtResourceFile *resourceFile)
+{
+ QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile);
+ if (!pathItem)
+ return;
+
+ QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile);
+ if (!aliasItem)
+ return;
+
+ QStandardItem *parentItem = pathItem->parent();
+ m_ignoreCurrentChanged = true;
+ const QList<QStandardItem *> items = parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row());
+
+ int row = parentItem->rowCount();
+ QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(resourceFile);
+ QStandardItem *nextItem = m_resourceFileToPathItem.value(nextResourceFile);
+ if (nextItem)
+ row = m_treeModel->indexFromItem(nextItem).row();
+ parentItem->insertRow(row, items);
+ m_ignoreCurrentChanged = false;
+}
+
+void QtResourceEditorDialogPrivate::slotResourceAliasChanged(QtResourceFile *resourceFile)
+{
+ QStandardItem *item = m_resourceFileToAliasItem.value(resourceFile);
+ if (!item)
+ return;
+
+ m_ignoreCurrentChanged = true;
+ const QString alias = resourceFile->alias();
+ item->setText(alias);
+ item->setToolTip(alias);
+
+ m_ignoreCurrentChanged = false;
+}
+
+void QtResourceEditorDialogPrivate::slotResourceFileRemoved(QtResourceFile *resourceFile)
+{
+ QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile);
+ if (!pathItem)
+ return;
+
+ QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile);
+ if (!aliasItem)
+ return;
+
+ QStandardItem *parentItem = pathItem->parent();
+
+ m_ignoreCurrentChanged = true;
+ parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row());
+ delete pathItem;
+ delete aliasItem;
+ m_ignoreCurrentChanged = false;
+ m_pathItemToResourceFile.remove(pathItem);
+ m_aliasItemToResourceFile.remove(aliasItem);
+ m_resourceFileToPathItem.remove(resourceFile);
+ m_resourceFileToAliasItem.remove(resourceFile);
+}
+
+
+void QtResourceEditorDialogPrivate::slotCurrentQrcFileChanged(QListWidgetItem *item)
+{
+ if (m_ignoreCurrentChanged)
+ return;
+
+ QtQrcFile *newCurrentQrcFile = m_itemToQrcFile.value(item);
+
+ if (newCurrentQrcFile == m_currentQrcFile)
+ return;
+
+ if (m_currentQrcFile) {
+ QMap<QtResourcePrefix *, QStandardItem *> currentPrefixList = m_resourcePrefixToPrefixItem;
+ QMapIterator<QtResourcePrefix *, QStandardItem *> itPrefix(currentPrefixList);
+ while (itPrefix.hasNext()) {
+ QtResourcePrefix *resourcePrefix = itPrefix.next().key();
+ QList<QtResourceFile *> currentResourceFiles = resourcePrefix->resourceFiles();
+ QListIterator<QtResourceFile *> itFile(currentResourceFiles);
+ while (itFile.hasNext())
+ slotResourceFileRemoved(itFile.next());
+ slotResourcePrefixRemoved(resourcePrefix);
+ }
+ }
+
+ m_currentQrcFile = newCurrentQrcFile;
+ slotCurrentTreeViewItemChanged(QModelIndex());
+ QStandardItem *firstPrefix = 0; // select first prefix
+ if (m_currentQrcFile) {
+ QList<QtResourcePrefix *> newPrefixList = m_currentQrcFile->resourcePrefixList();
+ QListIterator<QtResourcePrefix *> itPrefix(newPrefixList);
+ while (itPrefix.hasNext()) {
+ QtResourcePrefix *resourcePrefix = itPrefix.next();
+ if (QStandardItem *newPrefixItem = insertResourcePrefix(resourcePrefix))
+ if (!firstPrefix)
+ firstPrefix = newPrefixItem;
+ QList<QtResourceFile *> newResourceFiles = resourcePrefix->resourceFiles();
+ QListIterator<QtResourceFile *> itFile(newResourceFiles);
+ while (itFile.hasNext())
+ slotResourceFileInserted(itFile.next());
+ }
+ }
+ m_ui.resourceTreeView->setCurrentIndex(firstPrefix ? m_treeModel->indexFromItem(firstPrefix) : QModelIndex());
+
+ m_removeQrcFileAction->setEnabled(m_currentQrcFile);
+ m_moveUpQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->prevQrcFile(m_currentQrcFile));
+ m_moveDownQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->nextQrcFile(m_currentQrcFile));
+}
+
+void QtResourceEditorDialogPrivate::slotCurrentTreeViewItemChanged(const QModelIndex &index)
+{
+ QStandardItem *item = m_treeModel->itemFromIndex(index);
+ QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item);
+ if (!resourceFile)
+ resourceFile = m_aliasItemToResourceFile.value(item);
+ QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
+ if (!resourcePrefix)
+ resourcePrefix = m_languageItemToResourcePrefix.value(item);
+
+ bool moveUpEnabled = false;
+ bool moveDownEnabled = false;
+ bool currentItem = resourceFile || resourcePrefix;
+
+ if (resourceFile) {
+ if (m_qrcManager->prevResourceFile(resourceFile))
+ moveUpEnabled = true;
+ if (m_qrcManager->nextResourceFile(resourceFile))
+ moveDownEnabled = true;
+ } else if (resourcePrefix) {
+ if (m_qrcManager->prevResourcePrefix(resourcePrefix))
+ moveUpEnabled = true;
+ if (m_qrcManager->nextResourcePrefix(resourcePrefix))
+ moveDownEnabled = true;
+ }
+
+ m_newPrefixAction->setEnabled(m_currentQrcFile);
+ m_addResourceFileAction->setEnabled(currentItem);
+ m_changePrefixAction->setEnabled(currentItem);
+ m_changeLanguageAction->setEnabled(currentItem);
+ m_changeAliasAction->setEnabled(resourceFile);
+ m_removeAction->setEnabled(currentItem);
+ m_moveUpAction->setEnabled(moveUpEnabled);
+ m_moveDownAction->setEnabled(moveDownEnabled);
+ m_clonePrefixAction->setEnabled(currentItem);
+}
+
+void QtResourceEditorDialogPrivate::slotListWidgetContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu(q_ptr);
+ menu.addAction(m_newQrcFileAction);
+ menu.addAction(m_importQrcFileAction);
+ menu.addAction(m_removeQrcFileAction);
+ menu.addSeparator();
+ menu.addAction(m_moveUpQrcFileAction);
+ menu.addAction(m_moveDownQrcFileAction);
+ menu.exec(m_ui.qrcFileList->mapToGlobal(pos));
+}
+
+void QtResourceEditorDialogPrivate::slotTreeViewContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu(q_ptr);
+ menu.addAction(m_newPrefixAction);
+ menu.addAction(m_addResourceFileAction);
+ menu.addAction(m_removeAction);
+ menu.addSeparator();
+ menu.addAction(m_changePrefixAction);
+ menu.addAction(m_changeLanguageAction);
+ menu.addAction(m_changeAliasAction);
+ menu.addSeparator();
+ menu.addAction(m_clonePrefixAction);
+ menu.addSeparator();
+ menu.addAction(m_moveUpAction);
+ menu.addAction(m_moveDownAction);
+ menu.exec(m_ui.resourceTreeView->mapToGlobal(pos));
+}
+
+void QtResourceEditorDialogPrivate::slotTreeViewItemChanged(QStandardItem *item)
+{
+ if (m_ignoreCurrentChanged)
+ return;
+
+ const QString newValue = item->text();
+ QtResourceFile *resourceFile = m_aliasItemToResourceFile.value(item);
+ if (resourceFile) {
+ m_qrcManager->changeResourceAlias(resourceFile, newValue);
+ return;
+ }
+
+ QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
+ if (resourcePrefix) {
+ m_qrcManager->changeResourcePrefix(resourcePrefix, newValue);
+ return;
+ }
+
+ resourcePrefix = m_languageItemToResourcePrefix.value(item);
+ if (resourcePrefix) {
+ m_qrcManager->changeResourceLanguage(resourcePrefix, newValue);
+ return;
+ }
+}
+
+QString QtResourceEditorDialogPrivate::getSaveFileNameWithExtension(QWidget *parent,
+ const QString &title, QString dir, const QString &filter, const QString &extension) const
+{
+ const QChar dot = QLatin1Char('.');
+
+ QString saveFile;
+ while (true) {
+ saveFile = m_dlgGui->getSaveFileName(parent, title, dir, filter, 0, QFileDialog::DontConfirmOverwrite);
+ if (saveFile.isEmpty())
+ return saveFile;
+
+ const QFileInfo fInfo(saveFile);
+ if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) {
+ saveFile += dot;
+ saveFile += extension;
+ }
+
+ const QFileInfo fi(saveFile);
+ if (!fi.exists())
+ break;
+
+ if (warning(title, msgOverwrite(fi.fileName()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
+ break;
+
+ dir = saveFile;
+ }
+ return saveFile;
+}
+
+QString QtResourceEditorDialogPrivate::qrcStartDirectory() const
+{
+ if (!m_currentQrcFile)
+ return QString();
+ const QDir dir = QFileInfo(m_currentQrcFile->path()).dir();
+ return dir.exists() ? dir.absolutePath() : QString();
+}
+
+void QtResourceEditorDialogPrivate::slotNewQrcFile()
+{
+ const QString qrcPath = getSaveFileNameWithExtension(q_ptr,
+ QApplication::translate("QtResourceEditorDialog", "New Resource File", 0, QApplication::UnicodeUTF8),
+ m_firstQrcFileDialog ? qrcStartDirectory() : QString(),
+ QApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8),
+ QLatin1String("qrc"));
+ if (qrcPath.isEmpty())
+ return;
+
+ m_firstQrcFileDialog = false;
+ if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) {
+ // QMessageBox ???
+ QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile);
+ m_ui.qrcFileList->setCurrentItem(item);
+ item->setSelected(true);
+ return;
+ }
+
+ QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
+
+ QtQrcFile *qrcFile = m_qrcManager->insertQrcFile(qrcPath, nextQrcFile, true);
+ m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile));
+}
+
+void QtResourceEditorDialogPrivate::slotImportQrcFile()
+{
+ const QString qrcPath = m_dlgGui->getOpenFileName(q_ptr,
+ QApplication::translate("QtResourceEditorDialog", "Import Resource File", 0, QApplication::UnicodeUTF8),
+ m_firstQrcFileDialog ? qrcStartDirectory() : QString(),
+ QApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8));
+ if (qrcPath.isEmpty())
+ return;
+ m_firstQrcFileDialog = false;
+ if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) {
+ // QMessageBox ???
+ QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile);
+ m_ui.qrcFileList->setCurrentItem(item);
+ item->setSelected(true);
+ return;
+ }
+
+ QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
+
+ QtQrcFileData qrcFileData;
+ loadQrcFile(qrcPath, &qrcFileData);
+ QtQrcFile *qrcFile = m_qrcManager->importQrcFile(qrcFileData, nextQrcFile);
+ m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile));
+}
+
+void QtResourceEditorDialogPrivate::slotRemoveQrcFile()
+{
+ if (!m_currentQrcFile)
+ return;
+
+ QtQrcFile *currentQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
+ if (!currentQrcFile)
+ currentQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile);
+
+ m_qrcManager->removeQrcFile(m_currentQrcFile);
+ QListWidgetItem *item = m_qrcFileToItem.value(currentQrcFile);
+ if (item) {
+ m_ui.qrcFileList->setCurrentItem(item);
+ item->setSelected(true);
+ }
+}
+
+void QtResourceEditorDialogPrivate::slotMoveUpQrcFile()
+{
+ if (!m_currentQrcFile)
+ return;
+
+ QtQrcFile *prevQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile);
+ if (!prevQrcFile)
+ return;
+
+ m_qrcManager->moveQrcFile(m_currentQrcFile, prevQrcFile);
+}
+
+void QtResourceEditorDialogPrivate::slotMoveDownQrcFile()
+{
+ if (!m_currentQrcFile)
+ return;
+
+ QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
+ if (!nextQrcFile)
+ return;
+ nextQrcFile = m_qrcManager->nextQrcFile(nextQrcFile);
+
+ m_qrcManager->moveQrcFile(m_currentQrcFile, nextQrcFile);
+}
+
+QtResourceFile *QtResourceEditorDialogPrivate::getCurrentResourceFile() const
+{
+ QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
+
+
+ QtResourceFile *currentResourceFile = 0;
+ if (currentItem) {
+ currentResourceFile = m_pathItemToResourceFile.value(currentItem);
+ if (!currentResourceFile)
+ currentResourceFile = m_aliasItemToResourceFile.value(currentItem);
+ }
+ return currentResourceFile;
+}
+
+QtResourcePrefix *QtResourceEditorDialogPrivate::getCurrentResourcePrefix() const
+{
+ QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
+
+ QtResourcePrefix *currentResourcePrefix = 0;
+ if (currentItem) {
+ currentResourcePrefix = m_prefixItemToResourcePrefix.value(currentItem);
+ if (!currentResourcePrefix) {
+ currentResourcePrefix = m_languageItemToResourcePrefix.value(currentItem);
+ if (!currentResourcePrefix) {
+ QtResourceFile *currentResourceFile = getCurrentResourceFile();
+ if (currentResourceFile)
+ currentResourcePrefix = m_qrcManager->resourcePrefixOf(currentResourceFile);
+ }
+ }
+ }
+ return currentResourcePrefix;
+}
+
+void QtResourceEditorDialogPrivate::selectTreeRow(QStandardItem *item)
+{
+ const QModelIndex index = m_treeModel->indexFromItem(item);
+ m_treeSelection->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+ m_treeSelection->setCurrentIndex(index, QItemSelectionModel::Select);
+}
+
+void QtResourceEditorDialogPrivate::slotNewPrefix()
+{
+ if (!m_currentQrcFile)
+ return;
+
+ QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
+ QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(currentResourcePrefix);
+ QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile,
+ QApplication::translate("QtResourceEditorDialog", "newPrefix", 0, QApplication::UnicodeUTF8),
+ QString(), nextResourcePrefix);
+ if (!newResourcePrefix)
+ return;
+
+ QStandardItem *newItem = m_resourcePrefixToPrefixItem.value(newResourcePrefix);
+ if (!newItem)
+ return;
+
+ const QModelIndex index = m_treeModel->indexFromItem(newItem);
+ selectTreeRow(newItem);
+ m_ui.resourceTreeView->edit(index);
+}
+
+static inline QString outOfPathWarning(const QString &fname)
+{
+ return QApplication::translate("QtResourceEditorDialog",
+ "<p><b>Warning:</b> The file</p>"
+ "<p>%1</p>"
+ "<p>is outside of the current resource file's parent directory.</p>").arg(fname);
+}
+
+static inline QString outOfPathWarningInfo()
+{
+ return QApplication::translate("QtResourceEditorDialog",
+ "<p>To resolve the issue, press:</p>"
+ "<table>"
+ "<tr><th align=\"left\">Copy</th><td>to copy the file to the resource file's parent directory.</td></tr>"
+ "<tr><th align=\"left\">Copy As...</th><td>to copy the file into a subdirectory of the resource file's parent directory.</td></tr>"
+ "<tr><th align=\"left\">Keep</th><td>to use its current location.</td></tr></table>");
+}
+
+void QtResourceEditorDialogPrivate::slotAddFiles()
+{
+ if (!m_currentQrcFile)
+ return;
+
+ QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
+ QtResourceFile *currentResourceFile = getCurrentResourceFile();
+ if (!currentResourcePrefix)
+ return;
+
+ QString initialPath = m_currentQrcFile->path();
+ if (currentResourceFile) {
+ QFileInfo fi(currentResourceFile->fullPath());
+ initialPath = fi.absolutePath();
+ }
+
+ const QStringList resourcePaths = m_dlgGui->getOpenImageFileNames(q_ptr,
+ QApplication::translate("QtResourceEditorDialog", "Add Files", 0, QApplication::UnicodeUTF8),
+ initialPath);
+ if (resourcePaths.isEmpty())
+ return;
+
+ QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(currentResourceFile);
+ if (!currentResourceFile) {
+ QList<QtResourceFile *> resourceFiles = currentResourcePrefix->resourceFiles();
+ if (resourceFiles.count() > 0)
+ nextResourceFile = resourceFiles.first();
+ }
+
+ const QFileInfo fi(m_currentQrcFile->path());
+ const QString destDir = fi.absolutePath();
+ const QDir dir(fi.absolutePath());
+ QStringListIterator itResourcePath(resourcePaths);
+ while (itResourcePath.hasNext()) {
+ QString resourcePath = itResourcePath.next();
+ QString relativePath = dir.relativeFilePath(resourcePath);
+ if (relativePath.startsWith(QLatin1String(".."))) {
+ QMessageBox msgBox(QMessageBox::Warning,
+ QApplication::translate("QtResourceEditorDialog", "Incorrect Path", 0, QApplication::UnicodeUTF8),
+ outOfPathWarning(relativePath), QMessageBox::Cancel);
+ msgBox.setInformativeText(outOfPathWarningInfo());
+ QPushButton *copyButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog",
+ "Copy", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole);
+ QPushButton *copyAsButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog",
+ "Copy As...", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole);
+ QPushButton *keepButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog",
+ "Keep", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole);
+ QPushButton *skipButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog",
+ "Skip", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole);
+ msgBox.setEscapeButton(QMessageBox::Cancel);
+ msgBox.setDefaultButton(copyButton);
+ msgBox.exec();
+ QString destPath;
+ if (msgBox.clickedButton() == keepButton) {
+ // nothing
+ } else if (msgBox.clickedButton() == copyButton) {
+ QFileInfo resInfo(resourcePath);
+ QDir dd(destDir);
+ destPath = dd.absoluteFilePath(resInfo.fileName());
+ if (dd.exists(resInfo.fileName())) {
+ if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8),
+ msgOverwrite(resInfo.fileName()),
+ QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Yes)
+ continue;
+ }
+ resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled
+ } else if (msgBox.clickedButton() == copyAsButton) {
+ destPath = browseForNewLocation(resourcePath, dir); // returns empty string in case browsing was canceled
+ if (destPath.isEmpty())
+ continue;
+ resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled
+ } else if (msgBox.clickedButton() == skipButton) { // skipped
+ continue;
+ } else { // canceled
+ return;
+ }
+ if (resourcePath.isEmpty())
+ continue;
+ }
+ relativePath = dir.relativeFilePath(resourcePath);
+ QtResourceFile *newResourceFile = m_qrcManager->insertResourceFile(currentResourcePrefix, relativePath, QString(), nextResourceFile);
+
+ QStandardItem *newItem = m_resourceFileToPathItem.value(newResourceFile);
+ if (newItem)
+ selectTreeRow(newItem);
+ }
+}
+
+void QtResourceEditorDialogPrivate::slotChangePrefix()
+{
+ QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
+ if (!currentResourcePrefix)
+ return;
+
+ QStandardItem *item = m_resourcePrefixToPrefixItem.value(currentResourcePrefix);
+ QModelIndex index = m_treeModel->indexFromItem(item);
+ selectTreeRow(item);
+ m_ui.resourceTreeView->scrollTo(index);
+ m_ui.resourceTreeView->edit(index);
+}
+
+void QtResourceEditorDialogPrivate::slotChangeLanguage()
+{
+ QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
+ if (!currentResourcePrefix)
+ return;
+
+ QStandardItem *item = m_resourcePrefixToLanguageItem.value(currentResourcePrefix);
+ QModelIndex index = m_treeModel->indexFromItem(item);
+ selectTreeRow(item);
+ m_ui.resourceTreeView->scrollTo(index);
+ m_ui.resourceTreeView->edit(index);
+}
+
+void QtResourceEditorDialogPrivate::slotChangeAlias()
+{
+ QtResourceFile *currentResourceFile = getCurrentResourceFile();
+ if (!currentResourceFile)
+ return;
+
+ QStandardItem *item = m_resourceFileToAliasItem.value(currentResourceFile);
+ QModelIndex index = m_treeModel->indexFromItem(item);
+ selectTreeRow(item);
+ m_ui.resourceTreeView->scrollTo(index);
+ m_ui.resourceTreeView->edit(index);
+}
+
+void QtResourceEditorDialogPrivate::slotClonePrefix()
+{
+ QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
+ if (!currentResourcePrefix)
+ return;
+
+ bool ok;
+ QString suffix = QInputDialog::getText(q_ptr, QApplication::translate("QtResourceEditorDialog", "Clone Prefix", 0, QApplication::UnicodeUTF8),
+ QApplication::translate("QtResourceEditorDialog", "Enter the suffix which you want to add to the names of the cloned files.\n"
+ "This could for example be a language extension like \"_de\".", 0, QApplication::UnicodeUTF8),
+ QLineEdit::Normal, QString(), &ok);
+ if (!ok)
+ return;
+
+ QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile, currentResourcePrefix->prefix(),
+ currentResourcePrefix->language(), m_qrcManager->nextResourcePrefix(currentResourcePrefix));
+ if (newResourcePrefix) {
+ QList<QtResourceFile *> files = currentResourcePrefix->resourceFiles();
+ QListIterator<QtResourceFile *> itFile(files);
+ while (itFile.hasNext()) {
+ QtResourceFile *resourceFile = itFile.next();
+ QString path = resourceFile->path();
+ QFileInfo fi(path);
+ QDir dir(fi.dir());
+ QString oldSuffix = fi.completeSuffix();
+ if (!oldSuffix.isEmpty())
+ oldSuffix = QLatin1Char('.') + oldSuffix;
+ const QString newBaseName = fi.baseName() + suffix + oldSuffix;
+ const QString newPath = QDir::cleanPath(dir.filePath(newBaseName));
+ m_qrcManager->insertResourceFile(newResourcePrefix, newPath,
+ resourceFile->alias());
+ }
+ }
+}
+
+void QtResourceEditorDialogPrivate::slotRemove()
+{
+ QStandardItem *item = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
+ if (!item)
+ return;
+
+ QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item);
+ if (!resourceFile)
+ resourceFile = m_aliasItemToResourceFile.value(item);
+ QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
+ if (!resourcePrefix)
+ resourcePrefix = m_languageItemToResourcePrefix.value(item);
+
+ QStandardItem *newCurrentItem = 0;
+
+ if (resourceFile) {
+ QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile);
+ if (!nextFile)
+ nextFile = m_qrcManager->prevResourceFile(resourceFile);
+ newCurrentItem = m_resourceFileToPathItem.value(nextFile);
+ if (!newCurrentItem)
+ newCurrentItem = m_resourcePrefixToPrefixItem.value(m_qrcManager->resourcePrefixOf(resourceFile));
+ }
+ if (!newCurrentItem) {
+ QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
+ if (!nextPrefix)
+ nextPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
+ newCurrentItem = m_resourcePrefixToPrefixItem.value(nextPrefix);
+ }
+
+ selectTreeRow(newCurrentItem);
+
+ if (resourcePrefix)
+ m_qrcManager->removeResourcePrefix(resourcePrefix);
+ else if (resourceFile)
+ m_qrcManager->removeResourceFile(resourceFile);
+}
+
+void QtResourceEditorDialogPrivate::slotMoveUp()
+{
+ if (QtResourceFile *resourceFile = getCurrentResourceFile()) {
+ QtResourceFile *prevFile = m_qrcManager->prevResourceFile(resourceFile);
+
+ if (!prevFile)
+ return;
+
+ m_qrcManager->moveResourceFile(resourceFile, prevFile);
+ selectTreeRow(m_resourceFileToPathItem.value(resourceFile));
+ } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) {
+ QtResourcePrefix *prevPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
+
+ if (!prevPrefix)
+ return;
+
+ m_qrcManager->moveResourcePrefix(resourcePrefix, prevPrefix);
+ selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix));
+ }
+}
+
+void QtResourceEditorDialogPrivate::slotMoveDown()
+{
+ if (QtResourceFile *resourceFile = getCurrentResourceFile()) {
+ QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile);
+
+ if (!nextFile)
+ return;
+
+ m_qrcManager->moveResourceFile(resourceFile, m_qrcManager->nextResourceFile(nextFile));
+ selectTreeRow(m_resourceFileToPathItem.value(resourceFile));
+ } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) {
+ QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
+
+ if (!nextPrefix)
+ return;
+
+ m_qrcManager->moveResourcePrefix(resourcePrefix, m_qrcManager->nextResourcePrefix(nextPrefix));
+ selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix));
+ }
+}
+
+QString QtResourceEditorDialogPrivate::browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const
+{
+ QFileInfo fi(resourceFile);
+ const QString initialPath = rootDir.absoluteFilePath(fi.fileName());
+ while (1) {
+ QString newPath = m_dlgGui->getSaveFileName(q_ptr,
+ QApplication::translate("QtResourceEditorDialog", "Copy As", 0, QApplication::UnicodeUTF8),
+ initialPath);
+ QString relativePath = rootDir.relativeFilePath(newPath);
+ if (relativePath.startsWith(QLatin1String(".."))) {
+ if (warning(QApplication::translate("QtResourceEditorDialog", "Copy As", 0, QApplication::UnicodeUTF8),
+ QApplication::translate("QtResourceEditorDialog", "<p>The selected file:</p>"
+ "<p>%1</p><p>is outside of the current resource file's directory:</p><p>%2</p>"
+ "<p>Please select another path within this directory.<p>", 0,
+ QApplication::UnicodeUTF8).arg(relativePath).arg(rootDir.absolutePath()),
+ QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok)
+ return QString();
+ } else {
+ return newPath;
+ }
+ }
+
+ return QString();
+}
+
+QString QtResourceEditorDialogPrivate::copyResourceFile(const QString &resourceFile, const QString &destPath) const
+{
+ QFileInfo fi(destPath);
+ if (fi.exists()) {
+ while (fi.exists() && !QFile::remove(destPath)) {
+ if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8),
+ QApplication::translate("QtResourceEditorDialog", "Could not overwrite %1.", 0, QApplication::UnicodeUTF8).arg(fi.fileName()),
+ QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry)
+ return QString();
+ }
+ }
+ while (!QFile::copy(resourceFile, destPath)) {
+ if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8),
+ QApplication::translate("QtResourceEditorDialog", "Could not copy\n%1\nto\n%2",
+ 0, QApplication::UnicodeUTF8).arg(resourceFile).arg(destPath),
+ QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry)
+ return QString();
+ }
+ return destPath;
+}
+bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData)
+{
+ QString errorMessage;
+ const bool rc = loadQrcFile(path, qrcFileData, &errorMessage);
+// if (!rc)
+// warning(QApplication::translate("QtResourceEditorDialog", "Resource File Load Error"), errorMessage);
+ return rc;
+}
+bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage)
+{
+ if (!qrcFileData)
+ return false;
+
+ qrcFileData->qrcPath = path;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly)) {
+ // there is sufficient hint while loading a form and after opening the editor (qrc marked marked with red and with [missing] text)
+ //*errorMessage = QApplication::translate("QtResourceEditorDialog", "Unable to open %1 for reading: %2").arg(path).arg(file.errorString());
+ return false;
+ }
+
+ QByteArray dataArray = file.readAll();
+ file.close();
+
+ QDomDocument doc;
+ int errLine, errCol;
+ if (!doc.setContent(dataArray, errorMessage, &errLine, &errCol)) {
+ *errorMessage = QCoreApplication::translate("QtResourceEditorDialog", "A parse error occurred at line %1, column %2 of %3:\n%4").arg(errLine).arg(errCol).arg(path).arg(*errorMessage);
+ return false;
+ }
+
+ return loadQrcFileData(doc, path, qrcFileData, errorMessage);
+}
+
+bool QtResourceEditorDialogPrivate::saveQrcFile(const QtQrcFileData &qrcFileData)
+{
+ QFile file(qrcFileData.qrcPath);
+ while (!file.open(QIODevice::WriteOnly)) {
+ QMessageBox msgBox(QMessageBox::Warning,
+ QApplication::translate("QtResourceEditorDialog", "Save Resource File", 0, QApplication::UnicodeUTF8),
+ QApplication::translate("QtResourceEditorDialog", "Could not write %1: %2", 0, QApplication::UnicodeUTF8).arg(qrcFileData.qrcPath).arg(file.errorString()),
+ QMessageBox::Cancel|QMessageBox::Ignore|QMessageBox::Retry);
+ msgBox.setEscapeButton(QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Ignore);
+ switch (msgBox.exec()) {
+ case QMessageBox::Retry:
+ break; // nothing
+ case QMessageBox::Ignore:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ QDomDocument doc = saveQrcFileData(qrcFileData);
+
+ QByteArray dataArray = doc.toByteArray(2);
+ file.write(dataArray);
+
+ file.close();
+ return true;
+}
+
+QtResourceEditorDialog::QtResourceEditorDialog(QDesignerFormEditorInterface *core, QDesignerDialogGuiInterface *dlgGui, QWidget *parent)
+ : QDialog(parent)
+{
+ d_ptr = new QtResourceEditorDialogPrivate();
+ d_ptr->q_ptr = this;
+ d_ptr->m_ui.setupUi(this);
+ d_ptr->m_qrcManager = new QtQrcManager(this);
+ d_ptr->m_dlgGui = dlgGui;
+ d_ptr->m_core = core;
+
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowTitle(tr("Edit Resources"));
+
+ connect(d_ptr->m_qrcManager, SIGNAL(qrcFileInserted(QtQrcFile *)),
+ this, SLOT(slotQrcFileInserted(QtQrcFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(qrcFileMoved(QtQrcFile *, QtQrcFile *)),
+ this, SLOT(slotQrcFileMoved(QtQrcFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(qrcFileRemoved(QtQrcFile *)),
+ this, SLOT(slotQrcFileRemoved(QtQrcFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixInserted(QtResourcePrefix *)),
+ this, SLOT(slotResourcePrefixInserted(QtResourcePrefix *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixMoved(QtResourcePrefix *, QtResourcePrefix *)),
+ this, SLOT(slotResourcePrefixMoved(QtResourcePrefix *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixChanged(QtResourcePrefix *, const QString &)),
+ this, SLOT(slotResourcePrefixChanged(QtResourcePrefix *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourceLanguageChanged(QtResourcePrefix *, const QString &)),
+ this, SLOT(slotResourceLanguageChanged(QtResourcePrefix *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixRemoved(QtResourcePrefix *)),
+ this, SLOT(slotResourcePrefixRemoved(QtResourcePrefix *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourceFileInserted(QtResourceFile *)),
+ this, SLOT(slotResourceFileInserted(QtResourceFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourceFileMoved(QtResourceFile *, QtResourceFile *)),
+ this, SLOT(slotResourceFileMoved(QtResourceFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourceAliasChanged(QtResourceFile *, const QString &)),
+ this, SLOT(slotResourceAliasChanged(QtResourceFile *)));
+ connect(d_ptr->m_qrcManager, SIGNAL(resourceFileRemoved(QtResourceFile *)),
+ this, SLOT(slotResourceFileRemoved(QtResourceFile *)));
+
+ QIcon upIcon = qdesigner_internal::createIconSet(QString::fromUtf8("up.png"));
+ QIcon downIcon = qdesigner_internal::createIconSet(QString::fromUtf8("down.png"));
+ QIcon minusIcon = qdesigner_internal::createIconSet(QString::fromUtf8("minus-16.png"));
+ QIcon newIcon = qdesigner_internal::createIconSet(QString::fromUtf8("filenew-16.png"));
+ QIcon openIcon = qdesigner_internal::createIconSet(QString::fromUtf8("fileopen-16.png"));
+ QIcon removeIcon = qdesigner_internal::createIconSet(QString::fromUtf8("editdelete-16.png"));
+ QIcon addPrefixIcon = qdesigner_internal::createIconSet(QString::fromUtf8("prefix-add.png"));
+
+ d_ptr->m_newQrcFileAction = new QAction(newIcon, tr("New..."), this);
+ d_ptr->m_newQrcFileAction->setToolTip(tr("New Resource File"));
+ d_ptr->m_importQrcFileAction = new QAction(openIcon, tr("Open..."), this);
+ d_ptr->m_importQrcFileAction->setToolTip(tr("Open Resource File"));
+ d_ptr->m_removeQrcFileAction = new QAction(removeIcon, tr("Remove"), this);
+ d_ptr->m_moveUpQrcFileAction = new QAction(upIcon, tr("Move Up"), this);
+ d_ptr->m_moveDownQrcFileAction = new QAction(downIcon, tr("Move Down"), this);
+
+ d_ptr->m_newPrefixAction = new QAction(addPrefixIcon, tr("Add Prefix"), this);
+ d_ptr->m_newPrefixAction->setToolTip(tr("Add Prefix"));
+ d_ptr->m_addResourceFileAction = new QAction(openIcon, tr("Add Files..."), this);
+ d_ptr->m_changePrefixAction = new QAction(tr("Change Prefix"), this);
+ d_ptr->m_changeLanguageAction = new QAction(tr("Change Language"), this);
+ d_ptr->m_changeAliasAction = new QAction(tr("Change Alias"), this);
+ d_ptr->m_clonePrefixAction = new QAction(tr("Clone Prefix..."), this);
+ d_ptr->m_removeAction = new QAction(minusIcon, tr("Remove"), this);
+ d_ptr->m_moveUpAction = new QAction(upIcon, tr("Move Up"), this);
+ d_ptr->m_moveDownAction = new QAction(downIcon, tr("Move Down"), this);
+
+ d_ptr->m_ui.newQrcButton->setDefaultAction(d_ptr->m_newQrcFileAction);
+ d_ptr->m_ui.importQrcButton->setDefaultAction(d_ptr->m_importQrcFileAction);
+ d_ptr->m_ui.removeQrcButton->setDefaultAction(d_ptr->m_removeQrcFileAction);
+
+ d_ptr->m_ui.newResourceButton->setDefaultAction(d_ptr->m_newPrefixAction);
+ d_ptr->m_ui.addResourceButton->setDefaultAction(d_ptr->m_addResourceFileAction);
+ d_ptr->m_ui.removeResourceButton->setDefaultAction(d_ptr->m_removeAction);
+
+ connect(d_ptr->m_newQrcFileAction, SIGNAL(triggered()), this, SLOT(slotNewQrcFile()));
+ connect(d_ptr->m_importQrcFileAction, SIGNAL(triggered()), this, SLOT(slotImportQrcFile()));
+ connect(d_ptr->m_removeQrcFileAction, SIGNAL(triggered()), this, SLOT(slotRemoveQrcFile()));
+ connect(d_ptr->m_moveUpQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveUpQrcFile()));
+ connect(d_ptr->m_moveDownQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveDownQrcFile()));
+
+ connect(d_ptr->m_newPrefixAction, SIGNAL(triggered()), this, SLOT(slotNewPrefix()));
+ connect(d_ptr->m_addResourceFileAction, SIGNAL(triggered()), this, SLOT(slotAddFiles()));
+ connect(d_ptr->m_changePrefixAction, SIGNAL(triggered()), this, SLOT(slotChangePrefix()));
+ connect(d_ptr->m_changeLanguageAction, SIGNAL(triggered()), this, SLOT(slotChangeLanguage()));
+ connect(d_ptr->m_changeAliasAction, SIGNAL(triggered()), this, SLOT(slotChangeAlias()));
+ connect(d_ptr->m_clonePrefixAction, SIGNAL(triggered()), this, SLOT(slotClonePrefix()));
+ connect(d_ptr->m_removeAction, SIGNAL(triggered()), this, SLOT(slotRemove()));
+ connect(d_ptr->m_moveUpAction, SIGNAL(triggered()), this, SLOT(slotMoveUp()));
+ connect(d_ptr->m_moveDownAction, SIGNAL(triggered()), this, SLOT(slotMoveDown()));
+
+ d_ptr->m_ui.qrcFileList->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(d_ptr->m_ui.qrcFileList, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotListWidgetContextMenuRequested(const QPoint &)));
+ connect(d_ptr->m_ui.qrcFileList, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this, SLOT(slotCurrentQrcFileChanged(QListWidgetItem *)));
+
+ d_ptr->m_treeModel = new QStandardItemModel(this);
+ d_ptr->m_treeModel->setColumnCount(2);
+ d_ptr->m_treeModel->setHorizontalHeaderItem(0, new QStandardItem(tr("Prefix / Path")));
+ d_ptr->m_treeModel->setHorizontalHeaderItem(1, new QStandardItem(tr("Language / Alias")));
+ d_ptr->m_ui.resourceTreeView->setModel(d_ptr->m_treeModel);
+ d_ptr->m_ui.resourceTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ d_ptr->m_treeSelection = d_ptr->m_ui.resourceTreeView->selectionModel();
+ connect(d_ptr->m_ui.resourceTreeView->header(), SIGNAL(sectionDoubleClicked(int)), d_ptr->m_ui.resourceTreeView, SLOT(resizeColumnToContents(int)));
+ d_ptr->m_ui.resourceTreeView->setTextElideMode(Qt::ElideLeft);
+
+ connect(d_ptr->m_ui.resourceTreeView, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotTreeViewContextMenuRequested(const QPoint &)));
+ connect(d_ptr->m_treeModel, SIGNAL(itemChanged(QStandardItem *)),
+ this, SLOT(slotTreeViewItemChanged(QStandardItem *)));
+ connect(d_ptr->m_treeSelection, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(slotCurrentTreeViewItemChanged(const QModelIndex &)));
+
+ d_ptr->m_ui.resourceTreeView->setColumnWidth(0, 200);
+
+ d_ptr->slotCurrentTreeViewItemChanged(QModelIndex());
+ d_ptr->m_removeQrcFileAction->setEnabled(false);
+ d_ptr->m_moveUpQrcFileAction->setEnabled(false);
+ d_ptr->m_moveDownQrcFileAction->setEnabled(false);
+
+ QDesignerSettingsInterface *settings = core->settingsManager();
+ settings->beginGroup(QLatin1String(QrcDialogC));
+
+ d_ptr->m_ui.splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray());
+ if (settings->contains(QLatin1String(Geometry)))
+ setGeometry(settings->value(QLatin1String(Geometry)).toRect());
+
+ settings->endGroup();
+}
+
+QtResourceEditorDialog::~QtResourceEditorDialog()
+{
+ QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager();
+ settings->beginGroup(QLatin1String(QrcDialogC));
+
+ settings->setValue(QLatin1String(SplitterPosition), d_ptr->m_ui.splitter->saveState());
+ settings->setValue(QLatin1String(Geometry), geometry());
+ settings->endGroup();
+
+ delete d_ptr;
+}
+
+QtResourceModel *QtResourceEditorDialog::model() const
+{
+ return d_ptr->m_resourceModel;
+}
+
+void QtResourceEditorDialog::setResourceModel(QtResourceModel *model)
+{
+ d_ptr->m_resourceModel = model;
+
+ QtResourceSet *resourceSet = d_ptr->m_resourceModel->currentResourceSet();
+ if (!resourceSet) {
+ // disable everything but cancel button
+ return;
+ }
+
+ d_ptr->m_initialState.clear();
+
+ // enable qrcBox
+
+ QStringList paths = resourceSet->activeQrcPaths();
+ QStringListIterator it(paths);
+ while (it.hasNext()) {
+ const QString path = it.next();
+ QtQrcFileData qrcFileData;
+ d_ptr->loadQrcFile(path, &qrcFileData);
+ d_ptr->m_initialState << qrcFileData;
+ d_ptr->m_qrcManager->importQrcFile(qrcFileData);
+ }
+ if (d_ptr->m_ui.qrcFileList->count() > 0) {
+ d_ptr->m_ui.qrcFileList->item(0)->setSelected(true);
+ }
+}
+
+QString QtResourceEditorDialog::selectedResource() const
+{
+ //QtResourcePrefix *currentResourcePrefix = d_ptr->m_qrcManager->resourcePrefixOf(currentResourceFile);
+ QtResourcePrefix *currentResourcePrefix = d_ptr->getCurrentResourcePrefix();
+ if (!currentResourcePrefix)
+ return QString();
+
+ const QChar slash(QLatin1Char('/'));
+ QString resource = currentResourcePrefix->prefix();
+ if (!resource.startsWith(slash))
+ resource.prepend(slash);
+ if (!resource.endsWith(slash))
+ resource.append(slash);
+ resource.prepend(QLatin1Char(':'));
+
+ QtResourceFile *currentResourceFile = d_ptr->getCurrentResourceFile();
+ if (!currentResourceFile)
+ return resource;
+
+ QString resourceEnding = currentResourceFile->path();
+ if (!currentResourceFile->alias().isEmpty())
+ resourceEnding = currentResourceFile->alias();
+
+ const QString dotSlash(QLatin1String("./"));
+ const QString dotDotSlash(QLatin1String("../"));
+ while (1) {
+ if (resourceEnding.startsWith(slash))
+ resourceEnding = resourceEnding.mid(1);
+ else if (resourceEnding.startsWith(dotSlash))
+ resourceEnding = resourceEnding.mid(dotSlash.count());
+ else if (resourceEnding.startsWith(dotDotSlash))
+ resourceEnding = resourceEnding.mid(dotDotSlash.count());
+ else
+ break;
+ }
+
+ resource.append(resourceEnding);
+
+ return resource;
+}
+
+void QtResourceEditorDialog::displayResourceFailures(const QString &logOutput, QDesignerDialogGuiInterface *dlgGui, QWidget *parent)
+{
+ const QString msg = tr("<html><p><b>Warning:</b> There have been problems while reloading the resources:</p><pre>%1</pre></html>").arg(logOutput);
+ dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning,
+ tr("Resource Warning"), msg);
+}
+
+void QtResourceEditorDialog::accept()
+{
+ QStringList newQrcPaths;
+ QList<QtQrcFileData> currentState;
+
+ QList<QtQrcFile *> qrcFiles = d_ptr->m_qrcManager->qrcFiles();
+ QListIterator<QtQrcFile *> itQrc(qrcFiles);
+ while (itQrc.hasNext()) {
+ QtQrcFile *qrcFile = itQrc.next();
+ QtQrcFileData qrcFileData;
+ d_ptr->m_qrcManager->exportQrcFile(qrcFile, &qrcFileData);
+ currentState << qrcFileData;
+ if (qrcFileData == qrcFile->initialState()) {
+ // nothing
+ } else {
+ d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, false);
+ bool ok = d_ptr->saveQrcFile(qrcFileData);
+ d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, true);
+ if (!ok)
+ return;
+
+ d_ptr->m_resourceModel->setModified(qrcFileData.qrcPath);
+ }
+ newQrcPaths << qrcFileData.qrcPath;
+ }
+
+ if (currentState == d_ptr->m_initialState) {
+ // nothing
+ } else {
+ int errorCount;
+ QString errorMessages;
+ d_ptr->m_resourceModel->currentResourceSet()->activateQrcPaths(newQrcPaths, &errorCount, &errorMessages);
+ if (errorCount)
+ displayResourceFailures(errorMessages, d_ptr->m_dlgGui, this);
+ }
+ QDialog::accept();
+}
+
+QString QtResourceEditorDialog::editResources(QDesignerFormEditorInterface *core,
+ QtResourceModel *model,
+ QDesignerDialogGuiInterface *dlgGui,
+ QWidget *parent)
+{
+ QtResourceEditorDialog dialog(core, dlgGui, parent);
+ dialog.setResourceModel(model);
+ if (dialog.exec() == QDialog::Accepted)
+ return dialog.selectedResource();
+ return QString();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtresourceeditordialog_p.cpp"
+#include "qtresourceeditordialog.moc"
diff --git a/tools/designer/src/lib/shared/qtresourceeditordialog.ui b/tools/designer/src/lib/shared/qtresourceeditordialog.ui
new file mode 100644
index 0000000..fa760d9
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourceeditordialog.ui
@@ -0,0 +1,177 @@
+<ui version="4.0" >
+ <class>QtResourceEditorDialog</class>
+ <widget class="QDialog" name="QtResourceEditorDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>469</width>
+ <height>317</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="childrenCollapsible" >
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="qrcLayoutWidget" >
+ <layout class="QGridLayout" name="qrcLayout" >
+ <item row="0" column="0" colspan="4" >
+ <widget class="QListWidget" name="qrcFileList" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Ignored" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QToolButton" name="newQrcButton" >
+ <property name="toolTip" >
+ <string>New File</string>
+ </property>
+ <property name="text" >
+ <string>N</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QToolButton" name="removeQrcButton" >
+ <property name="toolTip" >
+ <string>Remove File</string>
+ </property>
+ <property name="text" >
+ <string>R</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Ignored</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QToolButton" name="importQrcButton" >
+ <property name="text" >
+ <string>I</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="resourceLayoutWidget" >
+ <layout class="QGridLayout" name="resourceLayout" >
+ <item row="0" column="0" colspan="4" >
+ <widget class="QTreeView" name="resourceTreeView" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QToolButton" name="newResourceButton" >
+ <property name="toolTip" >
+ <string>New Resource</string>
+ </property>
+ <property name="text" >
+ <string>N</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QToolButton" name="addResourceButton" >
+ <property name="text" >
+ <string>A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QToolButton" name="removeResourceButton" >
+ <property name="toolTip" >
+ <string>Remove Resource or File</string>
+ </property>
+ <property name="text" >
+ <string>R</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <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>
+ </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>QtResourceEditorDialog</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>QtResourceEditorDialog</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/lib/shared/qtresourceeditordialog_p.h b/tools/designer/src/lib/shared/qtresourceeditordialog_p.h
new file mode 100644
index 0000000..f2531d9
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourceeditordialog_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 QTRESOURCEEDITOR_H
+#define QTRESOURCEEDITOR_H
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QtResourceModel;
+class QDesignerDialogGuiInterface;
+class QDesignerFormEditorInterface;
+
+class QtResourceEditorDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ QtResourceModel *model() const;
+ void setResourceModel(QtResourceModel *model);
+
+ QString selectedResource() const;
+
+ static QString editResources(QDesignerFormEditorInterface *core, QtResourceModel *model,
+ QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0);
+
+ // Helper to display a message box with rcc logs in case of errors.
+ static void displayResourceFailures(const QString &logOutput, QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0);
+
+public slots:
+ virtual void accept();
+
+private:
+ QtResourceEditorDialog(QDesignerFormEditorInterface *core, QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0);
+ ~QtResourceEditorDialog();
+
+ class QtResourceEditorDialogPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QtResourceEditorDialog)
+ Q_DISABLE_COPY(QtResourceEditorDialog)
+
+ Q_PRIVATE_SLOT(d_func(), void slotQrcFileInserted(QtQrcFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotQrcFileMoved(QtQrcFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotQrcFileRemoved(QtQrcFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixInserted(QtResourcePrefix *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixMoved(QtResourcePrefix *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixChanged(QtResourcePrefix *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceLanguageChanged(QtResourcePrefix *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixRemoved(QtResourcePrefix *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceFileInserted(QtResourceFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceFileMoved(QtResourceFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceAliasChanged(QtResourceFile *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceFileRemoved(QtResourceFile *))
+
+ Q_PRIVATE_SLOT(d_func(), void slotCurrentQrcFileChanged(QListWidgetItem *))
+ Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeViewItemChanged(const QModelIndex &))
+ Q_PRIVATE_SLOT(d_func(), void slotListWidgetContextMenuRequested(const QPoint &))
+ Q_PRIVATE_SLOT(d_func(), void slotTreeViewContextMenuRequested(const QPoint &))
+ Q_PRIVATE_SLOT(d_func(), void slotTreeViewItemChanged(QStandardItem *))
+
+ Q_PRIVATE_SLOT(d_func(), void slotNewQrcFile())
+ Q_PRIVATE_SLOT(d_func(), void slotImportQrcFile())
+ Q_PRIVATE_SLOT(d_func(), void slotRemoveQrcFile())
+ Q_PRIVATE_SLOT(d_func(), void slotMoveUpQrcFile())
+ Q_PRIVATE_SLOT(d_func(), void slotMoveDownQrcFile())
+
+ Q_PRIVATE_SLOT(d_func(), void slotNewPrefix())
+ Q_PRIVATE_SLOT(d_func(), void slotAddFiles())
+ Q_PRIVATE_SLOT(d_func(), void slotChangePrefix())
+ Q_PRIVATE_SLOT(d_func(), void slotChangeLanguage())
+ Q_PRIVATE_SLOT(d_func(), void slotChangeAlias())
+ Q_PRIVATE_SLOT(d_func(), void slotClonePrefix())
+ Q_PRIVATE_SLOT(d_func(), void slotRemove())
+ Q_PRIVATE_SLOT(d_func(), void slotMoveUp())
+ Q_PRIVATE_SLOT(d_func(), void slotMoveDown())
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/tools/designer/src/lib/shared/qtresourcemodel.cpp b/tools/designer/src/lib/shared/qtresourcemodel.cpp
new file mode 100644
index 0000000..e6152be
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourcemodel.cpp
@@ -0,0 +1,648 @@
+/****************************************************************************
+**
+** 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 "qtresourcemodel_p.h"
+#include <rcc.h>
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QResource>
+#include <QtCore/QFileInfo>
+#include <QtCore/QIODevice>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+#include <QtCore/QFileSystemWatcher>
+
+QT_BEGIN_NAMESPACE
+
+enum { debugResourceModel = 0 };
+
+// ------------------- QtResourceSetPrivate
+class QtResourceSetPrivate
+{
+ QtResourceSet *q_ptr;
+ Q_DECLARE_PUBLIC(QtResourceSet)
+public:
+ QtResourceSetPrivate(QtResourceModel *model = 0);
+
+ QtResourceModel *m_resourceModel;
+};
+
+QtResourceSetPrivate::QtResourceSetPrivate(QtResourceModel *model) :
+ q_ptr(0),
+ m_resourceModel(model)
+{
+}
+
+// -------------------- QtResourceModelPrivate
+class QtResourceModelPrivate
+{
+ QtResourceModel *q_ptr;
+ Q_DECLARE_PUBLIC(QtResourceModel)
+ Q_DISABLE_COPY(QtResourceModelPrivate)
+public:
+ QtResourceModelPrivate();
+ void activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCount = 0, QString *errorMessages = 0);
+ void removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths);
+
+ QMap<QString, bool> m_pathToModified;
+ QMap<QtResourceSet *, QStringList> m_resourceSetToPaths;
+ QMap<QtResourceSet *, bool> m_resourceSetToReload; // while path is recreated it needs to be reregistered
+ // (it is - in the new current resource set, but when the path was used in
+ // other resource set
+ // then later when that resource set is activated it needs to be reregistered)
+ QMap<QtResourceSet *, bool> m_newlyCreated; // all created but not activated yet
+ // (if was active at some point and it's not now it will not be on that map)
+ QMap<QString, QList<QtResourceSet *> > m_pathToResourceSet;
+ QtResourceSet *m_currentResourceSet;
+
+ typedef QMap<QString, const QByteArray *> PathDataMap;
+ PathDataMap m_pathToData;
+
+ QMap<QString, QStringList> m_pathToContents; // qrc path to its contents.
+ QMap<QString, QString> m_fileToQrc; // this map contains the content of active resource set only.
+ // Activating different resource set changes the contents.
+
+ QFileSystemWatcher *m_fileWatcher;
+ bool m_fileWatcherEnabled;
+ QMap<QString, bool> m_fileWatchedMap;
+private:
+ void registerResourceSet(QtResourceSet *resourceSet);
+ void unregisterResourceSet(QtResourceSet *resourceSet);
+ void setWatcherEnabled(const QString &path, bool enable);
+ void addWatcher(const QString &path);
+ void removeWatcher(const QString &path);
+
+ void slotFileChanged(const QString &);
+
+ const QByteArray *createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const;
+ void deleteResource(const QByteArray *data) const;
+};
+
+QtResourceModelPrivate::QtResourceModelPrivate() :
+ q_ptr(0),
+ m_currentResourceSet(0),
+ m_fileWatcher(0),
+ m_fileWatcherEnabled(true)
+{
+}
+
+// --------------------- QtResourceSet
+QtResourceSet::QtResourceSet() :
+ d_ptr(new QtResourceSetPrivate)
+{
+ d_ptr->q_ptr = this;
+}
+
+QtResourceSet::QtResourceSet(QtResourceModel *model) :
+ d_ptr(new QtResourceSetPrivate(model))
+{
+ d_ptr->q_ptr = this;
+}
+
+QtResourceSet::~QtResourceSet()
+{
+ delete d_ptr;
+}
+
+QStringList QtResourceSet::activeQrcPaths() const
+{
+ QtResourceSet *that = const_cast<QtResourceSet *>(this);
+ return d_ptr->m_resourceModel->d_ptr->m_resourceSetToPaths.value(that);
+}
+
+void QtResourceSet::activateQrcPaths(const QStringList &paths, int *errorCount, QString *errorMessages)
+{
+ d_ptr->m_resourceModel->d_ptr->activate(this, paths, errorCount, errorMessages);
+}
+
+bool QtResourceSet::isModified(const QString &path) const
+{
+ return d_ptr->m_resourceModel->isModified(path);
+}
+
+void QtResourceSet::setModified(const QString &path)
+{
+ d_ptr->m_resourceModel->setModified(path);
+}
+
+// ------------------- QtResourceModelPrivate
+const QByteArray *QtResourceModelPrivate::createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const
+{
+ typedef RCCResourceLibrary::ResourceDataFileMap ResourceDataFileMap;
+ const QByteArray *rc = 0;
+ *errorCount = -1;
+ contents->clear();
+ do {
+ // run RCC
+ RCCResourceLibrary library;
+ library.setVerbose(true);
+ library.setInputFiles(QStringList(path));
+ library.setFormat(RCCResourceLibrary::Binary);
+
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ if (!library.readFiles(/* ignore errors*/ true, errorDevice))
+ break;
+ // return code cannot be fully trusted, might still be empty
+ const ResourceDataFileMap resMap = library.resourceDataFileMap();
+ if (resMap.empty())
+ break;
+
+ if (!library.output(buffer, errorDevice))
+ break;
+
+ *errorCount = library.failedResources().size();
+ *contents = resMap.keys();
+
+ buffer.close();
+ rc = new QByteArray(buffer.data());
+ } while (false);
+
+ if (debugResourceModel)
+ qDebug() << "createResource" << path << "returns data=" << rc << " hasWarnings=" << *errorCount;
+ return rc;
+}
+
+void QtResourceModelPrivate::deleteResource(const QByteArray *data) const
+{
+ if (data) {
+ if (debugResourceModel)
+ qDebug() << "deleteResource";
+ delete data;
+ }
+}
+
+void QtResourceModelPrivate::registerResourceSet(QtResourceSet *resourceSet)
+{
+ if (!resourceSet)
+ return;
+
+ // unregister old paths (all because the order of registration is important), later it can be optimized a bit
+ QStringList toRegister = resourceSet->activeQrcPaths();
+ QStringListIterator itRegister(toRegister);
+ while (itRegister.hasNext()) {
+ const QString path = itRegister.next();
+ if (debugResourceModel)
+ qDebug() << "registerResourceSet " << path;
+ const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path);
+ if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet
+ if (!QResource::registerResource(reinterpret_cast<const uchar *>(itRcc.value()->constData()))) {
+ qDebug() << "** WARNING: Failed to register " << path << " (QResource failure).";
+ } else {
+ QStringList contents = m_pathToContents.value(path);
+ QStringListIterator itContents(contents);
+ while (itContents.hasNext()) {
+ const QString filePath = itContents.next();
+ if (!m_fileToQrc.contains(filePath)) // the first loaded resource has higher priority in qt resource system
+ m_fileToQrc.insert(filePath, path);
+ }
+ }
+ }
+ }
+}
+
+void QtResourceModelPrivate::unregisterResourceSet(QtResourceSet *resourceSet)
+{
+ if (!resourceSet)
+ return;
+
+ // unregister old paths (all because the order of registration is importans), later it can be optimized a bit
+ QStringList toUnregister = resourceSet->activeQrcPaths();
+ QStringListIterator itUnregister(toUnregister);
+ while (itUnregister.hasNext()) {
+ const QString path = itUnregister.next();
+ if (debugResourceModel)
+ qDebug() << "unregisterResourceSet " << path;
+ const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path);
+ if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet
+ if (!QResource::unregisterResource(reinterpret_cast<const uchar *>(itRcc.value()->constData())))
+ qDebug() << "** WARNING: Failed to unregister " << path << " (QResource failure).";
+ }
+ }
+ m_fileToQrc.clear();
+}
+
+void QtResourceModelPrivate::activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCountPtr, QString *errorMessages)
+{
+ if (debugResourceModel)
+ qDebug() << "activate " << resourceSet;
+ if (errorCountPtr)
+ *errorCountPtr = 0;
+ if (errorMessages)
+ errorMessages->clear();
+
+ QBuffer errorStream;
+ errorStream.open(QIODevice::WriteOnly);
+
+ int errorCount = 0;
+ int generatedCount = 0;
+ bool newResourceSetChanged = false;
+
+ if (resourceSet && resourceSet->activeQrcPaths() != newPaths && !m_newlyCreated.contains(resourceSet))
+ newResourceSetChanged = true;
+
+ PathDataMap newPathToData = m_pathToData;
+
+ QStringListIterator itPath(newPaths);
+ while (itPath.hasNext()) {
+ const QString path = itPath.next();
+ if (resourceSet && !m_pathToResourceSet[path].contains(resourceSet))
+ m_pathToResourceSet[path].append(resourceSet);
+ const QMap<QString, bool>::iterator itMod = m_pathToModified.find(path);
+ if (itMod == m_pathToModified.end() || itMod.value()) { // new path or path is already created, but needs to be recreated
+ QStringList contents;
+ int qrcErrorCount;
+ generatedCount++;
+ if (const QByteArray *data = createResource(path, &contents, &qrcErrorCount, errorStream)) {
+ newPathToData.insert(path, data);
+ if (qrcErrorCount) // Count single failed files as sort of 1/2 error
+ errorCount++;
+ addWatcher(path);
+ } else {
+ newPathToData.remove(path);
+ errorCount++;
+ }
+ m_pathToModified.insert(path, false);
+ m_pathToContents.insert(path, contents);
+ newResourceSetChanged = true;
+ const QMap<QString, QList<QtResourceSet *> >::iterator itReload = m_pathToResourceSet.find(path);
+ if (itReload != m_pathToResourceSet.end()) {
+ QList<QtResourceSet *> resources = itReload.value();
+ QListIterator<QtResourceSet *> itRes(resources);
+ while (itRes.hasNext()) {
+ QtResourceSet *res = itRes.next();
+ if (res != resourceSet) {
+ m_resourceSetToReload[res] = true;
+ }
+ }
+ }
+ } else { // path is already created, don't need to recreate
+ }
+ }
+
+ QList<const QByteArray *> oldData = m_pathToData.values();
+ QList<const QByteArray *> newData = newPathToData.values();
+
+ QList<const QByteArray *> toDelete;
+ QListIterator<const QByteArray *> itOld(oldData);
+ if (itOld.hasNext()) {
+ const QByteArray *array = itOld.next();
+ if (!newData.contains(array))
+ toDelete.append(array);
+ }
+
+ // Nothing can fail below here?
+ if (generatedCount) {
+ if (errorCountPtr)
+ *errorCountPtr = errorCount;
+ errorStream.close();
+ const QString stderrOutput = QString::fromUtf8(errorStream.data());
+ if (debugResourceModel)
+ qDebug() << "Output: (" << errorCount << ")\n" << stderrOutput;
+ if (errorMessages)
+ *errorMessages = stderrOutput;
+ }
+ // register
+ const QMap<QtResourceSet *, bool>::iterator itReload = m_resourceSetToReload.find(resourceSet);
+ if (itReload != m_resourceSetToReload.end()) {
+ if (itReload.value()) {
+ newResourceSetChanged = true;
+ m_resourceSetToReload.insert(resourceSet, false);
+ }
+ }
+
+ QStringList oldActivePaths;
+ if (m_currentResourceSet)
+ oldActivePaths = m_currentResourceSet->activeQrcPaths();
+
+ const bool needReregister = (oldActivePaths != newPaths) || newResourceSetChanged;
+
+ QMap<QtResourceSet *, bool>::iterator itNew = m_newlyCreated.find(resourceSet);
+ if (itNew != m_newlyCreated.end()) {
+ m_newlyCreated.remove(resourceSet);
+ if (needReregister)
+ newResourceSetChanged = true;
+ }
+
+ if (!newResourceSetChanged && !needReregister && (m_currentResourceSet == resourceSet)) {
+ foreach (const QByteArray *data, toDelete)
+ deleteResource(data);
+
+ return; // nothing changed
+ }
+
+ if (needReregister)
+ unregisterResourceSet(m_currentResourceSet);
+
+ foreach (const QByteArray *data, toDelete)
+ deleteResource(data);
+
+ m_pathToData = newPathToData;
+ m_currentResourceSet = resourceSet;
+
+ if (resourceSet)
+ removeOldPaths(resourceSet, newPaths);
+
+ if (needReregister)
+ registerResourceSet(m_currentResourceSet);
+
+ emit q_ptr->resourceSetActivated(m_currentResourceSet, newResourceSetChanged);
+
+ // deactivates the paths from old current resource set
+ // add new paths to the new current resource set
+ // reloads all paths which are marked as modified from the current resource set;
+ // activates the paths from current resource set
+ // emits resourceSetActivated() (don't emit only in case when old resource set is the same as new one
+ // AND no path was reloaded AND the list of paths is exactly the same)
+}
+
+void QtResourceModelPrivate::removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths)
+{
+ QStringList oldPaths = m_resourceSetToPaths.value(resourceSet);
+ if (oldPaths != newPaths) {
+ // remove old
+ QStringListIterator itOldPaths(oldPaths);
+ while (itOldPaths.hasNext()) {
+ QString oldPath = itOldPaths.next();
+ if (!newPaths.contains(oldPath)) {
+ const QMap<QString, QList<QtResourceSet *> >::iterator itRemove = m_pathToResourceSet.find(oldPath);
+ if (itRemove != m_pathToResourceSet.end()) {
+ const int idx = itRemove.value().indexOf(resourceSet);
+ if (idx >= 0)
+ itRemove.value().removeAt(idx);
+ if (itRemove.value().count() == 0) {
+ PathDataMap::iterator it = m_pathToData.find(oldPath);
+ if (it != m_pathToData.end())
+ deleteResource(it.value());
+ m_pathToResourceSet.erase(itRemove);
+ m_pathToModified.remove(oldPath);
+ m_pathToContents.remove(oldPath);
+ m_pathToData.remove(oldPath);
+ removeWatcher(oldPath);
+ }
+ }
+ }
+ }
+ m_resourceSetToPaths[resourceSet] = newPaths;
+ }
+}
+
+void QtResourceModelPrivate::setWatcherEnabled(const QString &path, bool enable)
+{
+ m_fileWatcher->removePath(path);
+
+ if (!enable)
+ return;
+
+ QFileInfo fi(path);
+ if (fi.exists())
+ m_fileWatcher->addPath(path);
+}
+
+void QtResourceModelPrivate::addWatcher(const QString &path)
+{
+ QMap<QString, bool>::ConstIterator it = m_fileWatchedMap.constFind(path);
+ if (it != m_fileWatchedMap.constEnd() && it.value() == false)
+ return;
+
+ m_fileWatchedMap.insert(path, true);
+ if (!m_fileWatcherEnabled)
+ return;
+ setWatcherEnabled(path, true);
+}
+
+void QtResourceModelPrivate::removeWatcher(const QString &path)
+{
+ if (!m_fileWatchedMap.contains(path))
+ return;
+
+ m_fileWatchedMap.remove(path);
+ if (!m_fileWatcherEnabled)
+ return;
+ setWatcherEnabled(path, false);
+}
+
+void QtResourceModelPrivate::slotFileChanged(const QString &path)
+{
+ setWatcherEnabled(path, false);
+ emit q_ptr->qrcFileModifiedExternally(path);
+ setWatcherEnabled(path, true); //readd
+}
+
+// ----------------------- QtResourceModel
+QtResourceModel::QtResourceModel(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QtResourceModelPrivate)
+{
+ d_ptr->q_ptr = this;
+
+ d_ptr->m_fileWatcher = new QFileSystemWatcher(this);
+ connect(d_ptr->m_fileWatcher, SIGNAL(fileChanged(const QString &)),
+ this, SLOT(slotFileChanged(const QString &)));
+}
+
+QtResourceModel::~QtResourceModel()
+{
+ blockSignals(true);
+ QList<QtResourceSet *> resourceList = resourceSets();
+ QListIterator<QtResourceSet *> it(resourceList);
+ while (it.hasNext())
+ removeResourceSet(it.next());
+ blockSignals(false);
+ delete d_ptr;
+}
+
+QStringList QtResourceModel::loadedQrcFiles() const
+{
+ return d_ptr->m_pathToModified.keys();
+}
+
+bool QtResourceModel::isModified(const QString &path) const
+{
+ QMap<QString, bool>::const_iterator it = d_ptr->m_pathToModified.find(path);
+ if (it != d_ptr->m_pathToModified.constEnd())
+ return it.value();
+ return true;
+}
+
+void QtResourceModel::setModified(const QString &path)
+{
+ QMap<QString, bool>::const_iterator itMod = d_ptr->m_pathToModified.find(path);
+ if (itMod == d_ptr->m_pathToModified.constEnd())
+ return;
+
+ d_ptr->m_pathToModified[path] = true;
+ QMap<QString, QList<QtResourceSet *> >::const_iterator it = d_ptr->m_pathToResourceSet.constFind(path);
+ if (it == d_ptr->m_pathToResourceSet.constEnd())
+ return;
+
+ QList<QtResourceSet *> resourceList = it.value();
+ QListIterator<QtResourceSet *> itReload(resourceList);
+ while (itReload.hasNext())
+ d_ptr->m_resourceSetToReload.insert(itReload.next(), true);
+}
+
+QList<QtResourceSet *> QtResourceModel::resourceSets() const
+{
+ return d_ptr->m_resourceSetToPaths.keys();
+}
+
+QtResourceSet *QtResourceModel::currentResourceSet() const
+{
+ return d_ptr->m_currentResourceSet;
+}
+
+void QtResourceModel::setCurrentResourceSet(QtResourceSet *resourceSet, int *errorCount, QString *errorMessages)
+{
+ d_ptr->activate(resourceSet, d_ptr->m_resourceSetToPaths.value(resourceSet), errorCount, errorMessages);
+}
+
+QtResourceSet *QtResourceModel::addResourceSet(const QStringList &paths)
+{
+ QtResourceSet *newResource = new QtResourceSet(this);
+ d_ptr->m_resourceSetToPaths.insert(newResource, paths);
+ d_ptr->m_resourceSetToReload.insert(newResource, false);
+ d_ptr->m_newlyCreated.insert(newResource, true);
+ QStringListIterator it(paths);
+ while (it.hasNext()) {
+ const QString path = it.next();
+ d_ptr->m_pathToResourceSet[path].append(newResource);
+ }
+ return newResource;
+}
+
+// TODO
+void QtResourceModel::removeResourceSet(QtResourceSet *resourceSet)
+{
+ if (!resourceSet)
+ return;
+ if (currentResourceSet() == resourceSet)
+ setCurrentResourceSet(0);
+
+ // remove rcc files for those paths which are not used in any other resource set
+ d_ptr->removeOldPaths(resourceSet, QStringList());
+
+ d_ptr->m_resourceSetToPaths.remove(resourceSet);
+ d_ptr->m_resourceSetToReload.remove(resourceSet);
+ d_ptr->m_newlyCreated.remove(resourceSet);
+ delete resourceSet;
+}
+
+void QtResourceModel::reload(const QString &path, int *errorCount, QString *errorMessages)
+{
+ setModified(path);
+
+ d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages);
+}
+
+void QtResourceModel::reload(int *errorCount, QString *errorMessages)
+{
+ QMap<QString, bool>::iterator it = d_ptr->m_pathToModified.begin();
+ QMap<QString, bool>::iterator itEnd = d_ptr->m_pathToModified.end(); // will it be valid when I iterate the map and change it???
+ while (it != itEnd) {
+ it = d_ptr->m_pathToModified.insert(it.key(), true);
+ ++it;
+ }
+
+ QMap<QtResourceSet *, bool>::iterator itReload = d_ptr->m_resourceSetToReload.begin();
+ QMap<QtResourceSet *, bool>::iterator itReloadEnd = d_ptr->m_resourceSetToReload.end();
+ while (itReload != itReloadEnd) {
+ itReload = d_ptr->m_resourceSetToReload.insert(itReload.key(), true); // empty resourceSets could be omitted here
+ ++itReload;
+ }
+
+ d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages);
+}
+
+QMap<QString, QString> QtResourceModel::contents() const
+{
+ return d_ptr->m_fileToQrc;
+}
+
+QString QtResourceModel::qrcPath(const QString &file) const
+{
+ return d_ptr->m_fileToQrc.value(file);
+}
+
+void QtResourceModel::setWatcherEnabled(bool enable)
+{
+ if (d_ptr->m_fileWatcherEnabled == enable)
+ return;
+
+ d_ptr->m_fileWatcherEnabled = enable;
+
+ QMapIterator<QString, bool> it(d_ptr->m_fileWatchedMap);
+ if (it.hasNext())
+ d_ptr->setWatcherEnabled(it.next().key(), d_ptr->m_fileWatcherEnabled);
+}
+
+bool QtResourceModel::isWatcherEnabled() const
+{
+ return d_ptr->m_fileWatcherEnabled;
+}
+
+void QtResourceModel::setWatcherEnabled(const QString &path, bool enable)
+{
+ QMap<QString, bool>::Iterator it = d_ptr->m_fileWatchedMap.find(path);
+ if (it == d_ptr->m_fileWatchedMap.end())
+ return;
+
+ if (it.value() == enable)
+ return;
+
+ it.value() = enable;
+
+ if (!d_ptr->m_fileWatcherEnabled)
+ return;
+
+ d_ptr->setWatcherEnabled(it.key(), enable);
+}
+
+bool QtResourceModel::isWatcherEnabled(const QString &path)
+{
+ return d_ptr->m_fileWatchedMap.value(path, false);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtresourcemodel_p.cpp"
diff --git a/tools/designer/src/lib/shared/qtresourcemodel_p.h b/tools/designer/src/lib/shared/qtresourcemodel_p.h
new file mode 100644
index 0000000..726db29
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourcemodel_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** 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 QTRESOURCEMODEL_H
+#define QTRESOURCEMODEL_H
+
+#include "shared_global_p.h"
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QtResourceModel;
+
+class QDESIGNER_SHARED_EXPORT QtResourceSet // one instance per one form
+{
+public:
+ QStringList activeQrcPaths() const;
+
+ // activateQrcPaths(): if this QtResourceSet is active it emits resourceSetActivated();
+ // otherwise only in case if active QtResource set contains one of
+ // paths which was marked as modified by this resource set, the signal
+ // is emitted (with reload = true);
+ // If new path appears on the list it is automatically added to
+ // loaded list of QtResourceModel. In addition it is marked as modified in case
+ // QtResourceModel didn't contain the path.
+ // If some path is removed from that list (and is not used in any other
+ // resource set) it is automatically unloaded. The removed file can also be
+ // marked as modified (later when another resource set which contains
+ // removed path is activated will be reloaded)
+ void activateQrcPaths(const QStringList &paths, int *errorCount = 0, QString *errorMessages = 0);
+
+ bool isModified(const QString &path) const; // for all paths in resource model (redundant here, maybe it should be removed from here)
+ void setModified(const QString &path); // for all paths in resource model (redundant here, maybe it should be removed from here)
+private:
+ QtResourceSet();
+ QtResourceSet(QtResourceModel *model);
+ ~QtResourceSet();
+ friend class QtResourceModel;
+
+ class QtResourceSetPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QtResourceSet)
+ Q_DISABLE_COPY(QtResourceSet)
+};
+
+class QDESIGNER_SHARED_EXPORT QtResourceModel : public QObject // one instance per whole designer
+{
+ Q_OBJECT
+public:
+ QtResourceModel(QObject *parent = 0);
+ ~QtResourceModel();
+
+ QStringList loadedQrcFiles() const;
+ bool isModified(const QString &path) const; // only for paths which are on loadedQrcFiles() list
+ void setModified(const QString &path); // only for paths which are on loadedQrcPaths() list
+
+ QList<QtResourceSet *> resourceSets() const;
+
+ QtResourceSet *currentResourceSet() const;
+ void setCurrentResourceSet(QtResourceSet *resourceSet, int *errorCount = 0, QString *errorMessages = 0);
+
+ QtResourceSet *addResourceSet(const QStringList &paths);
+ void removeResourceSet(QtResourceSet *resourceSet);
+
+ void reload(const QString &path, int *errorCount = 0, QString *errorMessages = 0);
+ void reload(int *errorCount = 0, QString *errorMessages = 0);
+
+ // Contents of the current resource set (content file to qrc path)
+ QMap<QString, QString> contents() const;
+ // Find the qrc file belonging to the contained file (from current resource set)
+ QString qrcPath(const QString &file) const;
+
+ void setWatcherEnabled(bool enable);
+ bool isWatcherEnabled() const;
+
+ void setWatcherEnabled(const QString &path, bool enable);
+ bool isWatcherEnabled(const QString &path);
+
+signals:
+ void resourceSetActivated(QtResourceSet *resourceSet, bool resourceSetChanged); // resourceSetChanged since last time it was activated!
+ void qrcFileModifiedExternally(const QString &path);
+
+private:
+ friend class QtResourceSet;
+
+ class QtResourceModelPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QtResourceModel)
+ Q_DISABLE_COPY(QtResourceModel)
+
+ Q_PRIVATE_SLOT(d_func(), void slotFileChanged(const QString &))
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/qtresourceview.cpp b/tools/designer/src/lib/shared/qtresourceview.cpp
new file mode 100644
index 0000000..d956491
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourceview.cpp
@@ -0,0 +1,766 @@
+/****************************************************************************
+**
+** 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 "abstractsettings_p.h"
+#include "qtresourceview_p.h"
+#include "qtresourcemodel_p.h"
+#include "qtresourceeditordialog_p.h"
+#include "iconloader_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtGui/QToolBar>
+#include <QtGui/QAction>
+#include <QtGui/QSplitter>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QListWidget>
+#include <QtGui/QHeaderView>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QPainter>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QQueue>
+#include <QtGui/QPainter>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QPushButton>
+#include <QtGui/QMessageBox>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QMenu>
+#include <QtGui/QDrag>
+#include <QtCore/QMimeData>
+#include <QtXml/QDomDocument>
+
+QT_BEGIN_NAMESPACE
+
+static const char *elementResourceData = "resource";
+static const char *typeAttribute = "type";
+static const char *typeImage = "image";
+static const char *typeStyleSheet = "stylesheet";
+static const char *typeOther = "other";
+static const char *fileAttribute = "file";
+static const char *SplitterPosition = "SplitterPosition";
+static const char *Geometry = "Geometry";
+static const char *ResourceViewDialogC = "ResourceDialog";
+
+// ---------------- ResourceListWidget: A list widget that has drag enabled
+class ResourceListWidget : public QListWidget {
+public:
+ ResourceListWidget(QWidget *parent = 0);
+
+protected:
+ virtual void startDrag(Qt::DropActions supportedActions);
+};
+
+ResourceListWidget::ResourceListWidget(QWidget *parent) :
+ QListWidget(parent)
+{
+ setDragEnabled(true);
+}
+
+void ResourceListWidget::startDrag(Qt::DropActions supportedActions)
+{
+ if (supportedActions == Qt::MoveAction)
+ return;
+
+ QListWidgetItem *item = currentItem();
+ if (!item)
+ return;
+
+ const QString filePath = item->data(Qt::UserRole).toString();
+ const QIcon icon = item->icon();
+
+ QMimeData *mimeData = new QMimeData;
+ const QtResourceView::ResourceType type = icon.isNull() ? QtResourceView::ResourceOther : QtResourceView::ResourceImage;
+ mimeData->setText(QtResourceView::encodeMimeData(type , filePath));
+
+ QDrag *drag = new QDrag(this);
+ if (!icon.isNull()) {
+ const QSize size = icon.actualSize(iconSize());
+ drag->setPixmap(icon.pixmap(size));
+ drag->setHotSpot(QPoint(size.width() / 2, size.height() / 2));
+ }
+
+ drag->setMimeData(mimeData);
+ drag->exec(Qt::CopyAction);
+}
+
+/* TODO
+
+ 1) load the icons in separate thread...Hmm..if Qt is configured with threads....
+*/
+
+// ---------------------------- QtResourceViewPrivate
+class QtResourceViewPrivate
+{
+ QtResourceView *q_ptr;
+ Q_DECLARE_PUBLIC(QtResourceView)
+public:
+ QtResourceViewPrivate(QDesignerFormEditorInterface *core);
+
+ void slotResourceSetActivated(QtResourceSet *resourceSet);
+ void slotCurrentPathChanged(QTreeWidgetItem *);
+ void slotCurrentResourceChanged(QListWidgetItem *);
+ void slotResourceActivated(QListWidgetItem *);
+ void slotEditResources();
+ void slotReloadResources();
+ void slotCopyResourcePath();
+ void slotListWidgetContextMenuRequested(const QPoint &pos);
+ void createPaths();
+ QTreeWidgetItem *createPath(const QString &path, QTreeWidgetItem *parent);
+ void createResources(const QString &path);
+ void storeExpansionState();
+ void applyExpansionState();
+ void restoreSettings();
+ void saveSettings();
+ void updateActions();
+
+ QPixmap makeThumbnail(const QPixmap &pix) const;
+
+ QDesignerFormEditorInterface *m_core;
+ QtResourceModel *m_resourceModel;
+ QToolBar *m_toolBar;
+ QTreeWidget *m_treeWidget;
+ QListWidget *m_listWidget;
+ QSplitter *m_splitter;
+ QMap<QString, QStringList> m_pathToContents; // full path to contents file names
+ QMap<QString, QTreeWidgetItem *> m_pathToItem;
+ QMap<QTreeWidgetItem *, QString> m_itemToPath;
+ QMap<QString, QListWidgetItem *> m_resourceToItem;
+ QMap<QListWidgetItem *, QString> m_itemToResource;
+ QAction *m_editResourcesAction;
+ QAction *m_reloadResourcesAction;
+ QAction *m_copyResourcePathAction;
+
+ QMap<QString, bool> m_expansionState;
+
+ bool m_ignoreGuiSignals;
+ QString m_settingsKey;
+ bool m_resourceEditingEnabled;
+};
+
+QtResourceViewPrivate::QtResourceViewPrivate(QDesignerFormEditorInterface *core) :
+ q_ptr(0),
+ m_core(core),
+ m_resourceModel(0),
+ m_toolBar(new QToolBar),
+ m_treeWidget(new QTreeWidget),
+ m_listWidget(new ResourceListWidget),
+ m_splitter(0),
+ m_editResourcesAction(0),
+ m_reloadResourcesAction(0),
+ m_copyResourcePathAction(0),
+ m_ignoreGuiSignals(false),
+ m_resourceEditingEnabled(true)
+{
+}
+
+void QtResourceViewPrivate::restoreSettings()
+{
+ if (m_settingsKey.isEmpty())
+ return;
+
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->beginGroup(m_settingsKey);
+
+ m_splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray());
+ settings->endGroup();
+}
+
+void QtResourceViewPrivate::saveSettings()
+{
+ if (m_settingsKey.isEmpty())
+ return;
+
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->beginGroup(m_settingsKey);
+
+ settings->setValue(QLatin1String(SplitterPosition), m_splitter->saveState());
+ settings->endGroup();
+}
+
+void QtResourceViewPrivate::slotEditResources()
+{
+ const QString selectedResource
+ = QtResourceEditorDialog::editResources(m_core, m_resourceModel,
+ m_core->dialogGui(), q_ptr);
+ if (!selectedResource.isEmpty())
+ q_ptr->selectResource(selectedResource);
+}
+
+void QtResourceViewPrivate::slotReloadResources()
+{
+ if (m_resourceModel) {
+ int errorCount;
+ QString errorMessages;
+ m_resourceModel->reload(&errorCount, &errorMessages);
+ if (errorCount)
+ QtResourceEditorDialog::displayResourceFailures(errorMessages, m_core->dialogGui(), q_ptr);
+ }
+}
+
+void QtResourceViewPrivate::slotCopyResourcePath()
+{
+ const QString path = q_ptr->selectedResource();
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setText(path);
+}
+
+void QtResourceViewPrivate::slotListWidgetContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu(q_ptr);
+ menu.addAction(m_copyResourcePathAction);
+ menu.exec(m_listWidget->mapToGlobal(pos));
+}
+
+void QtResourceViewPrivate::storeExpansionState()
+{
+ QMapIterator<QString, QTreeWidgetItem *> it(m_pathToItem);
+ while (it.hasNext()) {
+ it.next();
+ m_expansionState[it.key()] = it.value()->isExpanded();
+ }
+}
+
+void QtResourceViewPrivate::applyExpansionState()
+{
+ QMapIterator<QString, QTreeWidgetItem *> it(m_pathToItem);
+ while (it.hasNext()) {
+ it.next();
+ it.value()->setExpanded(m_expansionState.value(it.key(), true));
+ }
+}
+
+QPixmap QtResourceViewPrivate::makeThumbnail(const QPixmap &pix) const
+{
+ int w = qMax(48, pix.width());
+ int h = qMax(48, pix.height());
+ QRect imgRect(0, 0, w, h);
+ QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ if (!pix.isNull()) {
+ QRect r(0, 0, pix.width(), pix.height());
+ r.moveCenter(imgRect.center());
+ QPainter p(&img);
+ p.drawPixmap(r.topLeft(), pix);
+ }
+ return QPixmap::fromImage(img);
+}
+
+void QtResourceViewPrivate::updateActions()
+{
+ bool resourceActive = false;
+ if (m_resourceModel)
+ resourceActive = m_resourceModel->currentResourceSet();
+
+ m_editResourcesAction->setVisible(m_resourceEditingEnabled);
+ m_editResourcesAction->setEnabled(resourceActive);
+ m_reloadResourcesAction->setEnabled(resourceActive);
+}
+
+void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet)
+{
+ Q_UNUSED(resourceSet)
+
+ updateActions();
+
+ storeExpansionState();
+ const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem());
+ const QString currentResource = m_itemToResource.value(m_listWidget->currentItem());
+ m_treeWidget->clear();
+ m_pathToContents.clear();
+ m_pathToItem.clear();
+ m_itemToPath.clear();
+ m_listWidget->clear();
+ m_resourceToItem.clear();
+ m_itemToResource.clear();
+
+ createPaths();
+ applyExpansionState();
+
+ if (!currentResource.isEmpty())
+ q_ptr->selectResource(currentResource);
+ else if (!currentPath.isEmpty())
+ q_ptr->selectResource(currentPath);
+}
+
+void QtResourceViewPrivate::slotCurrentPathChanged(QTreeWidgetItem *item)
+{
+ if (m_ignoreGuiSignals)
+ return;
+
+ m_listWidget->clear();
+ m_resourceToItem.clear();
+ m_itemToResource.clear();
+
+ if (!item)
+ return;
+
+ const QString currentPath = m_itemToPath.value(item);
+ createResources(currentPath);
+}
+
+void QtResourceViewPrivate::slotCurrentResourceChanged(QListWidgetItem *item)
+{
+ m_copyResourcePathAction->setEnabled(item);
+ if (m_ignoreGuiSignals)
+ return;
+
+ emit q_ptr->resourceSelected(m_itemToResource.value(item));
+}
+
+void QtResourceViewPrivate::slotResourceActivated(QListWidgetItem *item)
+{
+ if (m_ignoreGuiSignals)
+ return;
+
+ emit q_ptr->resourceActivated(m_itemToResource.value(item));
+}
+
+void QtResourceViewPrivate::createPaths()
+{
+ if (!m_resourceModel)
+ return;
+
+ const QString root(QLatin1Char(':'));
+
+ QMap<QString, QString> pathToParentPath; // full path to full parent path
+ QMap<QString, QStringList> pathToSubPaths; // full path to full sub paths
+
+ QMap<QString, QString> contents = m_resourceModel->contents();
+ QMapIterator<QString, QString> itContents(contents);
+ while (itContents.hasNext()) {
+ const QString filePath = itContents.next().key();
+ const QFileInfo fi(filePath);
+ QString dirPath = fi.absolutePath();
+ m_pathToContents[dirPath].append(fi.fileName());
+ while (!pathToParentPath.contains(dirPath) && dirPath != root) {
+ const QFileInfo fd(dirPath);
+ const QString parentDirPath = fd.absolutePath();
+ pathToParentPath[dirPath] = parentDirPath;
+ pathToSubPaths[parentDirPath].append(dirPath);
+ dirPath = parentDirPath;
+ }
+ }
+
+ QQueue<QPair<QString, QTreeWidgetItem *> > pathToParentItemQueue;
+ pathToParentItemQueue.enqueue(qMakePair(root, static_cast<QTreeWidgetItem *>(0)));
+ while (!pathToParentItemQueue.isEmpty()) {
+ QPair<QString, QTreeWidgetItem *> pathToParentItem = pathToParentItemQueue.dequeue();
+ const QString path = pathToParentItem.first;
+ QTreeWidgetItem *item = createPath(path, pathToParentItem.second);
+ QStringList subPaths = pathToSubPaths.value(path);
+ QStringListIterator itSubPaths(subPaths);
+ while (itSubPaths.hasNext())
+ pathToParentItemQueue.enqueue(qMakePair(itSubPaths.next(), item));
+ }
+}
+
+QTreeWidgetItem *QtResourceViewPrivate::createPath(const QString &path, QTreeWidgetItem *parent)
+{
+ QTreeWidgetItem *item = 0;
+ if (parent)
+ item = new QTreeWidgetItem(parent);
+ else
+ item = new QTreeWidgetItem(m_treeWidget);
+ m_pathToItem[path] = item;
+ m_itemToPath[item] = path;
+ QString substPath;
+ if (parent) {
+ QFileInfo di(path);
+ substPath = di.fileName();
+ } else {
+ substPath = QLatin1String("<resource root>");
+ }
+ item->setText(0, substPath);
+ item->setToolTip(0, path);
+ return item;
+}
+
+void QtResourceViewPrivate::createResources(const QString &path)
+{
+ QDir dir(path);
+ QStringList files = m_pathToContents.value(path);
+ QStringListIterator it(files);
+ while (it.hasNext()) {
+ QString file = it.next();
+ QString filePath = dir.absoluteFilePath(file);
+ QFileInfo fi(filePath);
+ if (fi.isFile()) {
+ QListWidgetItem *item = new QListWidgetItem(fi.fileName(), m_listWidget);
+ const QPixmap pix = QPixmap(filePath);
+ if (pix.isNull()) {
+ item->setToolTip(filePath);
+ } else {
+ item->setIcon(QIcon(makeThumbnail(pix)));
+ const QSize size = pix.size();
+ item->setToolTip(QtResourceView::tr("Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath));
+ }
+ item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
+ item->setData(Qt::UserRole, filePath);
+ m_itemToResource[item] = filePath;
+ m_resourceToItem[filePath] = item;
+ }
+ }
+}
+
+// -------------- QtResourceView
+
+QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent) :
+ QWidget(parent),
+ d_ptr(new QtResourceViewPrivate(core))
+{
+ d_ptr->q_ptr = this;
+
+ d_ptr->m_editResourcesAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("edit.png")), tr("Edit Resources..."), this);
+ d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction);
+ connect(d_ptr->m_editResourcesAction, SIGNAL(triggered()), this, SLOT(slotEditResources()));
+ d_ptr->m_editResourcesAction->setEnabled(false);
+
+ d_ptr->m_reloadResourcesAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("reload.png")), tr("Reload"), this);
+ d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction);
+ connect(d_ptr->m_reloadResourcesAction, SIGNAL(triggered()), this, SLOT(slotReloadResources()));
+ d_ptr->m_reloadResourcesAction->setEnabled(false);
+
+ d_ptr->m_copyResourcePathAction = new QAction(qdesigner_internal::createIconSet(QLatin1String("editcopy.png")), tr("Copy Path"), this);
+ connect(d_ptr->m_copyResourcePathAction, SIGNAL(triggered()), this, SLOT(slotCopyResourcePath()));
+ d_ptr->m_copyResourcePathAction->setEnabled(false);
+
+ d_ptr->m_splitter = new QSplitter;
+ d_ptr->m_splitter->setChildrenCollapsible(false);
+ d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget);
+ d_ptr->m_splitter->addWidget(d_ptr->m_listWidget);
+
+ QLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(d_ptr->m_toolBar);
+ layout->addWidget(d_ptr->m_splitter);
+
+ d_ptr->m_treeWidget->setColumnCount(1);
+ d_ptr->m_treeWidget->header()->hide();
+ d_ptr->m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
+
+ d_ptr->m_listWidget->setViewMode(QListView::IconMode);
+ d_ptr->m_listWidget->setResizeMode(QListView::Adjust);
+ d_ptr->m_listWidget->setIconSize(QSize(48, 48));
+ d_ptr->m_listWidget->setGridSize(QSize(64, 64));
+
+ connect(d_ptr->m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(slotCurrentPathChanged(QTreeWidgetItem *)));
+ connect(d_ptr->m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this, SLOT(slotCurrentResourceChanged(QListWidgetItem *)));
+ connect(d_ptr->m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)),
+ this, SLOT(slotResourceActivated(QListWidgetItem *)));
+ d_ptr->m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(d_ptr->m_listWidget, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(slotListWidgetContextMenuRequested(QPoint)));
+}
+
+QtResourceView::~QtResourceView()
+{
+ if (!d_ptr->m_settingsKey.isEmpty())
+ d_ptr->saveSettings();
+
+ delete d_ptr;
+}
+
+bool QtResourceView::event(QEvent *event)
+{
+ if (event->type() == QEvent::Show) {
+ d_ptr->m_listWidget->scrollToItem(d_ptr->m_listWidget->currentItem());
+ d_ptr->m_treeWidget->scrollToItem(d_ptr->m_treeWidget->currentItem());
+ }
+ return QWidget::event(event);
+}
+
+QtResourceModel *QtResourceView::model() const
+{
+ return d_ptr->m_resourceModel;
+}
+
+QString QtResourceView::selectedResource() const
+{
+ QListWidgetItem *item = d_ptr->m_listWidget->currentItem();
+ return d_ptr->m_itemToResource.value(item);
+}
+
+void QtResourceView::selectResource(const QString &resource)
+{
+ QFileInfo fi(resource);
+ QDir dir = fi.absoluteDir();
+ if (fi.isDir())
+ dir = QDir(resource);
+ QString dirPath = dir.absolutePath();
+ QMap<QString, QTreeWidgetItem *>::const_iterator it;
+ while ((it = d_ptr->m_pathToItem.find(dirPath)) == d_ptr->m_pathToItem.constEnd()) {
+ if (!dir.cdUp())
+ break;
+ dirPath = dir.absolutePath();
+ }
+ if (it != d_ptr->m_pathToItem.constEnd()) {
+ QTreeWidgetItem *treeItem = it.value();
+ d_ptr->m_treeWidget->setCurrentItem(treeItem);
+ d_ptr->m_treeWidget->scrollToItem(treeItem);
+ // expand all up to current one is done by qt
+ // list widget is already propagated (currrent changed was sent by qt)
+ QListWidgetItem *item = d_ptr->m_resourceToItem.value(resource);
+ if (item) {
+ d_ptr->m_listWidget->setCurrentItem(item);
+ d_ptr->m_listWidget->scrollToItem(item);
+ }
+ }
+}
+
+QString QtResourceView::settingsKey() const
+{
+ return d_ptr->m_settingsKey;
+}
+
+void QtResourceView::setSettingsKey(const QString &key)
+{
+ if (d_ptr->m_settingsKey == key)
+ return;
+
+ d_ptr->m_settingsKey = key;
+
+ if (key.isEmpty())
+ return;
+
+ d_ptr->restoreSettings();
+}
+
+void QtResourceView::setResourceModel(QtResourceModel *model)
+{
+ if (d_ptr->m_resourceModel) {
+ disconnect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet *, bool)),
+ this, SLOT(slotResourceSetActivated(QtResourceSet *)));
+ }
+
+ // clear here
+ d_ptr->m_treeWidget->clear();
+ d_ptr->m_listWidget->clear();
+
+ d_ptr->m_resourceModel = model;
+
+ if (!d_ptr->m_resourceModel)
+ return;
+
+ connect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet *, bool)),
+ this, SLOT(slotResourceSetActivated(QtResourceSet *)));
+
+ // fill new here
+ d_ptr->slotResourceSetActivated(d_ptr->m_resourceModel->currentResourceSet());
+}
+
+bool QtResourceView::isResourceEditingEnabled() const
+{
+ return d_ptr->m_resourceEditingEnabled;
+}
+
+void QtResourceView::setResourceEditingEnabled(bool enable)
+{
+ d_ptr->m_resourceEditingEnabled = enable;
+ d_ptr->updateActions();
+}
+
+void QtResourceView::setDragEnabled(bool dragEnabled)
+{
+ d_ptr->m_listWidget->setDragEnabled(dragEnabled);
+}
+
+bool QtResourceView::dragEnabled() const
+{
+ return d_ptr->m_listWidget->dragEnabled();
+}
+
+QString QtResourceView::encodeMimeData(ResourceType resourceType, const QString &path)
+{
+ QDomDocument doc;
+ QDomElement elem = doc.createElement(QLatin1String(elementResourceData));
+ switch (resourceType) {
+ case ResourceImage:
+ elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeImage));
+ break;
+ case ResourceStyleSheet:
+ elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeStyleSheet));
+ break;
+ case ResourceOther:
+ elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeOther));
+ break;
+ }
+ elem.setAttribute(QLatin1String(fileAttribute), path);
+ doc.appendChild(elem);
+ return doc.toString();
+}
+
+bool QtResourceView::decodeMimeData(const QMimeData *md, ResourceType *t, QString *file)
+{
+ return md->hasText() ? decodeMimeData(md->text(), t, file) : false;
+}
+
+bool QtResourceView::decodeMimeData(const QString &text, ResourceType *t, QString *file)
+{
+
+ const QString docElementName = QLatin1String(elementResourceData);
+ static const QString docElementString = QLatin1Char('<') + docElementName;
+
+ if (text.isEmpty() || text.indexOf(docElementString) == -1)
+ return false;
+
+ QDomDocument doc;
+ if (!doc.setContent(text))
+ return false;
+
+ const QDomElement domElement = doc.documentElement();
+ if (domElement.tagName() != docElementName)
+ return false;
+
+ if (t) {
+ const QString typeAttr = QLatin1String(typeAttribute);
+ if (domElement.hasAttribute (typeAttr)) {
+ const QString typeValue = domElement.attribute(typeAttr, QLatin1String(typeOther));
+ if (typeValue == QLatin1String(typeImage)) {
+ *t = ResourceImage;
+ } else {
+ *t = typeValue == QLatin1String(typeStyleSheet) ? ResourceStyleSheet : ResourceOther;
+ }
+ }
+ }
+ if (file) {
+ const QString fileAttr = QLatin1String(fileAttribute);
+ if (domElement.hasAttribute(fileAttr)) {
+ *file = domElement.attribute(fileAttr, QString());
+ } else {
+ file->clear();
+ }
+ }
+ return true;
+}
+
+// ---------------------------- QtResourceViewDialogPrivate
+
+class QtResourceViewDialogPrivate
+{
+ QtResourceViewDialog *q_ptr;
+ Q_DECLARE_PUBLIC(QtResourceViewDialog)
+public:
+ QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core);
+
+ void slotResourceSelected(const QString &resource) { setOkButtonEnabled(!resource.isEmpty()); }
+ void setOkButtonEnabled(bool v) { m_box->button(QDialogButtonBox::Ok)->setEnabled(v); }
+
+ QDesignerFormEditorInterface *m_core;
+ QtResourceView *m_view;
+ QDialogButtonBox *m_box;
+};
+
+QtResourceViewDialogPrivate::QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core) :
+ q_ptr(0),
+ m_core(core),
+ m_view(new QtResourceView(core)),
+ m_box(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel))
+{
+ m_view->setSettingsKey(QLatin1String(ResourceViewDialogC));
+}
+
+// ------------ QtResourceViewDialog
+QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
+ QDialog(parent),
+ d_ptr(new QtResourceViewDialogPrivate(core))
+{
+ setWindowTitle(tr("Select Resource"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ d_ptr->q_ptr = this;
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(d_ptr->m_view);
+ layout->addWidget(d_ptr->m_box);
+ connect(d_ptr->m_box, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(d_ptr->m_box, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(d_ptr->m_view, SIGNAL(resourceActivated(QString)), this, SLOT(accept()));
+ connect(d_ptr->m_view, SIGNAL(resourceSelected(QString)), this, SLOT(slotResourceSelected(QString)));
+ d_ptr->setOkButtonEnabled(false);
+ d_ptr->m_view->setResourceModel(core->resourceModel());
+
+ QDesignerSettingsInterface *settings = core->settingsManager();
+ settings->beginGroup(QLatin1String(ResourceViewDialogC));
+
+ if (settings->contains(QLatin1String(Geometry)))
+ setGeometry(settings->value(QLatin1String(Geometry)).toRect());
+
+ settings->endGroup();
+}
+
+QtResourceViewDialog::~QtResourceViewDialog()
+{
+ QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager();
+ settings->beginGroup(QLatin1String(ResourceViewDialogC));
+
+ settings->setValue(QLatin1String(Geometry), geometry());
+
+ settings->endGroup();
+
+ delete d_ptr;
+}
+
+QString QtResourceViewDialog::selectedResource() const
+{
+ return d_ptr->m_view->selectedResource();
+}
+
+void QtResourceViewDialog::selectResource(const QString &path)
+{
+ d_ptr->m_view->selectResource(path);
+}
+
+bool QtResourceViewDialog::isResourceEditingEnabled() const
+{
+ return d_ptr->m_view->isResourceEditingEnabled();
+}
+
+void QtResourceViewDialog::setResourceEditingEnabled(bool enable)
+{
+ d_ptr->m_view->setResourceEditingEnabled(enable);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtresourceview_p.cpp"
diff --git a/tools/designer/src/lib/shared/qtresourceview_p.h b/tools/designer/src/lib/shared/qtresourceview_p.h
new file mode 100644
index 0000000..33162c5
--- /dev/null
+++ b/tools/designer/src/lib/shared/qtresourceview_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 QTRESOURCEVIEW_H
+#define QTRESOURCEVIEW_H
+
+#include "shared_global_p.h"
+#include <QtGui/QWidget>
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QtResourceModel;
+class QtResourceSet;
+class QDesignerFormEditorInterface;
+class QMimeData;
+
+class QDESIGNER_SHARED_EXPORT QtResourceView : public QWidget
+{
+ Q_OBJECT
+public:
+ QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+ ~QtResourceView();
+
+ void setDragEnabled(bool dragEnabled);
+ bool dragEnabled() const;
+
+ QtResourceModel *model() const;
+ void setResourceModel(QtResourceModel *model);
+
+ QString selectedResource() const;
+ void selectResource(const QString &resource);
+
+ QString settingsKey() const;
+ void setSettingsKey(const QString &key);
+
+ bool isResourceEditingEnabled() const;
+ void setResourceEditingEnabled(bool enable);
+
+ // Helpers for handling the drag originating in QtResourceView (Xml/text)
+ enum ResourceType { ResourceImage, ResourceStyleSheet, ResourceOther };
+ static QString encodeMimeData(ResourceType resourceType, const QString &path);
+
+ static bool decodeMimeData(const QMimeData *md, ResourceType *t = 0, QString *file = 0);
+ static bool decodeMimeData(const QString &text, ResourceType *t = 0, QString *file = 0);
+
+signals:
+ void resourceSelected(const QString &resource);
+ void resourceActivated(const QString &resource);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+
+ class QtResourceViewPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QtResourceView)
+ Q_DISABLE_COPY(QtResourceView)
+ Q_PRIVATE_SLOT(d_func(), void slotResourceSetActivated(QtResourceSet *))
+ Q_PRIVATE_SLOT(d_func(), void slotCurrentPathChanged(QTreeWidgetItem *))
+ Q_PRIVATE_SLOT(d_func(), void slotCurrentResourceChanged(QListWidgetItem *))
+ Q_PRIVATE_SLOT(d_func(), void slotResourceActivated(QListWidgetItem *))
+ Q_PRIVATE_SLOT(d_func(), void slotEditResources())
+ Q_PRIVATE_SLOT(d_func(), void slotReloadResources())
+ Q_PRIVATE_SLOT(d_func(), void slotCopyResourcePath())
+ Q_PRIVATE_SLOT(d_func(), void slotListWidgetContextMenuRequested(const QPoint &pos))
+};
+
+class QDESIGNER_SHARED_EXPORT QtResourceViewDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+ virtual ~QtResourceViewDialog();
+
+ QString selectedResource() const;
+ void selectResource(const QString &path);
+
+ bool isResourceEditingEnabled() const;
+ void setResourceEditingEnabled(bool enable);
+
+private:
+ class QtResourceViewDialogPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QtResourceViewDialog)
+ Q_DISABLE_COPY(QtResourceViewDialog)
+ Q_PRIVATE_SLOT(d_func(), void slotResourceSelected(const QString &))
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/richtexteditor.cpp b/tools/designer/src/lib/shared/richtexteditor.cpp
new file mode 100644
index 0000000..8aa036b
--- /dev/null
+++ b/tools/designer/src/lib/shared/richtexteditor.cpp
@@ -0,0 +1,762 @@
+/****************************************************************************
+**
+** 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::RichTextEditorDialog
+*/
+
+#include "richtexteditor_p.h"
+#include "htmlhighlighter_p.h"
+#include "iconselector_p.h"
+#include "ui_addlinkdialog.h"
+#include "abstractsettings_p.h"
+
+#include "iconloader_p.h"
+
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QPointer>
+
+#include <QtGui/QAction>
+#include <QtGui/QColorDialog>
+#include <QtGui/QComboBox>
+#include <QtGui/QFontDatabase>
+#include <QtGui/QTextCursor>
+#include <QtGui/QPainter>
+#include <QtGui/QIcon>
+#include <QtGui/QMenu>
+#include <QtGui/QMoveEvent>
+#include <QtGui/QTabWidget>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextBlock>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QPushButton>
+#include <QtGui/QDialogButtonBox>
+
+QT_BEGIN_NAMESPACE
+
+static const char *RichTextDialogC = "RichTextDialog";
+static const char *Geometry = "Geometry";
+
+namespace qdesigner_internal {
+
+class RichTextEditor : public QTextEdit
+{
+ Q_OBJECT
+public:
+ RichTextEditor(QWidget *parent = 0);
+ void setDefaultFont(const QFont &font);
+
+ QToolBar *createToolBar(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+
+public slots:
+ void setFontBold(bool b);
+ void setFontPointSize(double);
+ void setText(const QString &text);
+ QString text(Qt::TextFormat format) const;
+
+signals:
+ void stateChanged();
+};
+
+class AddLinkDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AddLinkDialog(RichTextEditor *editor, QWidget *parent = 0);
+ ~AddLinkDialog();
+
+ int showDialog();
+
+public slots:
+ void accept();
+
+private:
+ RichTextEditor *m_editor;
+ Ui::AddLinkDialog *m_ui;
+};
+
+AddLinkDialog::AddLinkDialog(RichTextEditor *editor, QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::AddLinkDialog)
+{
+ m_ui->setupUi(this);
+
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ m_editor = editor;
+}
+
+AddLinkDialog::~AddLinkDialog()
+{
+ delete m_ui;
+}
+
+int AddLinkDialog::showDialog()
+{
+ // Set initial focus
+ const QTextCursor cursor = m_editor->textCursor();
+ if (cursor.hasSelection()) {
+ m_ui->titleInput->setText(cursor.selectedText());
+ m_ui->urlInput->setFocus();
+ } else {
+ m_ui->titleInput->setFocus();
+ }
+
+ return exec();
+}
+
+void AddLinkDialog::accept()
+{
+ const QString title = m_ui->titleInput->text();
+ const QString url = m_ui->urlInput->text();
+
+ if (!title.isEmpty()) {
+ QString html = QLatin1String("<a href=\"");
+ html += url;
+ html += QLatin1String("\">");
+ html += title;
+ html += QLatin1String("</a>");
+
+ m_editor->insertHtml(html);
+ }
+
+ m_ui->titleInput->clear();
+ m_ui->urlInput->clear();
+
+ QDialog::accept();
+}
+
+class HtmlTextEdit : public QTextEdit
+{
+ Q_OBJECT
+
+public:
+ HtmlTextEdit(QWidget *parent = 0)
+ : QTextEdit(parent)
+ {}
+
+ void contextMenuEvent(QContextMenuEvent *event);
+
+private slots:
+ void actionTriggered(QAction *action);
+};
+
+void HtmlTextEdit::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *menu = createStandardContextMenu();
+ QMenu *htmlMenu = new QMenu(tr("Insert HTML entity"), menu);
+
+ typedef struct {
+ const char *text;
+ const char *entity;
+ } Entry;
+
+ const Entry entries[] = {
+ { "&&amp; (&&)", "&amp;" },
+ { "&&nbsp;", "&nbsp;" },
+ { "&&lt; (<)", "&lt;" },
+ { "&&gt; (>)", "&gt;" },
+ { "&&copy; (Copyright)", "&copy;" },
+ { "&&reg; (Trade Mark)", "&reg;" },
+ };
+
+ for (int i = 0; i < 6; ++i) {
+ QAction *entityAction = new QAction(QLatin1String(entries[i].text),
+ htmlMenu);
+ entityAction->setData(QLatin1String(entries[i].entity));
+ htmlMenu->addAction(entityAction);
+ }
+
+ menu->addMenu(htmlMenu);
+ connect(htmlMenu, SIGNAL(triggered(QAction*)),
+ SLOT(actionTriggered(QAction*)));
+ menu->exec(event->globalPos());
+ delete menu;
+}
+
+void HtmlTextEdit::actionTriggered(QAction *action)
+{
+ insertPlainText(action->data().toString());
+}
+
+class ColorAction : public QAction
+{
+ Q_OBJECT
+
+public:
+ ColorAction(QObject *parent);
+
+ const QColor& color() const { return m_color; }
+ void setColor(const QColor &color);
+
+signals:
+ void colorChanged(const QColor &color);
+
+private slots:
+ void chooseColor();
+
+private:
+ QColor m_color;
+};
+
+ColorAction::ColorAction(QObject *parent):
+ QAction(parent)
+{
+ setText(tr("Text Color"));
+ setColor(Qt::black);
+ connect(this, SIGNAL(triggered()), this, SLOT(chooseColor()));
+}
+
+void ColorAction::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ QPixmap pix(24, 24);
+ QPainter painter(&pix);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.fillRect(pix.rect(), m_color);
+ painter.setPen(m_color.darker());
+ painter.drawRect(pix.rect().adjusted(0, 0, -1, -1));
+ setIcon(pix);
+}
+
+void ColorAction::chooseColor()
+{
+ const QColor col = QColorDialog::getColor(m_color, 0);
+ if (col.isValid() && col != m_color) {
+ setColor(col);
+ emit colorChanged(m_color);
+ }
+}
+
+class RichTextEditorToolBar : public QToolBar
+{
+ Q_OBJECT
+public:
+ RichTextEditorToolBar(QDesignerFormEditorInterface *core,
+ RichTextEditor *editor,
+ QWidget *parent = 0);
+
+public slots:
+ void updateActions();
+
+private slots:
+ void alignmentActionTriggered(QAction *action);
+ void sizeInputActivated(const QString &size);
+ void colorChanged(const QColor &color);
+ void setVAlignSuper(bool super);
+ void setVAlignSub(bool sub);
+ void insertLink();
+ void insertImage();
+
+private:
+ QAction *m_bold_action;
+ QAction *m_italic_action;
+ QAction *m_underline_action;
+ QAction *m_valign_sup_action;
+ QAction *m_valign_sub_action;
+ QAction *m_align_left_action;
+ QAction *m_align_center_action;
+ QAction *m_align_right_action;
+ QAction *m_align_justify_action;
+ QAction *m_link_action;
+ QAction *m_image_action;
+ ColorAction *m_color_action;
+ QComboBox *m_font_size_input;
+
+ QDesignerFormEditorInterface *m_core;
+ QPointer<RichTextEditor> m_editor;
+};
+
+static QAction *createCheckableAction(const QIcon &icon, const QString &text,
+ QObject *receiver, const char *slot,
+ QObject *parent = 0)
+{
+ QAction *result = new QAction(parent);
+ result->setIcon(icon);
+ result->setText(text);
+ result->setCheckable(true);
+ result->setChecked(false);
+ if (slot)
+ QObject::connect(result, SIGNAL(triggered(bool)), receiver, slot);
+ return result;
+}
+
+RichTextEditorToolBar::RichTextEditorToolBar(QDesignerFormEditorInterface *core,
+ RichTextEditor *editor,
+ QWidget *parent) :
+ QToolBar(parent),
+ m_link_action(new QAction(this)),
+ m_image_action(new QAction(this)),
+ m_color_action(new ColorAction(this)),
+ m_font_size_input(new QComboBox),
+ m_core(core),
+ m_editor(editor)
+{
+ // Font size combo box
+ m_font_size_input->setEditable(false);
+ const QList<int> font_sizes = QFontDatabase::standardSizes();
+ foreach (int font_size, font_sizes)
+ m_font_size_input->addItem(QString::number(font_size));
+
+ connect(m_font_size_input, SIGNAL(activated(QString)),
+ this, SLOT(sizeInputActivated(QString)));
+ addWidget(m_font_size_input);
+
+ addSeparator();
+
+ // Bold, italic and underline buttons
+
+ m_bold_action = createCheckableAction(
+ createIconSet(QLatin1String("textbold.png")),
+ tr("Bold"), editor, SLOT(setFontBold(bool)), this);
+ m_bold_action->setShortcut(tr("CTRL+B"));
+ addAction(m_bold_action);
+
+ m_italic_action = createCheckableAction(
+ createIconSet(QLatin1String("textitalic.png")),
+ tr("Italic"), editor, SLOT(setFontItalic(bool)), this);
+ m_italic_action->setShortcut(tr("CTRL+I"));
+ addAction(m_italic_action);
+
+ m_underline_action = createCheckableAction(
+ createIconSet(QLatin1String("textunder.png")),
+ tr("Underline"), editor, SLOT(setFontUnderline(bool)), this);
+ m_underline_action->setShortcut(tr("CTRL+U"));
+ addAction(m_underline_action);
+
+ addSeparator();
+
+ // Left, center, right and justified alignment buttons
+
+ QActionGroup *alignment_group = new QActionGroup(this);
+ connect(alignment_group, SIGNAL(triggered(QAction*)),
+ SLOT(alignmentActionTriggered(QAction*)));
+
+ m_align_left_action = createCheckableAction(
+ createIconSet(QLatin1String("textleft.png")),
+ tr("Left Align"), editor, 0, alignment_group);
+ addAction(m_align_left_action);
+
+ m_align_center_action = createCheckableAction(
+ createIconSet(QLatin1String("textcenter.png")),
+ tr("Center"), editor, 0, alignment_group);
+ addAction(m_align_center_action);
+
+ m_align_right_action = createCheckableAction(
+ createIconSet(QLatin1String("textright.png")),
+ tr("Right Align"), editor, 0, alignment_group);
+ addAction(m_align_right_action);
+
+ m_align_justify_action = createCheckableAction(
+ createIconSet(QLatin1String("textjustify.png")),
+ tr("Justify"), editor, 0, alignment_group);
+ addAction(m_align_justify_action);
+
+ addSeparator();
+
+ // Superscript and subscript buttons
+
+ m_valign_sup_action = createCheckableAction(
+ createIconSet(QLatin1String("textsuperscript.png")),
+ tr("Superscript"),
+ this, SLOT(setVAlignSuper(bool)), this);
+ addAction(m_valign_sup_action);
+
+ m_valign_sub_action = createCheckableAction(
+ createIconSet(QLatin1String("textsubscript.png")),
+ tr("Subscript"),
+ this, SLOT(setVAlignSub(bool)), this);
+ addAction(m_valign_sub_action);
+
+ addSeparator();
+
+ // Insert hyperlink and image buttons
+
+ m_link_action->setIcon(createIconSet(QLatin1String("textanchor.png")));
+ m_link_action->setText(tr("Insert &Link"));
+ connect(m_link_action, SIGNAL(triggered()), SLOT(insertLink()));
+ addAction(m_link_action);
+
+ m_image_action->setIcon(createIconSet(QLatin1String("insertimage.png")));
+ m_image_action->setText(tr("Insert &Image"));
+ connect(m_image_action, SIGNAL(triggered()), SLOT(insertImage()));
+ addAction(m_image_action);
+
+ addSeparator();
+
+ // Text color button
+ connect(m_color_action, SIGNAL(colorChanged(QColor)),
+ this, SLOT(colorChanged(QColor)));
+ addAction(m_color_action);
+
+ connect(editor, SIGNAL(textChanged()), this, SLOT(updateActions()));
+ connect(editor, SIGNAL(stateChanged()), this, SLOT(updateActions()));
+
+ updateActions();
+}
+
+void RichTextEditorToolBar::alignmentActionTriggered(QAction *action)
+{
+ Qt::Alignment new_alignment;
+
+ if (action == m_align_left_action) {
+ new_alignment = Qt::AlignLeft;
+ } else if (action == m_align_center_action) {
+ new_alignment = Qt::AlignCenter;
+ } else if (action == m_align_right_action) {
+ new_alignment = Qt::AlignRight;
+ } else {
+ new_alignment = Qt::AlignJustify;
+ }
+
+ m_editor->setAlignment(new_alignment);
+}
+
+void RichTextEditorToolBar::colorChanged(const QColor &color)
+{
+ m_editor->setTextColor(color);
+ m_editor->setFocus();
+}
+
+void RichTextEditorToolBar::sizeInputActivated(const QString &size)
+{
+ bool ok;
+ int i = size.toInt(&ok);
+ if (!ok)
+ return;
+
+ m_editor->setFontPointSize(i);
+ m_editor->setFocus();
+}
+
+void RichTextEditorToolBar::setVAlignSuper(bool super)
+{
+ const QTextCharFormat::VerticalAlignment align = super ?
+ QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal;
+
+ QTextCharFormat charFormat = m_editor->currentCharFormat();
+ charFormat.setVerticalAlignment(align);
+ m_editor->setCurrentCharFormat(charFormat);
+
+ m_valign_sub_action->setChecked(false);
+}
+
+void RichTextEditorToolBar::setVAlignSub(bool sub)
+{
+ const QTextCharFormat::VerticalAlignment align = sub ?
+ QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal;
+
+ QTextCharFormat charFormat = m_editor->currentCharFormat();
+ charFormat.setVerticalAlignment(align);
+ m_editor->setCurrentCharFormat(charFormat);
+
+ m_valign_sup_action->setChecked(false);
+}
+
+void RichTextEditorToolBar::insertLink()
+{
+ AddLinkDialog linkDialog(m_editor, this);
+ linkDialog.showDialog();
+ m_editor->setFocus();
+}
+
+void RichTextEditorToolBar::insertImage()
+{
+ const QString path = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), QString(), this);
+ if (!path.isEmpty())
+ m_editor->insertHtml(QLatin1String("<img src=\"") + path + QLatin1String("\"/>"));
+}
+
+void RichTextEditorToolBar::updateActions()
+{
+ if (m_editor == 0) {
+ setEnabled(false);
+ return;
+ }
+
+ const Qt::Alignment alignment = m_editor->alignment();
+ const QTextCursor cursor = m_editor->textCursor();
+ const QTextCharFormat charFormat = cursor.charFormat();
+ const QFont font = charFormat.font();
+ const QTextCharFormat::VerticalAlignment valign =
+ charFormat.verticalAlignment();
+ const bool superScript = valign == QTextCharFormat::AlignSuperScript;
+ const bool subScript = valign == QTextCharFormat::AlignSubScript;
+
+ if (alignment & Qt::AlignLeft) {
+ m_align_left_action->setChecked(true);
+ } else if (alignment & Qt::AlignRight) {
+ m_align_right_action->setChecked(true);
+ } else if (alignment & Qt::AlignHCenter) {
+ m_align_center_action->setChecked(true);
+ } else {
+ m_align_justify_action->setChecked(true);
+ }
+
+ m_bold_action->setChecked(font.bold());
+ m_italic_action->setChecked(font.italic());
+ m_underline_action->setChecked(font.underline());
+ m_valign_sup_action->setChecked(superScript);
+ m_valign_sub_action->setChecked(subScript);
+
+ const int size = font.pointSize();
+ const int idx = m_font_size_input->findText(QString::number(size));
+ if (idx != -1)
+ m_font_size_input->setCurrentIndex(idx);
+
+ m_color_action->setColor(m_editor->textColor());
+}
+
+RichTextEditor::RichTextEditor(QWidget *parent)
+ : QTextEdit(parent)
+{
+ connect(this, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
+ this, SIGNAL(stateChanged()));
+ connect(this, SIGNAL(cursorPositionChanged()),
+ this, SIGNAL(stateChanged()));
+}
+
+QToolBar *RichTextEditor::createToolBar(QDesignerFormEditorInterface *core, QWidget *parent)
+{
+ return new RichTextEditorToolBar(core, this, parent);
+}
+
+void RichTextEditor::setFontBold(bool b)
+{
+ if (b)
+ setFontWeight(QFont::Bold);
+ else
+ setFontWeight(QFont::Normal);
+}
+
+void RichTextEditor::setFontPointSize(double d)
+{
+ QTextEdit::setFontPointSize(qreal(d));
+}
+
+void RichTextEditor::setText(const QString &text)
+{
+ if (Qt::mightBeRichText(text))
+ setHtml(text);
+ else
+ setPlainText(text);
+}
+
+void RichTextEditor::setDefaultFont(const QFont &font)
+{
+ document()->setDefaultFont(font);
+ if (font.pointSize() > 0)
+ setFontPointSize(font.pointSize());
+ else
+ setFontPointSize(QFontInfo(font).pointSize());
+ emit textChanged();
+}
+
+QString RichTextEditor::text(Qt::TextFormat format) const
+{
+ switch (format) {
+ case Qt::LogText:
+ case Qt::PlainText:
+ return toPlainText();
+ case Qt::RichText:
+ return toHtml();
+ case Qt::AutoText:
+ break;
+ }
+ const QString html = toHtml();
+ const QString plain = toPlainText();
+ QTextEdit tester;
+ tester.setPlainText(plain);
+ return tester.toHtml() == html ? plain : html;
+}
+
+RichTextEditorDialog::RichTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
+ QDialog(parent),
+ m_editor(new RichTextEditor()),
+ m_text_edit(new HtmlTextEdit),
+ m_tab_widget(new QTabWidget),
+ m_state(Clean),
+ m_core(core)
+{
+ setWindowTitle(tr("Edit text"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ m_text_edit->setAcceptRichText(false);
+ new HtmlHighlighter(m_text_edit);
+
+ connect(m_editor, SIGNAL(textChanged()), this, SLOT(richTextChanged()));
+ connect(m_text_edit, SIGNAL(textChanged()), this, SLOT(sourceChanged()));
+
+ // The toolbar needs to be created after the RichTextEditor
+ QToolBar *tool_bar = m_editor->createToolBar(core);
+ tool_bar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+
+ QWidget *rich_edit = new QWidget;
+ QVBoxLayout *rich_edit_layout = new QVBoxLayout(rich_edit);
+ rich_edit_layout->addWidget(tool_bar);
+ rich_edit_layout->addWidget(m_editor);
+
+ QWidget *plain_edit = new QWidget;
+ QVBoxLayout *plain_edit_layout = new QVBoxLayout(plain_edit);
+ plain_edit_layout->addWidget(m_text_edit);
+
+ m_tab_widget->setTabPosition(QTabWidget::South);
+ m_tab_widget->addTab(rich_edit, tr("Rich Text"));
+ m_tab_widget->addTab(plain_edit, tr("Source"));
+ connect(m_tab_widget, SIGNAL(currentChanged(int)),
+ SLOT(tabIndexChanged(int)));
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
+ QPushButton *ok_button = buttonBox->button(QDialogButtonBox::Ok);
+ ok_button->setText(tr("&OK"));
+ ok_button->setDefault(true);
+ buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("&Cancel"));
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_tab_widget);
+ layout->addWidget(buttonBox);
+
+ m_editor->setFocus();
+
+ QDesignerSettingsInterface *settings = core->settingsManager();
+ settings->beginGroup(QLatin1String(RichTextDialogC));
+
+ if (settings->contains(QLatin1String(Geometry)))
+ restoreGeometry(settings->value(QLatin1String(Geometry)).toByteArray());
+
+ settings->endGroup();
+}
+
+RichTextEditorDialog::~RichTextEditorDialog()
+{
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->beginGroup(QLatin1String(RichTextDialogC));
+
+ settings->setValue(QLatin1String(Geometry), saveGeometry());
+ settings->endGroup();
+}
+
+int RichTextEditorDialog::showDialog()
+{
+ m_tab_widget->setCurrentIndex(0);
+ m_editor->selectAll();
+ m_editor->setFocus();
+
+ return exec();
+}
+
+void RichTextEditorDialog::setDefaultFont(const QFont &font)
+{
+ m_editor->setDefaultFont(font);
+}
+
+void RichTextEditorDialog::setText(const QString &text)
+{
+ m_editor->setText(text);
+ m_text_edit->setPlainText(text);
+ m_state = Clean;
+}
+
+QString RichTextEditorDialog::text(Qt::TextFormat format) const
+{
+ // In autotext mode, if the user has changed the source, use that
+ if (format == Qt::AutoText && (m_state == Clean || m_state == SourceChanged))
+ return m_text_edit->toPlainText();
+ // If the plain text HTML editor is selected, first copy its contents over
+ // to the rich text editor so that it is converted to Qt-HTML or actual
+ // plain text.
+ if (m_tab_widget->currentIndex() == SourceIndex && m_state == SourceChanged)
+ m_editor->setHtml(m_text_edit->toPlainText());
+ return m_editor->text(format);
+}
+
+void RichTextEditorDialog::tabIndexChanged(int newIndex)
+{
+ // Anything changed, is there a need for a conversion?
+ if (newIndex == SourceIndex && m_state != RichTextChanged)
+ return;
+ if (newIndex == RichTextIndex && m_state != SourceChanged)
+ return;
+ const State oldState = m_state;
+ // Remember the cursor position, since it is invalidated by setPlainText
+ QTextEdit *new_edit = (newIndex == SourceIndex) ? m_text_edit : m_editor;
+ const int position = new_edit->textCursor().position();
+
+ if (newIndex == SourceIndex)
+ m_text_edit->setPlainText(m_editor->text(Qt::RichText));
+ else
+ m_editor->setHtml(m_text_edit->toPlainText());
+
+ QTextCursor cursor = new_edit->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ if (cursor.position() > position) {
+ cursor.setPosition(position);
+ }
+ new_edit->setTextCursor(cursor);
+ m_state = oldState; // Changed is triggered by setting the text
+}
+
+void RichTextEditorDialog::richTextChanged()
+{
+ m_state = RichTextChanged;
+}
+
+void RichTextEditorDialog::sourceChanged()
+{
+ m_state = SourceChanged;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#include "richtexteditor.moc"
diff --git a/tools/designer/src/lib/shared/richtexteditor_p.h b/tools/designer/src/lib/shared/richtexteditor_p.h
new file mode 100644
index 0000000..5341fbb
--- /dev/null
+++ b/tools/designer/src/lib/shared/richtexteditor_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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 RICHTEXTEDITOR_H
+#define RICHTEXTEDITOR_H
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QDialog>
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTabWidget;
+class QToolBar;
+
+class QDesignerFormEditorInterface;
+
+namespace qdesigner_internal {
+
+class RichTextEditor;
+
+class QDESIGNER_SHARED_EXPORT RichTextEditorDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ RichTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0);
+ ~RichTextEditorDialog();
+
+ int showDialog();
+ void setDefaultFont(const QFont &font);
+ void setText(const QString &text);
+ QString text(Qt::TextFormat format = Qt::AutoText) const;
+
+private slots:
+ void tabIndexChanged(int newIndex);
+ void richTextChanged();
+ void sourceChanged();
+
+private:
+ enum TabIndex { RichTextIndex, SourceIndex };
+ enum State { Clean, RichTextChanged, SourceChanged };
+ RichTextEditor *m_editor;
+ QTextEdit *m_text_edit;
+ QTabWidget *m_tab_widget;
+ State m_state;
+ QDesignerFormEditorInterface *m_core;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // RITCHTEXTEDITOR_H
diff --git a/tools/designer/src/lib/shared/scriptcommand.cpp b/tools/designer/src/lib/shared/scriptcommand.cpp
new file mode 100644
index 0000000..5261562
--- /dev/null
+++ b/tools/designer/src/lib/shared/scriptcommand.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "scriptcommand_p.h"
+#include "metadatabase_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+ScriptCommand::ScriptCommand(QDesignerFormWindowInterface *formWindow) :
+ QDesignerFormWindowCommand(QCoreApplication::translate("Command", "Change script"), formWindow)
+{
+}
+
+bool ScriptCommand::init(const ObjectList &list, const QString &script)
+{
+ MetaDataBase *metaDataBase = qobject_cast<MetaDataBase*>(formWindow()->core()->metaDataBase());
+ if (!metaDataBase)
+ return false;
+
+ // Save old values
+ m_oldValues.clear();
+ foreach (QObject *obj, list) {
+ const MetaDataBaseItem* item = metaDataBase->metaDataBaseItem(obj);
+ if (!item)
+ return false;
+ m_oldValues.push_back(ObjectScriptPair(obj, item->script()));
+ }
+ m_script = script;
+ return true;
+}
+
+void ScriptCommand::redo()
+{
+ MetaDataBase *metaDataBase = qobject_cast<MetaDataBase*>(formWindow()->core()->metaDataBase());
+ Q_ASSERT(metaDataBase);
+
+ ObjectScriptList::const_iterator cend = m_oldValues.constEnd();
+ for (ObjectScriptList::const_iterator it = m_oldValues.constBegin();it != cend; ++it ) {
+ if (it->first)
+ metaDataBase->metaDataBaseItem(it->first)->setScript(m_script);
+ }
+}
+
+void ScriptCommand::undo()
+{
+ MetaDataBase *metaDataBase = qobject_cast<MetaDataBase*>(formWindow()->core()->metaDataBase());
+ Q_ASSERT(metaDataBase);
+
+ ObjectScriptList::const_iterator cend = m_oldValues.constEnd();
+ for (ObjectScriptList::const_iterator it = m_oldValues.constBegin();it != cend; ++it ) {
+ if (it->first)
+ metaDataBase->metaDataBaseItem(it->first)->setScript(it->second);
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/scriptcommand_p.h b/tools/designer/src/lib/shared/scriptcommand_p.h
new file mode 100644
index 0000000..45cc588
--- /dev/null
+++ b/tools/designer/src/lib/shared/scriptcommand_p.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$
+**
+****************************************************************************/
+
+//
+// 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 QDESIGNER_SCRIPTCOMMAND_H
+#define QDESIGNER_SCRIPTCOMMAND_H
+
+#include "qdesigner_formwindowcommand_p.h"
+
+#include <QtCore/QPair>
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT ScriptCommand: public QDesignerFormWindowCommand
+{
+ ScriptCommand(const ScriptCommand &);
+ ScriptCommand& operator=(const ScriptCommand &);
+
+public:
+ explicit ScriptCommand(QDesignerFormWindowInterface *formWindow);
+
+ typedef QList<QObject *> ObjectList;
+ bool init(const ObjectList &list, const QString &script);
+
+ virtual void redo();
+ virtual void undo();
+
+private:
+ typedef QPair<QPointer<QObject>, QString> ObjectScriptPair;
+ typedef QList<ObjectScriptPair> ObjectScriptList;
+ ObjectScriptList m_oldValues;
+ QString m_script;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // QDESIGNER_SCRIPTCOMMAND_H
diff --git a/tools/designer/src/lib/shared/scriptdialog.cpp b/tools/designer/src/lib/shared/scriptdialog.cpp
new file mode 100644
index 0000000..616f0c9
--- /dev/null
+++ b/tools/designer/src/lib/shared/scriptdialog.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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::ScriptDialog
+*/
+
+#include "scriptdialog_p.h"
+#include "qscripthighlighter_p.h"
+
+#include <abstractdialoggui_p.h>
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QMessageBox>
+#include <QtScript/QScriptEngine>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+ // ScriptDialog
+ ScriptDialog::ScriptDialog(QDesignerDialogGuiInterface *m_dialogGui, QWidget *parent) :
+ QDialog(parent),
+ m_dialogGui(m_dialogGui),
+ m_textEdit(new QTextEdit)
+ {
+ setWindowTitle(tr("Edit script"));
+ setModal(true);
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+
+ const QString textHelp = tr("\
+<html>Enter a Qt Script snippet to be executed while loading the form.<br>\
+The widget and its children are accessible via the \
+variables <i>widget</i> and <i>childWidgets</i>, respectively.");
+ m_textEdit->setToolTip(textHelp);
+ m_textEdit->setWhatsThis(textHelp);
+ m_textEdit->setMinimumSize(QSize(600, 400));
+ vboxLayout->addWidget(m_textEdit);
+ new QScriptHighlighter(m_textEdit->document());
+ // button box
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
+ connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
+ connect(buttonBox , SIGNAL(accepted()), this, SLOT(slotAccept()));
+ vboxLayout->addWidget(buttonBox);
+ }
+
+ bool ScriptDialog::editScript(QString &script)
+ {
+ m_textEdit->setText(script);
+ if (exec() != Accepted)
+ return false;
+
+ script = trimmedScript();
+ return true;
+ }
+
+ void ScriptDialog::slotAccept()
+ {
+ if (checkScript())
+ accept();
+ }
+
+ QString ScriptDialog::trimmedScript() const
+ {
+ // Ensure a single newline
+ QString rc = m_textEdit->toPlainText().trimmed();
+ if (!rc.isEmpty())
+ rc += QLatin1Char('\n');
+ return rc;
+ }
+
+ bool ScriptDialog::checkScript()
+ {
+ const QString script = trimmedScript();
+ if (script.isEmpty())
+ return true;
+ QScriptEngine scriptEngine;
+ if (scriptEngine.canEvaluate(script))
+ return true;
+ m_dialogGui->message(this, QDesignerDialogGuiInterface::ScriptDialogMessage, QMessageBox::Warning,
+ windowTitle(), tr("Syntax error"), QMessageBox::Ok);
+ return false;
+ }
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/scriptdialog_p.h b/tools/designer/src/lib/shared/scriptdialog_p.h
new file mode 100644
index 0000000..418cc1e
--- /dev/null
+++ b/tools/designer/src/lib/shared/scriptdialog_p.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 SCRIPTDIALOG_H
+#define SCRIPTDIALOG_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerDialogGuiInterface;
+
+class QTextEdit;
+
+namespace qdesigner_internal {
+
+ // Dialog for showing script errors
+ class QDESIGNER_SHARED_EXPORT ScriptDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit ScriptDialog(QDesignerDialogGuiInterface *dialogGui, QWidget *parent);
+ bool editScript(QString &script);
+
+ private slots:
+ void slotAccept();
+
+ private:
+ QString trimmedScript() const;
+ bool checkScript();
+
+ QDesignerDialogGuiInterface *m_dialogGui;
+ QTextEdit *m_textEdit;
+ };
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // SCRIPTDIALOG_H
diff --git a/tools/designer/src/lib/shared/scripterrordialog.cpp b/tools/designer/src/lib/shared/scripterrordialog.cpp
new file mode 100644
index 0000000..c4a7e07
--- /dev/null
+++ b/tools/designer/src/lib/shared/scripterrordialog.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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::ScriptErrorDialog
+*/
+
+#include "scripterrordialog_p.h"
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCursor>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QPen>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+static void formatError(const QFormScriptRunner::Error &error,
+ QTextCursor &cursor)
+{
+ const QTextCharFormat oldFormat = cursor.charFormat();
+ // Message
+ cursor.insertText(QCoreApplication::translate("ScriptErrorDialog", "An error occurred while running the scripts for \"%1\":\n").arg(error.objectName));
+
+ QTextCharFormat format(oldFormat);
+
+ // verbatim listing
+ format.setFontFamily(QLatin1String("Courier"));
+ cursor.insertText(error.script, format);
+
+ const QString newLine(QLatin1Char('\n'));
+
+ cursor.insertText(newLine);
+
+ // red error
+ format = oldFormat;
+ format.setTextOutline(QPen(Qt::red));
+ cursor.insertText(error.errorMessage, format);
+ cursor.insertText(newLine);
+ cursor.setCharFormat (oldFormat);
+}
+
+namespace qdesigner_internal {
+
+ // ScriptErrorDialog
+ ScriptErrorDialog::ScriptErrorDialog(const Errors& errors, QWidget *parent) :
+ QDialog(parent),
+ m_textEdit(new QTextEdit)
+ {
+ setWindowTitle(tr("Script errors"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setModal(true);
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+
+ m_textEdit->setReadOnly(true);
+ m_textEdit->setMinimumSize(QSize(600, 400));
+ vboxLayout->addWidget(m_textEdit);
+ // button box
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
+ vboxLayout->addWidget(buttonBox);
+
+ // Generate text
+ QTextCursor cursor = m_textEdit->textCursor();
+ cursor.movePosition (QTextCursor::End);
+ foreach (const QFormScriptRunner::Error error, errors)
+ formatError(error, cursor);
+ }
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/scripterrordialog_p.h b/tools/designer/src/lib/shared/scripterrordialog_p.h
new file mode 100644
index 0000000..2a8b89a
--- /dev/null
+++ b/tools/designer/src/lib/shared/scripterrordialog_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 SCRIPTERRORDIALOG_H
+#define SCRIPTERRORDIALOG_H
+
+#include "shared_global_p.h"
+#include "formscriptrunner_p.h"
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+
+class QTextEdit;
+
+namespace qdesigner_internal {
+
+ // Dialog for showing script errors
+ class QDESIGNER_SHARED_EXPORT ScriptErrorDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ typedef QFormScriptRunner::Errors Errors;
+ ScriptErrorDialog(const Errors& errors, QWidget *parent);
+
+ private:
+ QTextEdit *m_textEdit;
+
+ };
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // SCRIPTERRORDIALOG_H
diff --git a/tools/designer/src/lib/shared/selectsignaldialog.ui b/tools/designer/src/lib/shared/selectsignaldialog.ui
new file mode 100644
index 0000000..99387dd
--- /dev/null
+++ b/tools/designer/src/lib/shared/selectsignaldialog.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SelectSignalDialog</class>
+ <widget class="QDialog" name="SelectSignalDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>514</width>
+ <height>183</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Go to slot</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Select signal</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTreeWidget" name="signalList">
+ <property name="sortingEnabled">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>signal</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>class</string>
+ </property>
+ </column>
+ </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::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SelectSignalDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>335</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SelectSignalDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>325</x>
+ <y>335</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/designer/src/lib/shared/shared.pri b/tools/designer/src/lib/shared/shared.pri
new file mode 100644
index 0000000..8ed051a
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared.pri
@@ -0,0 +1,189 @@
+
+INCLUDEPATH += $$PWD
+QT += script
+
+include($$QT_SOURCE_TREE/tools/shared/qtpropertybrowser/qtpropertybrowser.pri)
+include($$QT_SOURCE_TREE/tools/shared/deviceskin/deviceskin.pri)
+include($$QT_SOURCE_TREE/src/tools/rcc/rcc.pri)
+include($$QT_SOURCE_TREE/tools/shared/findwidget/findwidget.pri)
+include($$QT_SOURCE_TREE/tools/shared/qtgradienteditor/qtgradienteditor.pri)
+
+# Input
+FORMS += $$PWD/addlinkdialog.ui \
+ $$PWD/orderdialog.ui \
+ $$PWD/newactiondialog.ui \
+ $$PWD/gridpanel.ui \
+ $$PWD/signalslotdialog.ui \
+ $$PWD/previewconfigurationwidget.ui \
+ $$PWD/qtresourceeditordialog.ui \
+ $$PWD/newformwidget.ui \
+ $$PWD/selectsignaldialog.ui \
+ $$PWD/formlayoutrowdialog.ui \
+ $$PWD/plugindialog.ui
+
+HEADERS += \
+ $$PWD/shared_global_p.h \
+ $$PWD/spacer_widget_p.h \
+ $$PWD/layoutinfo_p.h \
+ $$PWD/layout_p.h \
+ $$PWD/connectionedit_p.h \
+ $$PWD/pluginmanager_p.h \
+ $$PWD/metadatabase_p.h \
+ $$PWD/qdesigner_formeditorcommand_p.h \
+ $$PWD/qdesigner_formwindowcommand_p.h \
+ $$PWD/qdesigner_command_p.h \
+ $$PWD/morphmenu_p.h \
+ $$PWD/qdesigner_command2_p.h \
+ $$PWD/qdesigner_formbuilder_p.h \
+ $$PWD/qdesigner_taskmenu_p.h \
+ $$PWD/formlayoutmenu_p.h \
+ $$PWD/qdesigner_widget_p.h \
+ $$PWD/qdesigner_propertysheet_p.h \
+ $$PWD/qdesigner_membersheet_p.h \
+ $$PWD/qdesigner_propertyeditor_p.h \
+ $$PWD/qdesigner_objectinspector_p.h \
+ $$PWD/qdesigner_integration_p.h \
+ $$PWD/invisible_widget_p.h \
+ $$PWD/qlayout_widget_p.h \
+ $$PWD/sheet_delegate_p.h \
+ $$PWD/qdesigner_stackedbox_p.h \
+ $$PWD/qdesigner_tabwidget_p.h \
+ $$PWD/qdesigner_dockwidget_p.h \
+ $$PWD/qdesigner_toolbox_p.h \
+ $$PWD/qdesigner_dnditem_p.h \
+ $$PWD/qsimpleresource_p.h \
+ $$PWD/widgetfactory_p.h \
+ $$PWD/widgetdatabase_p.h \
+ $$PWD/qdesigner_promotion_p.h \
+ $$PWD/qdesigner_introspection_p.h \
+ $$PWD/promotionmodel_p.h \
+ $$PWD/qdesigner_promotiondialog_p.h \
+ $$PWD/iconloader_p.h \
+ $$PWD/richtexteditor_p.h \
+ $$PWD/plaintexteditor_p.h \
+ $$PWD/actioneditor_p.h \
+ $$PWD/actionrepository_p.h \
+ $$PWD/qdesigner_toolbar_p.h \
+ $$PWD/qdesigner_menubar_p.h \
+ $$PWD/qdesigner_menu_p.h \
+ $$PWD/actionprovider_p.h \
+ $$PWD/orderdialog_p.h \
+ $$PWD/newactiondialog_p.h \
+ $$PWD/stylesheeteditor_p.h \
+ $$PWD/csshighlighter_p.h \
+ $$PWD/shared_enums_p.h \
+ $$PWD/textpropertyeditor_p.h \
+ $$PWD/propertylineedit_p.h \
+ $$PWD/promotiontaskmenu_p.h \
+ $$PWD/scripterrordialog_p.h \
+ $$PWD/scriptcommand_p.h \
+ $$PWD/scriptdialog_p.h \
+ $$PWD/qscripthighlighter_p.h \
+ $$PWD/gridpanel_p.h \
+ $$PWD/grid_p.h \
+ $$PWD/formwindowbase_p.h \
+ $$PWD/qdesigner_utils_p.h \
+ $$PWD/qdesigner_widgetbox_p.h \
+ $$PWD/signalslotdialog_p.h \
+ $$PWD/extensionfactory_p.h \
+ $$PWD/dialoggui_p.h \
+ $$PWD/deviceprofile_p.h \
+ $$PWD/zoomwidget_p.h \
+ $$PWD/previewmanager_p.h \
+ $$PWD/previewconfigurationwidget_p.h \
+ $$PWD/codedialog_p.h \
+ $$PWD/qtresourceeditordialog_p.h \
+ $$PWD/qtresourcemodel_p.h \
+ $$PWD/qtresourceview_p.h \
+ $$PWD/iconselector_p.h \
+ $$PWD/htmlhighlighter_p.h \
+ $$PWD/qdesigner_widgetitem_p.h \
+ $$PWD/qdesigner_qsettings_p.h \
+ $$PWD/qdesigner_formwindowmanager_p.h \
+ $$PWD/shared_settings_p.h \
+ $$PWD/newformwidget_p.h \
+ $$PWD/filterwidget_p.h \
+ $$PWD/plugindialog_p.h
+
+SOURCES += \
+ $$PWD/spacer_widget.cpp \
+ $$PWD/layoutinfo.cpp \
+ $$PWD/layout.cpp \
+ $$PWD/connectionedit.cpp \
+ $$PWD/pluginmanager.cpp \
+ $$PWD/qdesigner_formwindowcommand.cpp \
+ $$PWD/qdesigner_formeditorcommand.cpp \
+ $$PWD/qdesigner_command.cpp \
+ $$PWD/morphmenu.cpp \
+ $$PWD/qdesigner_command2.cpp \
+ $$PWD/qdesigner_propertycommand.cpp \
+ $$PWD/qdesigner_formbuilder.cpp \
+ $$PWD/qdesigner_taskmenu.cpp \
+ $$PWD/formlayoutmenu.cpp \
+ $$PWD/qdesigner_widget.cpp \
+ $$PWD/qdesigner_dockwidget.cpp \
+ $$PWD/qdesigner_propertysheet.cpp \
+ $$PWD/qdesigner_membersheet.cpp \
+ $$PWD/qdesigner_propertyeditor.cpp \
+ $$PWD/qdesigner_objectinspector.cpp \
+ $$PWD/qdesigner_integration.cpp \
+ $$PWD/qdesigner_dnditem.cpp \
+ $$PWD/qsimpleresource.cpp \
+ $$PWD/invisible_widget.cpp \
+ $$PWD/qlayout_widget.cpp \
+ $$PWD/sheet_delegate.cpp \
+ $$PWD/metadatabase.cpp \
+ $$PWD/qdesigner_stackedbox.cpp \
+ $$PWD/qdesigner_tabwidget.cpp \
+ $$PWD/qdesigner_toolbox.cpp \
+ $$PWD/widgetfactory.cpp \
+ $$PWD/widgetdatabase.cpp \
+ $$PWD/qdesigner_promotion.cpp \
+ $$PWD/qdesigner_introspection.cpp \
+ $$PWD/promotionmodel.cpp \
+ $$PWD/qdesigner_promotiondialog.cpp \
+ $$PWD/richtexteditor.cpp \
+ $$PWD/plaintexteditor.cpp \
+ $$PWD/actioneditor.cpp \
+ $$PWD/actionrepository.cpp \
+ $$PWD/qdesigner_toolbar.cpp \
+ $$PWD/qdesigner_menubar.cpp \
+ $$PWD/qdesigner_menu.cpp \
+ $$PWD/orderdialog.cpp \
+ $$PWD/newactiondialog.cpp \
+ $$PWD/stylesheeteditor.cpp \
+ $$PWD/csshighlighter.cpp \
+ $$PWD/textpropertyeditor.cpp \
+ $$PWD/propertylineedit.cpp \
+ $$PWD/promotiontaskmenu.cpp \
+ $$PWD/scripterrordialog.cpp \
+ $$PWD/scriptcommand.cpp \
+ $$PWD/scriptdialog.cpp \
+ $$PWD/qscripthighlighter.cpp\
+ $$PWD/gridpanel.cpp \
+ $$PWD/grid.cpp \
+ $$PWD/formwindowbase.cpp \
+ $$PWD/qdesigner_utils.cpp \
+ $$PWD/qdesigner_widgetbox.cpp \
+ $$PWD/iconloader.cpp \
+ $$PWD/signalslotdialog.cpp \
+ $$PWD/dialoggui.cpp \
+ $$PWD/deviceprofile.cpp \
+ $$PWD/zoomwidget.cpp \
+ $$PWD/previewmanager.cpp \
+ $$PWD/previewconfigurationwidget.cpp \
+ $$PWD/codedialog.cpp \
+ $$PWD/qtresourceeditordialog.cpp \
+ $$PWD/qtresourcemodel.cpp \
+ $$PWD/qtresourceview.cpp \
+ $$PWD/iconselector.cpp \
+ $$PWD/htmlhighlighter.cpp \
+ $$PWD/qdesigner_widgetitem.cpp \
+ $$PWD/qdesigner_qsettings.cpp \
+ $$PWD/qdesigner_formwindowmanager.cpp \
+ $$PWD/shared_settings.cpp \
+ $$PWD/newformwidget.cpp \
+ $$PWD/filterwidget.cpp \
+ $$PWD/plugindialog.cpp
+
+RESOURCES += $$PWD/shared.qrc
diff --git a/tools/designer/src/lib/shared/shared.qrc b/tools/designer/src/lib/shared/shared.qrc
new file mode 100644
index 0000000..81be807
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared.qrc
@@ -0,0 +1,20 @@
+<RCC>
+ <qresource prefix="/trolltech/designer">
+ <file>defaultgradients.xml</file>
+ <!-- Templates -->
+ <file>templates/forms/Dialog_with_Buttons_Bottom.ui</file>
+ <file>templates/forms/240x320/Dialog_with_Buttons_Bottom.ui</file>
+ <file>templates/forms/320x240/Dialog_with_Buttons_Bottom.ui</file>
+ <file>templates/forms/480x640/Dialog_with_Buttons_Bottom.ui</file>
+ <file>templates/forms/640x480/Dialog_with_Buttons_Bottom.ui</file>
+ <file>templates/forms/Dialog_with_Buttons_Right.ui</file>
+ <file>templates/forms/240x320/Dialog_with_Buttons_Right.ui</file>
+ <file>templates/forms/320x240/Dialog_with_Buttons_Right.ui</file>
+ <file>templates/forms/480x640/Dialog_with_Buttons_Right.ui</file>
+ <file>templates/forms/640x480/Dialog_with_Buttons_Right.ui</file>
+ <file>templates/forms/Dialog_without_Buttons.ui</file>
+ <file>templates/forms/Widget.ui</file>
+ <file>templates/forms/Main_Window.ui</file>
+ </qresource>
+</RCC>
+
diff --git a/tools/designer/src/lib/shared/shared_enums_p.h b/tools/designer/src/lib/shared/shared_enums_p.h
new file mode 100644
index 0000000..838b9d0
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared_enums_p.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$
+**
+****************************************************************************/
+
+//
+// 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 SHAREDENUMS_H
+#define SHAREDENUMS_H
+
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+ // Validation mode of text property line edits
+ enum TextPropertyValidationMode {
+ // Allow for multiline editing using literal "\n".
+ ValidationMultiLine,
+ // Allow for HTML rich text including multiline editing using literal "\n".
+ ValidationRichText,
+ // Validate a stylesheet
+ ValidationStyleSheet,
+ // Single line mode, suppresses newlines
+ ValidationSingleLine,
+ // Allow only for identifier characters
+ ValidationObjectName,
+ // Allow only for identifier characters and colons
+ ValidationObjectNameScope,
+ // URL
+ ValidationURL
+ };
+
+ // Container types
+ enum ContainerType {
+ // A container with pages, at least one of which one must always be present (for example, QTabWidget)
+ PageContainer,
+ // Mdi type container. All pages may be deleted, no concept of page order
+ MdiContainer,
+ // Wizard container
+ WizardContainer
+ };
+
+ enum AuxiliaryItemDataRoles {
+ // item->flags while being edited
+ ItemFlagsShadowRole = 0x13370551
+ };
+
+}
+
+QT_END_NAMESPACE
+
+#endif // SHAREDENUMS_H
diff --git a/tools/designer/src/lib/shared/shared_global_p.h b/tools/designer/src/lib/shared/shared_global_p.h
new file mode 100644
index 0000000..277472c
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared_global_p.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$
+**
+****************************************************************************/
+
+//
+// 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 SHARED_GLOBAL_H
+#define SHARED_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_DESIGNER_STATIC
+#define QDESIGNER_SHARED_EXTERN
+#define QDESIGNER_SHARED_IMPORT
+#else
+#define QDESIGNER_SHARED_EXTERN Q_DECL_EXPORT
+#define QDESIGNER_SHARED_IMPORT Q_DECL_IMPORT
+#endif
+
+#ifndef QT_NO_SHARED_EXPORT
+# ifdef QDESIGNER_SHARED_LIBRARY
+# define QDESIGNER_SHARED_EXPORT QDESIGNER_SHARED_EXTERN
+# else
+# define QDESIGNER_SHARED_EXPORT QDESIGNER_SHARED_IMPORT
+# endif
+#else
+# define QDESIGNER_SHARED_EXPORT
+#endif
+
+#endif // SHARED_GLOBAL_H
diff --git a/tools/designer/src/lib/shared/shared_settings.cpp b/tools/designer/src/lib/shared/shared_settings.cpp
new file mode 100644
index 0000000..c97dd3b
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared_settings.cpp
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** 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 "shared_settings_p.h"
+#include "grid_p.h"
+#include "previewmanager_p.h"
+#include "qdesigner_utils_p.h"
+#include <QtDesigner/abstractformeditor.h>
+#include <QtDesigner/private/abstractsettings_p.h>
+#include <QtCore/QStringList>
+#include <QtCore/QDir>
+#include <QtCore/QVariantMap>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSize>
+
+QT_BEGIN_NAMESPACE
+
+static const char *designerPath = "/.designer";
+static const char *defaultGridKey = "defaultGrid";
+static const char *previewKey = "Preview";
+static const char *enabledKey = "Enabled";
+static const char *userDeviceSkinsKey= "UserDeviceSkins";
+static const char *zoomKey = "zoom";
+static const char *zoomEnabledKey = "zoomEnabled";
+static const char *deviceProfileIndexKey = "DeviceProfileIndex";
+static const char *deviceProfilesKey = "DeviceProfiles";
+static const char *formTemplatePathsKey = "FormTemplatePaths";
+static const char *formTemplateKey = "FormTemplate";
+static const char *newFormSizeKey = "NewFormSize";
+
+using namespace qdesigner_internal;
+
+static bool checkTemplatePath(const QString &path, bool create)
+{
+ QDir current(QDir::current());
+ if (current.exists(path))
+ return true;
+
+ if (!create)
+ return false;
+
+ if (current.mkpath(path))
+ return true;
+
+ qdesigner_internal::designerWarning(QCoreApplication::translate("QDesignerSharedSettings", "The template path %1 could not be created.").arg(path));
+ return false;
+}
+
+namespace qdesigner_internal {
+
+QDesignerSharedSettings::QDesignerSharedSettings(QDesignerFormEditorInterface *core)
+ : m_settings(core->settingsManager())
+{
+}
+
+Grid QDesignerSharedSettings::defaultGrid() const
+{
+ Grid grid;
+ const QVariantMap defaultGridMap
+ = m_settings->value(QLatin1String(defaultGridKey), QVariantMap()).toMap();
+ if (!defaultGridMap.empty())
+ grid.fromVariantMap(defaultGridMap);
+ return grid;
+}
+
+void QDesignerSharedSettings::setDefaultGrid(const Grid &grid)
+{
+ m_settings->setValue(QLatin1String(defaultGridKey), grid.toVariantMap());
+}
+
+const QStringList &QDesignerSharedSettings::defaultFormTemplatePaths()
+{
+ static QStringList rc;
+ if (rc.empty()) {
+ // Ensure default form template paths
+ const QString templatePath = QLatin1String("/templates");
+ // home
+ QString path = QDir::homePath();
+ path += QLatin1String(designerPath);
+ path += templatePath;
+ if (checkTemplatePath(path, true))
+ rc += path;
+
+ // designer/bin: Might be owned by root in some installations, do not force it.
+ path = qApp->applicationDirPath();
+ path += templatePath;
+ if (checkTemplatePath(path, false))
+ rc += path;
+ }
+ return rc;
+}
+
+QStringList QDesignerSharedSettings::formTemplatePaths() const
+{
+ return m_settings->value(QLatin1String(formTemplatePathsKey),
+ defaultFormTemplatePaths()).toStringList();
+}
+
+void QDesignerSharedSettings::setFormTemplatePaths(const QStringList &paths)
+{
+ m_settings->setValue(QLatin1String(formTemplatePathsKey), paths);
+}
+
+QString QDesignerSharedSettings::formTemplate() const
+{
+ return m_settings->value(QLatin1String(formTemplateKey)).toString();
+}
+
+void QDesignerSharedSettings::setFormTemplate(const QString &t)
+{
+ m_settings->setValue(QLatin1String(formTemplateKey), t);
+}
+
+void QDesignerSharedSettings::setAdditionalFormTemplatePaths(const QStringList &additionalPaths)
+{
+ // merge template paths
+ QStringList templatePaths = defaultFormTemplatePaths();
+ templatePaths += additionalPaths;
+ setFormTemplatePaths(templatePaths);
+}
+
+QStringList QDesignerSharedSettings::additionalFormTemplatePaths() const
+{
+ // get template paths excluding internal ones
+ QStringList rc = formTemplatePaths();
+ foreach (QString internalTemplatePath, defaultFormTemplatePaths()) {
+ const int index = rc.indexOf(internalTemplatePath);
+ if (index != -1)
+ rc.removeAt(index);
+ }
+ return rc;
+}
+
+QSize QDesignerSharedSettings::newFormSize() const
+{
+ return m_settings->value(QLatin1String(newFormSizeKey), QSize(0, 0)).toSize();
+}
+
+void QDesignerSharedSettings::setNewFormSize(const QSize &s)
+{
+ if (s.isNull()) {
+ m_settings->remove(QLatin1String(newFormSizeKey));
+ } else {
+ m_settings->setValue(QLatin1String(newFormSizeKey), s);
+ }
+}
+
+
+PreviewConfiguration QDesignerSharedSettings::customPreviewConfiguration() const
+{
+ PreviewConfiguration configuration;
+ configuration.fromSettings(QLatin1String(previewKey), m_settings);
+ return configuration;
+}
+
+void QDesignerSharedSettings::setCustomPreviewConfiguration(const PreviewConfiguration &configuration)
+{
+ configuration.toSettings(QLatin1String(previewKey), m_settings);
+}
+
+bool QDesignerSharedSettings::isCustomPreviewConfigurationEnabled() const
+{
+ m_settings->beginGroup(QLatin1String(previewKey));
+ bool isEnabled = m_settings->value(QLatin1String(enabledKey), false).toBool();
+ m_settings->endGroup();
+ return isEnabled;
+}
+
+void QDesignerSharedSettings::setCustomPreviewConfigurationEnabled(bool enabled)
+{
+ m_settings->beginGroup(QLatin1String(previewKey));
+ m_settings->setValue(QLatin1String(enabledKey), enabled);
+ m_settings->endGroup();
+}
+
+QStringList QDesignerSharedSettings::userDeviceSkins() const
+{
+ m_settings->beginGroup(QLatin1String(previewKey));
+ QStringList userDeviceSkins
+ = m_settings->value(QLatin1String(userDeviceSkinsKey), QStringList()).toStringList();
+ m_settings->endGroup();
+ return userDeviceSkins;
+}
+
+void QDesignerSharedSettings::setUserDeviceSkins(const QStringList &userDeviceSkins)
+{
+ m_settings->beginGroup(QLatin1String(previewKey));
+ m_settings->setValue(QLatin1String(userDeviceSkinsKey), userDeviceSkins);
+ m_settings->endGroup();
+}
+
+int QDesignerSharedSettings::zoom() const
+{
+ return m_settings->value(QLatin1String(zoomKey), 100).toInt();
+}
+
+void QDesignerSharedSettings::setZoom(int z)
+{
+ m_settings->setValue(QLatin1String(zoomKey), QVariant(z));
+}
+
+bool QDesignerSharedSettings::zoomEnabled() const
+{
+ return m_settings->value(QLatin1String(zoomEnabledKey), false).toBool();
+}
+
+void QDesignerSharedSettings::setZoomEnabled(bool v)
+{
+ m_settings->setValue(QLatin1String(zoomEnabledKey), v);
+}
+
+DeviceProfile QDesignerSharedSettings::currentDeviceProfile() const
+{
+ return deviceProfileAt(currentDeviceProfileIndex());
+}
+
+void QDesignerSharedSettings::setCurrentDeviceProfileIndex(int i)
+{
+ m_settings->setValue(QLatin1String(deviceProfileIndexKey), i);
+}
+
+int QDesignerSharedSettings::currentDeviceProfileIndex() const
+{
+ return m_settings->value(QLatin1String(deviceProfileIndexKey), -1).toInt();
+}
+
+static inline QString msgWarnDeviceProfileXml(const QString &msg)
+{
+ return QCoreApplication::translate("QDesignerSharedSettings", "An error has been encountered while parsing device profile XML: %1").arg(msg);
+}
+
+DeviceProfile QDesignerSharedSettings::deviceProfileAt(int idx) const
+{
+ DeviceProfile rc;
+ if (idx < 0)
+ return rc;
+ const QStringList xmls = deviceProfileXml();
+ if (idx >= xmls.size())
+ return rc;
+ QString errorMessage;
+ if (!rc.fromXml(xmls.at(idx), &errorMessage)) {
+ rc.clear();
+ designerWarning(msgWarnDeviceProfileXml(errorMessage));
+ }
+ return rc;
+}
+
+QStringList QDesignerSharedSettings::deviceProfileXml() const
+{
+ return m_settings->value(QLatin1String(deviceProfilesKey), QStringList()).toStringList();
+}
+
+QDesignerSharedSettings::DeviceProfileList QDesignerSharedSettings::deviceProfiles() const
+{
+ DeviceProfileList rc;
+ const QStringList xmls = deviceProfileXml();
+ if (xmls.empty())
+ return rc;
+ // De-serialize
+ QString errorMessage;
+ DeviceProfile dp;
+ const QStringList::const_iterator scend = xmls.constEnd();
+ for (QStringList::const_iterator it = xmls.constBegin(); it != scend; ++it) {
+ if (dp.fromXml(*it, &errorMessage)) {
+ rc.push_back(dp);
+ } else {
+ designerWarning(msgWarnDeviceProfileXml(errorMessage));
+ }
+ }
+ return rc;
+}
+
+void QDesignerSharedSettings::setDeviceProfiles(const DeviceProfileList &dp)
+{
+ QStringList l;
+ const DeviceProfileList::const_iterator dcend = dp.constEnd();
+ for (DeviceProfileList::const_iterator it = dp.constBegin(); it != dcend; ++it)
+ l.push_back(it->toXml());
+ m_settings->setValue(QLatin1String(deviceProfilesKey), l);
+}
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/shared_settings_p.h b/tools/designer/src/lib/shared/shared_settings_p.h
new file mode 100644
index 0000000..c021b00
--- /dev/null
+++ b/tools/designer/src/lib/shared/shared_settings_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 SHARED_SETTINGS_H
+#define SHARED_SETTINGS_H
+
+#include "shared_global_p.h"
+#include "deviceprofile_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerSettingsInterface;
+
+class QStringList;
+class QSize;
+
+namespace qdesigner_internal {
+class Grid;
+class PreviewConfiguration;
+}
+
+/*!
+ Auxiliary methods to store/retrieve settings
+ */
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT QDesignerSharedSettings {
+public:
+ typedef QList<DeviceProfile> DeviceProfileList;
+
+ explicit QDesignerSharedSettings(QDesignerFormEditorInterface *core);
+
+ Grid defaultGrid() const;
+ void setDefaultGrid(const Grid &grid);
+
+ QStringList formTemplatePaths() const;
+ void setFormTemplatePaths(const QStringList &paths);
+
+ void setAdditionalFormTemplatePaths(const QStringList &additionalPaths);
+ QStringList additionalFormTemplatePaths() const;
+
+ QString formTemplate() const;
+ void setFormTemplate(const QString &t);
+
+ QSize newFormSize() const;
+ void setNewFormSize(const QSize &s);
+
+ // Check with isCustomPreviewConfigurationEnabled if custom or default
+ // configuration should be used.
+ PreviewConfiguration customPreviewConfiguration() const;
+ void setCustomPreviewConfiguration(const PreviewConfiguration &configuration);
+
+ bool isCustomPreviewConfigurationEnabled() const;
+ void setCustomPreviewConfigurationEnabled(bool enabled);
+
+ QStringList userDeviceSkins() const;
+ void setUserDeviceSkins(const QStringList &userDeviceSkins);
+
+ bool zoomEnabled() const;
+ void setZoomEnabled(bool v);
+
+ // Zoom in percent
+ int zoom() const;
+ void setZoom(int z);
+
+ // Embedded Design
+ DeviceProfile currentDeviceProfile() const;
+ void setCurrentDeviceProfileIndex(int i);
+ int currentDeviceProfileIndex() const;
+
+ DeviceProfile deviceProfileAt(int idx) const;
+ DeviceProfileList deviceProfiles() const;
+ void setDeviceProfiles(const DeviceProfileList &dp);
+
+ static const QStringList &defaultFormTemplatePaths();
+
+protected:
+ QDesignerSettingsInterface *settings() const { return m_settings; }
+
+private:
+ QStringList deviceProfileXml() const;
+ QDesignerSettingsInterface *m_settings;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // SHARED_SETTINGS_H
diff --git a/tools/designer/src/lib/shared/sheet_delegate.cpp b/tools/designer/src/lib/shared/sheet_delegate.cpp
new file mode 100644
index 0000000..c0722bb
--- /dev/null
+++ b/tools/designer/src/lib/shared/sheet_delegate.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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 "sheet_delegate_p.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtGui/QTreeView>
+#include <QtGui/QStyle>
+#include <QtGui/QPainter>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+SheetDelegate::SheetDelegate(QTreeView *view, QWidget *parent)
+ : QItemDelegate(parent),
+ m_view(view)
+{
+}
+
+void SheetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ const QAbstractItemModel *model = index.model();
+ Q_ASSERT(model);
+
+ if (!model->parent(index).isValid()) {
+ // this is a top-level item.
+ QStyleOptionButton buttonOption;
+
+ buttonOption.state = option.state;
+#ifdef Q_WS_MAC
+ buttonOption.state |= QStyle::State_Raised;
+#endif
+ buttonOption.state &= ~QStyle::State_HasFocus;
+
+ buttonOption.rect = option.rect;
+ buttonOption.palette = option.palette;
+ buttonOption.features = QStyleOptionButton::None;
+ m_view->style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter, m_view);
+
+ QStyleOption branchOption;
+ static const int i = 9; // ### hardcoded in qcommonstyle.cpp
+ QRect r = option.rect;
+ branchOption.rect = QRect(r.left() + i/2, r.top() + (r.height() - i)/2, i, i);
+ branchOption.palette = option.palette;
+ branchOption.state = QStyle::State_Children;
+
+ if (m_view->isExpanded(index))
+ branchOption.state |= QStyle::State_Open;
+
+ m_view->style()->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, painter, m_view);
+
+ // draw text
+ QRect textrect = QRect(r.left() + i*2, r.top(), r.width() - ((5*i)/2), r.height());
+ QString text = elidedText(option.fontMetrics, textrect.width(), Qt::ElideMiddle,
+ model->data(index, Qt::DisplayRole).toString());
+ m_view->style()->drawItemText(painter, textrect, Qt::AlignCenter,
+ option.palette, m_view->isEnabled(), text);
+
+ } else {
+ QItemDelegate::paint(painter, option, index);
+ }
+}
+
+QSize SheetDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
+{
+ QStyleOptionViewItem option = opt;
+ QSize sz = QItemDelegate::sizeHint(opt, index) + QSize(2, 2);
+ return sz;
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/sheet_delegate_p.h b/tools/designer/src/lib/shared/sheet_delegate_p.h
new file mode 100644
index 0000000..a3d70df
--- /dev/null
+++ b/tools/designer/src/lib/shared/sheet_delegate_p.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$
+**
+****************************************************************************/
+
+//
+// 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 SHEET_DELEGATE_H
+#define SHEET_DELEGATE_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QItemDelegate>
+#include <QtGui/QTreeView>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeView;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT SheetDelegate: public QItemDelegate
+{
+ Q_OBJECT
+public:
+ SheetDelegate(QTreeView *view, QWidget *parent);
+
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ virtual QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const;
+
+private:
+ QTreeView *m_view;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // SHEET_DELEGATE_H
diff --git a/tools/designer/src/lib/shared/signalslotdialog.cpp b/tools/designer/src/lib/shared/signalslotdialog.cpp
new file mode 100644
index 0000000..a23d228
--- /dev/null
+++ b/tools/designer/src/lib/shared/signalslotdialog.cpp
@@ -0,0 +1,526 @@
+/****************************************************************************
+**
+** 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 "signalslotdialog_p.h"
+#include "ui_signalslotdialog.h"
+#include "metadatabase_p.h"
+#include "widgetdatabase_p.h"
+
+#include "qdesigner_formwindowcommand_p.h"
+#include "iconloader_p.h"
+
+#include <QtDesigner/QDesignerMemberSheetExtension>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <abstractdialoggui_p.h>
+
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QRegExpValidator>
+#include <QtGui/QItemDelegate>
+#include <QtGui/QLineEdit>
+#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
+
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+// Regexp to match a function signature, arguments potentially
+// with namespace colons.
+static const char *signatureRegExp = "^[\\w+_]+\\(([\\w+:]\\*?,?)*\\)$";
+static const char *methodNameRegExp = "^[\\w+_]+$";
+
+static QStandardItem *createEditableItem(const QString &text)
+{
+ QStandardItem *rc = new QStandardItem(text);
+ rc->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable);
+ return rc;
+}
+
+static QStandardItem *createDisabledItem(const QString &text)
+{
+ QStandardItem *rc = new QStandardItem(text);
+ Qt::ItemFlags flags = rc->flags();
+ rc->setFlags(flags & ~(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable));
+ return rc;
+}
+
+static void fakeMethodsFromMetaDataBase(QDesignerFormEditorInterface *core, QObject *o, QStringList &slotList, QStringList &signalList)
+{
+ slotList.clear();
+ signalList.clear();
+ if (qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase()))
+ if (const qdesigner_internal::MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(o)) {
+ slotList = item->fakeSlots();
+ signalList = item->fakeSignals();
+ }
+}
+
+static void fakeMethodsToMetaDataBase(QDesignerFormEditorInterface *core, QObject *o, const QStringList &slotList, const QStringList &signalList)
+{
+ if (qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase())) {
+ qdesigner_internal::MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(o);
+ Q_ASSERT(item);
+ item->setFakeSlots(slotList);
+ item->setFakeSignals(signalList);
+ }
+}
+
+static void existingMethodsFromMemberSheet(QDesignerFormEditorInterface *core,
+ QObject *o,
+ QStringList &slotList, QStringList &signalList)
+{
+ slotList.clear();
+ signalList.clear();
+
+ QDesignerMemberSheetExtension *msheet = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), o);
+ if (!msheet)
+ return;
+
+ for (int i = 0, count = msheet->count(); i < count; ++i)
+ if (msheet->isVisible(i)) {
+ if (msheet->isSlot(i))
+ slotList += msheet->signature(i);
+ else
+ if (msheet->isSignal(i))
+ signalList += msheet->signature(i);
+ }
+}
+
+namespace {
+ // Internal helper class: A Delegate that validates using RegExps and additionally checks
+ // on closing (adds missing parentheses).
+ class SignatureDelegate : public QItemDelegate {
+ public:
+ SignatureDelegate(QObject * parent = 0);
+ virtual QWidget * createEditor (QWidget * parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
+ virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+
+ private:
+ const QRegExp m_signatureRegexp;
+ const QRegExp m_methodNameRegexp;
+ };
+
+ SignatureDelegate::SignatureDelegate(QObject * parent) :
+ QItemDelegate(parent),
+ m_signatureRegexp(QLatin1String(signatureRegExp)),
+ m_methodNameRegexp(QLatin1String(methodNameRegExp))
+ {
+ Q_ASSERT(m_signatureRegexp.isValid());
+ Q_ASSERT(m_methodNameRegexp.isValid());
+ }
+
+ QWidget * SignatureDelegate::createEditor ( QWidget * parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
+ {
+ QWidget *rc = QItemDelegate::createEditor(parent, option, index);
+ QLineEdit *le = qobject_cast<QLineEdit *>(rc);
+ Q_ASSERT(le);
+ le->setValidator(new QRegExpValidator(m_signatureRegexp, le));
+ return rc;
+ }
+
+ void SignatureDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
+ {
+ QLineEdit *le = qobject_cast<QLineEdit *>(editor);
+ Q_ASSERT(le);
+ // Did the user just type a name? .. Add parentheses
+ QString signature = le->text();
+ if (!m_signatureRegexp.exactMatch(signature )) {
+ if (m_methodNameRegexp.exactMatch(signature )) {
+ signature += QLatin1String("()");
+ le->setText(signature);
+ } else {
+ return;
+ }
+ }
+ QItemDelegate::setModelData(editor, model, index);
+ }
+
+ // ------ FakeMethodMetaDBCommand: Undo Command to change fake methods in the meta DB.
+ class FakeMethodMetaDBCommand : public qdesigner_internal::QDesignerFormWindowCommand {
+
+ public:
+ explicit FakeMethodMetaDBCommand(QDesignerFormWindowInterface *formWindow);
+
+ void init(QObject *o,
+ const QStringList &oldFakeSlots, const QStringList &oldFakeSignals,
+ const QStringList &newFakeSlots, const QStringList &newFakeSignals);
+
+ virtual void undo() { fakeMethodsToMetaDataBase(core(), m_object, m_oldFakeSlots, m_oldFakeSignals); }
+ virtual void redo() { fakeMethodsToMetaDataBase(core(), m_object, m_newFakeSlots, m_newFakeSignals); }
+
+ private:
+ QObject *m_object;
+ QStringList m_oldFakeSlots;
+ QStringList m_oldFakeSignals;
+ QStringList m_newFakeSlots;
+ QStringList m_newFakeSignals;
+ };
+
+ FakeMethodMetaDBCommand::FakeMethodMetaDBCommand(QDesignerFormWindowInterface *formWindow) :
+ qdesigner_internal::QDesignerFormWindowCommand(QApplication::translate("Command", "Change signals/slots"), formWindow),
+ m_object(0)
+ {
+ }
+
+ void FakeMethodMetaDBCommand::init(QObject *o,
+ const QStringList &oldFakeSlots, const QStringList &oldFakeSignals,
+ const QStringList &newFakeSlots, const QStringList &newFakeSignals)
+ {
+ m_object = o;
+ m_oldFakeSlots = oldFakeSlots;
+ m_oldFakeSignals = oldFakeSignals;
+ m_newFakeSlots = newFakeSlots;
+ m_newFakeSignals = newFakeSignals;
+ }
+}
+
+namespace qdesigner_internal {
+
+// ------ SignalSlotDialogData
+void SignalSlotDialogData::clear()
+{
+ m_existingMethods.clear();
+ m_fakeMethods.clear();
+}
+
+// ------ SignatureModel
+SignatureModel::SignatureModel(QObject *parent) :
+ QStandardItemModel(parent)
+{
+}
+
+bool SignatureModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role != Qt::EditRole)
+ return QStandardItemModel::setData(index, value, role);
+ // check via signal (unless it is the same), in which case we can't be bothered.
+ const QStandardItem *item = itemFromIndex(index);
+ Q_ASSERT(item);
+ const QString signature = value.toString();
+ if (item->text() == signature)
+ return true;
+
+ bool ok = true;
+ emit checkSignature(signature, &ok);
+ if (!ok)
+ return false;
+
+ return QStandardItemModel::setData(index, value, role);
+}
+
+// ------ SignaturePanel
+SignaturePanel::SignaturePanel(QObject *parent, QListView *listView, QToolButton *addButton, QToolButton *removeButton, const QString &newPrefix) :
+ QObject(parent),
+ m_newPrefix(newPrefix),
+ m_model(new SignatureModel(this)),
+ m_listView(listView),
+ m_removeButton(removeButton)
+{
+ m_removeButton->setEnabled(false);
+
+ connect(addButton, SIGNAL(clicked()), this, SLOT(slotAdd()));
+ connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove()));
+
+ m_listView->setModel(m_model);
+ SignatureDelegate *delegate = new SignatureDelegate(this);
+ m_listView->setItemDelegate(delegate);
+ connect(m_model, SIGNAL(checkSignature(QString,bool*)), this, SIGNAL(checkSignature(QString,bool*)));
+
+ connect(m_listView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
+ this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
+}
+
+void SignaturePanel::slotAdd()
+{
+ m_listView->selectionModel()->clearSelection();
+ // find unique name
+ for (int i = 1; ; i++) {
+ QString newSlot = m_newPrefix;
+ newSlot += QString::number(i); // Always add number, Avoid setting 'slot' for first entry
+ newSlot += QLatin1Char('(');
+ // check for function name independent of parameters
+ if (m_model->findItems(newSlot, Qt::MatchStartsWith, 0).empty()) {
+ newSlot += QLatin1Char(')');
+ QStandardItem * item = createEditableItem(newSlot);
+ m_model->appendRow(item);
+ const QModelIndex index = m_model->indexFromItem (item);
+ m_listView->setCurrentIndex (index);
+ m_listView->edit(index);
+ return;
+ }
+ }
+}
+
+int SignaturePanel::count(const QString &signature) const
+{
+ return m_model->findItems(signature).size();
+}
+
+void SignaturePanel::slotRemove()
+{
+ const QModelIndexList selectedIndexes = m_listView->selectionModel()->selectedIndexes ();
+ if (selectedIndexes.empty())
+ return;
+
+ closeEditor();
+ // scroll to previous
+ if (const int row = selectedIndexes.front().row())
+ m_listView->setCurrentIndex (selectedIndexes.front().sibling(row - 1, 0));
+
+ for (int i = selectedIndexes.size() - 1; i >= 0; i--)
+ qDeleteAll(m_model->takeRow(selectedIndexes[i].row()));
+}
+
+void SignaturePanel::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &)
+{
+ m_removeButton->setEnabled(!selected.indexes().empty());
+}
+
+void SignaturePanel::setData(const SignalSlotDialogData &d)
+{
+ m_model->clear();
+
+ QStandardItem *lastExisting = 0;
+ foreach(const QString &s, d.m_existingMethods) {
+ lastExisting = createDisabledItem(s);
+ m_model->appendRow(lastExisting);
+ }
+ foreach(const QString &s, d.m_fakeMethods)
+ m_model->appendRow(createEditableItem(s));
+ if (lastExisting)
+ m_listView->scrollTo(m_model->indexFromItem(lastExisting));
+}
+
+QStringList SignaturePanel::fakeMethods() const
+{
+ QStringList rc;
+ if (const int rowCount = m_model->rowCount())
+ for (int i = 0; i < rowCount; i++) {
+ const QStandardItem *item = m_model->item(i);
+ if (item->flags() & Qt::ItemIsEditable)
+ rc += item->text();
+ }
+ return rc;
+}
+
+void SignaturePanel::closeEditor()
+{
+ const QModelIndex idx = m_listView->currentIndex();
+ if (idx.isValid())
+ m_listView->closePersistentEditor(idx);
+}
+
+// ------ SignalSlotDialog
+
+SignalSlotDialog::SignalSlotDialog(QDesignerDialogGuiInterface *dialogGui, QWidget *parent, FocusMode mode) :
+ QDialog(parent),
+ m_focusMode(mode),
+ m_ui(new Ui::SignalSlotDialogClass),
+ m_dialogGui(dialogGui)
+{
+ setModal(true);
+ m_ui->setupUi(this);
+
+ const QIcon plusIcon = qdesigner_internal::createIconSet(QString::fromUtf8("plus.png"));
+ const QIcon minusIcon = qdesigner_internal::createIconSet(QString::fromUtf8("minus.png"));
+ m_ui->addSlotButton->setIcon(plusIcon);
+ m_ui->removeSlotButton->setIcon(minusIcon);
+ m_ui->addSignalButton->setIcon(plusIcon);
+ m_ui->removeSignalButton->setIcon(minusIcon);
+
+ m_slotPanel = new SignaturePanel(this, m_ui->slotListView, m_ui->addSlotButton, m_ui->removeSlotButton, QLatin1String("slot"));
+ m_signalPanel = new SignaturePanel(this, m_ui->signalListView, m_ui->addSignalButton, m_ui->removeSignalButton, QLatin1String("signal"));
+ connect(m_slotPanel, SIGNAL(checkSignature(QString,bool*)), this, SLOT(slotCheckSignature(QString,bool*)));
+ connect(m_signalPanel, SIGNAL(checkSignature(QString,bool*)), this, SLOT(slotCheckSignature(QString,bool*)));
+
+ connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ switch(m_focusMode) {
+ case FocusSlots:
+ m_ui->slotListView->setFocus(Qt::OtherFocusReason);
+ break;
+ case FocusSignals:
+ m_ui->signalListView->setFocus(Qt::OtherFocusReason);
+ break;
+ }
+}
+
+SignalSlotDialog::~SignalSlotDialog()
+{
+ delete m_ui;
+}
+
+void SignalSlotDialog::slotCheckSignature(const QString &signature, bool *ok)
+{
+ QString errorMessage;
+ do {
+ if (m_slotPanel->count(signature)) {
+ errorMessage = tr("There is already a slot with the signature '%1'.").arg(signature);
+ *ok = false;
+ break;
+ }
+ if (m_signalPanel->count(signature)) {
+ errorMessage = tr("There is already a signal with the signature '%1'.").arg(signature);
+ *ok = false;
+ break;
+ }
+ } while (false);
+ if (!*ok)
+ m_dialogGui->message(this, QDesignerDialogGuiInterface::SignalSlotDialogMessage,
+ QMessageBox::Warning, tr("%1 - Duplicate Signature").arg(windowTitle()), errorMessage, QMessageBox::Close);
+}
+
+QDialog::DialogCode SignalSlotDialog::showDialog(SignalSlotDialogData &slotData, SignalSlotDialogData &signalData)
+{
+ m_slotPanel->setData(slotData);
+ m_signalPanel->setData(signalData);
+
+ const DialogCode rc = static_cast<DialogCode>(exec());
+ if (rc == Rejected)
+ return rc;
+
+ slotData.m_fakeMethods = m_slotPanel->fakeMethods();
+ signalData.m_fakeMethods = m_signalPanel->fakeMethods();
+ return rc;
+}
+
+bool SignalSlotDialog::editMetaDataBase(QDesignerFormWindowInterface *fw, QObject *object, QWidget *parent, FocusMode mode)
+{
+ QDesignerFormEditorInterface *core = fw->core();
+ SignalSlotDialog dlg(core->dialogGui(), parent, mode);
+ dlg.setWindowTitle(tr("Signals/Slots of %1").arg(object->objectName()));
+
+ SignalSlotDialogData slotData;
+ SignalSlotDialogData signalData;
+
+ existingMethodsFromMemberSheet(core, object, slotData.m_existingMethods, signalData.m_existingMethods);
+ fakeMethodsFromMetaDataBase(core, object, slotData.m_fakeMethods, signalData.m_fakeMethods);
+
+ const QStringList oldSlots = slotData.m_fakeMethods;
+ const QStringList oldSignals = signalData.m_fakeMethods;
+
+ if (dlg.showDialog(slotData, signalData) == QDialog::Rejected)
+ return false;
+
+ if (oldSlots == slotData.m_fakeMethods && oldSignals == signalData.m_fakeMethods)
+ return false;
+
+ FakeMethodMetaDBCommand *cmd = new FakeMethodMetaDBCommand(fw);
+ cmd->init(object, oldSlots, oldSignals, slotData.m_fakeMethods, signalData.m_fakeMethods);
+ fw->commandHistory()->push(cmd);
+ return true;
+}
+
+bool SignalSlotDialog::editPromotedClass(QDesignerFormEditorInterface *core, const QString &promotedClassName, QWidget *parent, FocusMode mode)
+{
+ const int index = core->widgetDataBase()->indexOfClassName(promotedClassName);
+ if (index == -1)
+ return false;
+
+ const QString baseClassName = core->widgetDataBase()->item(index)->extends();
+ if (baseClassName.isEmpty())
+ return false;
+
+ QWidget *widget = core->widgetFactory()->createWidget(baseClassName, 0);
+ if (!widget)
+ return false;
+ const bool rc = editPromotedClass(core, promotedClassName, widget, parent, mode);
+ widget->deleteLater();
+ return rc;
+}
+
+bool SignalSlotDialog::editPromotedClass(QDesignerFormEditorInterface *core, QObject *baseObject, QWidget *parent, FocusMode mode)
+{
+ if (!baseObject->isWidgetType())
+ return false;
+
+ const QString promotedClassName = promotedCustomClassName(core, qobject_cast<QWidget*>(baseObject));
+ if (promotedClassName.isEmpty())
+ return false;
+ return editPromotedClass(core, promotedClassName, baseObject, parent, mode);
+}
+
+
+bool SignalSlotDialog::editPromotedClass(QDesignerFormEditorInterface *core, const QString &promotedClassName, QObject *object, QWidget *parent, FocusMode mode)
+{
+ WidgetDataBase *db = qobject_cast<WidgetDataBase *>(core->widgetDataBase());
+ if (!db)
+ return false;
+
+ const int index = core->widgetDataBase()->indexOfClassName(promotedClassName);
+ if (index == -1)
+ return false;
+
+ WidgetDataBaseItem* item = static_cast<WidgetDataBaseItem*>(db->item(index));
+
+ SignalSlotDialogData slotData;
+ SignalSlotDialogData signalData;
+
+ existingMethodsFromMemberSheet(core, object, slotData.m_existingMethods, signalData.m_existingMethods);
+ slotData.m_fakeMethods = item->fakeSlots();
+ signalData.m_fakeMethods = item->fakeSignals();
+
+ const QStringList oldSlots = slotData.m_fakeMethods;
+ const QStringList oldSignals = signalData.m_fakeMethods;
+
+ SignalSlotDialog dlg(core->dialogGui(), parent, mode);
+ dlg.setWindowTitle(tr("Signals/Slots of %1").arg(promotedClassName));
+
+ if (dlg.showDialog(slotData, signalData) == QDialog::Rejected)
+ return false;
+
+ if (oldSlots == slotData.m_fakeMethods && oldSignals == signalData.m_fakeMethods)
+ return false;
+
+ item->setFakeSlots(slotData.m_fakeMethods);
+ item->setFakeSignals(signalData.m_fakeMethods);
+
+ return true;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/signalslotdialog.ui b/tools/designer/src/lib/shared/signalslotdialog.ui
new file mode 100644
index 0000000..1a8a8d9
--- /dev/null
+++ b/tools/designer/src/lib/shared/signalslotdialog.ui
@@ -0,0 +1,129 @@
+<ui version="4.0" >
+ <class>SignalSlotDialogClass</class>
+ <widget class="QDialog" name="SignalSlotDialogClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>617</width>
+ <height>535</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Signals and slots</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="slotGroupBox" >
+ <property name="title" >
+ <string>Slots</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QListView" name="slotListView" />
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QToolButton" name="addSlotButton" >
+ <property name="toolTip" >
+ <string>Add</string>
+ </property>
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="removeSlotButton" >
+ <property name="toolTip" >
+ <string>Delete</string>
+ </property>
+ <property name="text" >
+ <string>...</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>
+ <widget class="QGroupBox" name="signalGroupBox" >
+ <property name="title" >
+ <string>Signals</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QListView" name="signalListView" />
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QToolButton" name="addSignalButton" >
+ <property name="toolTip" >
+ <string>Add</string>
+ </property>
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="removeSignalButton" >
+ <property name="toolTip" >
+ <string>Delete</string>
+ </property>
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="spacerName" stdset="0" >
+ <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>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/signalslotdialog_p.h b/tools/designer/src/lib/shared/signalslotdialog_p.h
new file mode 100644
index 0000000..434b73f
--- /dev/null
+++ b/tools/designer/src/lib/shared/signalslotdialog_p.h
@@ -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$
+**
+****************************************************************************/
+
+//
+// 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 _SIGNALSLOTDIALOG_H
+#define _SIGNALSLOTDIALOG_H
+
+#include "shared_global_p.h"
+#include <QtCore/QStringList>
+#include <QtGui/QDialog>
+#include <QtGui/QStandardItemModel>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormEditorInterface;
+class QDesignerFormWindowInterface;
+class QDesignerDialogGuiInterface;
+class QDesignerMemberSheet;
+class QListView;
+class QToolButton;
+class QItemSelection;
+
+namespace Ui {
+ class SignalSlotDialogClass;
+}
+
+namespace qdesigner_internal {
+
+// Dialog data
+struct SignalSlotDialogData {
+ void clear();
+ QStringList m_existingMethods;
+ QStringList m_fakeMethods;
+};
+
+// Internal helper class: A model for signatures that allows for verifying duplicates
+// (checking signals versus slots and vice versa).
+class SignatureModel : public QStandardItemModel {
+ Q_OBJECT
+
+public:
+ SignatureModel(QObject *parent = 0);
+ virtual bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+signals:
+ void checkSignature(const QString &signature, bool *ok);
+};
+
+// Internal helper class: Panel for editing method signatures. List view with validator,
+// add and remove button
+class SignaturePanel : public QObject {
+ Q_OBJECT
+
+public:
+ SignaturePanel(QObject *parent, QListView *listView, QToolButton *addButton, QToolButton *removeButton, const QString &newPrefix);
+
+ QStringList fakeMethods() const;
+ void setData(const SignalSlotDialogData &d);
+ int count(const QString &signature) const;
+
+signals:
+ void checkSignature(const QString &signature, bool *ok);
+
+private slots:
+ void slotAdd();
+ void slotRemove();
+ void slotSelectionChanged(const QItemSelection &, const QItemSelection &);
+
+private:
+ void closeEditor();
+
+ const QString m_newPrefix;
+ SignatureModel *m_model;
+ QListView *m_listView;
+ QToolButton *m_removeButton;
+};
+
+// Dialog for editing signals and slots.
+// Provides static convenience function
+// to modify fake signals and slots. They are
+// handled in 2 ways:
+// 1) For the MainContainer: Fake signals and slots are stored
+// in the meta database (per-instance)
+// 2) For promoted widgets: Fake signals and slots are stored
+// in the widget database (per-class)
+// Arguably, we could require the MainContainer to be promoted for that, too,
+// but that would require entering a header.
+
+class QDESIGNER_SHARED_EXPORT SignalSlotDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ enum FocusMode { FocusSlots, FocusSignals };
+
+ explicit SignalSlotDialog(QDesignerDialogGuiInterface *dialogGui, QWidget *parent = 0, FocusMode m = FocusSlots);
+ virtual ~SignalSlotDialog();
+
+ DialogCode showDialog(SignalSlotDialogData &slotData, SignalSlotDialogData &signalData);
+
+ // Edit fake methods stored in MetaDataBase (per instance, used for main containers)
+ static bool editMetaDataBase(QDesignerFormWindowInterface *fw, QObject *object, QWidget *parent = 0, FocusMode m = FocusSlots);
+
+ // Edit fake methods of a promoted class stored in WidgetDataBase (synthesizes a widget to obtain existing members).
+ static bool editPromotedClass(QDesignerFormEditorInterface *core, const QString &promotedClassName, QWidget *parent = 0, FocusMode m = FocusSlots);
+ // Edit fake methods of a promoted class stored in WidgetDataBase on a base class instance.
+ static bool editPromotedClass(QDesignerFormEditorInterface *core, QObject *baseObject, QWidget *parent = 0, FocusMode m = FocusSlots);
+
+private slots:
+ void slotCheckSignature(const QString &signature, bool *ok);
+
+private:
+ // Edit fake methods of a promoted class stored in WidgetDataBase using an instance of the base class.
+ static bool editPromotedClass(QDesignerFormEditorInterface *core, const QString &promotedClassName, QObject *baseObject, QWidget *parent, FocusMode m);
+
+ const FocusMode m_focusMode;
+ Ui::SignalSlotDialogClass *m_ui;
+ QDesignerDialogGuiInterface *m_dialogGui;
+ SignaturePanel *m_slotPanel;
+ SignaturePanel *m_signalPanel;
+};
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/designer/src/lib/shared/spacer_widget.cpp b/tools/designer/src/lib/shared/spacer_widget.cpp
new file mode 100644
index 0000000..8256bf7
--- /dev/null
+++ b/tools/designer/src/lib/shared/spacer_widget.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 "spacer_widget_p.h"
+#include "layoutinfo_p.h"
+
+#include <QtDesigner/abstractformwindow.h>
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtGui/QLayout>
+#include <QtGui/QPainter>
+#include <QtGui/qevent.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+// The Spacer widget is Designer representation of QLayoutItem.
+// It uses QLayoutItem's sizeHint property as QWidget
+// sizeHint and the QLayoutItem's sizeType property as QWidget size policy.
+// If it is not within a layout, it adds a margin (m_SizeOffset) around it
+// to avoid being shrunk to an invisible state when the sizeHint is reset to 0,0
+// and enables sizeHandle-resizing. In a layout, however, this m_SizeOffset
+// should not be applied for pixel-exact design.
+
+Spacer::Spacer(QWidget *parent) :
+ QWidget(parent),
+ m_SizeOffset(3, 3), // A small offset to ensure the spacer is still visible when reset to size 0,0
+ m_orientation(Qt::Vertical),
+ m_interactive(true),
+ m_layoutState(UnknownLayoutState),
+ m_sizeHint(0, 0)
+{
+ setAttribute(Qt::WA_MouseNoMask);
+ m_formWindow = QDesignerFormWindowInterface::findFormWindow(this);
+ setSizeType(QSizePolicy::Expanding);
+}
+
+bool Spacer::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ToolTip:
+ updateToolTip(); // Tooltip includes size, so, refresh on demand
+ break;
+ case QEvent::ParentChange: // Cache information about 'being in layout' which is expensive to calculate.
+ m_layoutState = UnknownLayoutState;
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(e);
+}
+
+bool Spacer::isInLayout() const
+{
+ if (m_layoutState == UnknownLayoutState) {
+ m_layoutState = OutsideLayout;
+ if (m_formWindow)
+ if (const QWidget *parent = parentWidget())
+ if (qdesigner_internal::LayoutInfo::managedLayoutType(m_formWindow->core(), parent) != qdesigner_internal::LayoutInfo::NoLayout)
+ m_layoutState = InLayout;
+ }
+ return m_layoutState == InLayout;
+}
+
+void Spacer::paintEvent(QPaintEvent *)
+{
+ // Only draw spacers when we're editting widgets
+ if (m_formWindow != 0 && m_formWindow->currentTool() != 0)
+ return;
+
+ QPainter p(this);
+ p.setPen(Qt::blue);
+ const int w = width();
+ const int h = height();
+ if (w * h == 0)
+ return;
+
+ if (w <= m_SizeOffset.width() || h <= m_SizeOffset.height()) {
+ const int lw = w - 1;
+ const int lh = h - 1;
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ p.drawLine(0, 0, 0, lh);
+ p.drawLine(lw, 0, lw, lh);
+ break;
+ case Qt::Vertical:
+ p.drawLine(0, 0, lw, 0);
+ p.drawLine(0, lh, lw, lh);
+ break;
+ }
+ return;
+ }
+ if (m_orientation == Qt::Horizontal) {
+ const int dist = 3;
+ const int amplitude = qMin(3, h / 3);
+ const int base = h / 2;
+ int i = 0;
+ p.setPen(Qt::white);
+ for (i = 0; i < w / 3 +2; ++i)
+ p.drawLine(i * dist, base - amplitude, i * dist + dist / 2, base + amplitude);
+ p.setPen(Qt::blue);
+ for (i = 0; i < w / 3 +2; ++i)
+ p.drawLine(i * dist + dist / 2, base + amplitude, i * dist + dist, base - amplitude);
+ const int y = h/2;
+ p.drawLine(0, y-10, 0, y+10);
+ p.drawLine(w - 1, y-10, w - 1, y+10);
+ } else {
+ const int dist = 3;
+ const int amplitude = qMin(3, w / 3);
+ const int base = w / 2;
+ int i = 0;
+ p.setPen(Qt::white);
+ for (i = 0; i < h / 3 +2; ++i)
+ p.drawLine(base - amplitude, i * dist, base + amplitude,i * dist + dist / 2);
+ p.setPen(Qt::blue);
+ for (i = 0; i < h / 3 +2; ++i)
+ p.drawLine(base + amplitude, i * dist + dist / 2, base - amplitude, i * dist + dist);
+ const int x = w/2;
+ p.drawLine(x-10, 0, x+10, 0);
+ p.drawLine(x-10, h - 1, x+10, h - 1);
+ }
+}
+
+void Spacer::resizeEvent(QResizeEvent* e)
+{
+ QWidget::resizeEvent(e);
+ // When resized by widget handle dragging after a reset (QSize(0, 0)):
+ // Mark the property as changed (geometry and sizeHint are in sync except for 'changed').
+ if (m_formWindow) {
+ const QSize oldSize = e->oldSize();
+ if (oldSize.isNull() || oldSize.width() <= m_SizeOffset.width() || oldSize.height() <= m_SizeOffset.height())
+ if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), this))
+ sheet->setChanged(sheet->indexOf(QLatin1String("sizeHint")), true);
+ }
+
+ updateMask();
+
+ if (!m_interactive)
+ return;
+
+ if (!isInLayout()) { // Allow size-handle resize only if not in layout
+ const QSize currentSize = size();
+ if (currentSize.width() >= m_SizeOffset.width() && currentSize.height() >= m_SizeOffset.height())
+ m_sizeHint = currentSize - m_SizeOffset;
+ }
+}
+
+void Spacer::updateMask()
+{
+ QRegion r(rect());
+ const int w = width();
+ const int h = height();
+ if (w > 1 && h > 1) {
+ if (m_orientation == Qt::Horizontal) {
+ const int amplitude = qMin(3, h / 3);
+ const int base = h / 2;
+ r = r.subtract(QRect(1, 0, w - 2, base - amplitude));
+ r = r.subtract(QRect(1, base + amplitude, w - 2, h - base - amplitude));
+ } else {
+ const int amplitude = qMin(3, w / 3);
+ const int base = w / 2;
+ r = r.subtract(QRect(0, 1, base - amplitude, h - 2));
+ r = r.subtract(QRect(base + amplitude, 1, w - base - amplitude, h - 2));
+ }
+ }
+ setMask(r);
+}
+
+void Spacer::setSizeType(QSizePolicy::Policy t)
+{
+ const QSizePolicy sizeP = m_orientation == Qt::Vertical ? QSizePolicy(QSizePolicy::Minimum, t) : QSizePolicy(t, QSizePolicy::Minimum);
+ setSizePolicy(sizeP);
+}
+
+
+QSizePolicy::Policy Spacer::sizeType() const
+{
+ return m_orientation == Qt::Vertical ? sizePolicy().verticalPolicy() : sizePolicy().horizontalPolicy();
+}
+
+Qt::Alignment Spacer::alignment() const
+{
+ // For grid layouts
+ return m_orientation == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter;
+}
+
+QSize Spacer::sizeHint() const
+{
+ return isInLayout() ? m_sizeHint : m_sizeHint + m_SizeOffset;
+}
+
+QSize Spacer::sizeHintProperty() const
+{
+ return m_sizeHint;
+}
+
+void Spacer::setSizeHintProperty(const QSize &s)
+{
+ m_sizeHint = s;
+
+ if (!isInLayout()) // Visible resize only if not in layout
+ resize(s + m_SizeOffset);
+
+ updateGeometry();
+}
+
+Qt::Orientation Spacer::orientation() const
+{
+ return m_orientation;
+}
+
+void Spacer::setOrientation(Qt::Orientation o)
+{
+ if (m_orientation == o)
+ return;
+
+ const QSizePolicy::Policy st = sizeType(); // flip size type
+ m_orientation = o;
+ setSizeType(st);
+
+ if (m_interactive) {
+ m_sizeHint = QSize(m_sizeHint.height(), m_sizeHint.width());
+ if (!isInLayout())
+ resize(m_sizeHint + m_SizeOffset);
+ }
+
+ updateMask();
+ update();
+ updateGeometry();
+}
+
+void Spacer::updateToolTip()
+{
+ const QString format = m_orientation == Qt::Horizontal ? tr("Horizontal Spacer '%1', %2 x %3") : tr("Vertical Spacer '%1', %2 x %3");
+ QString msg = format.arg(objectName()).arg(m_sizeHint.width()).arg(m_sizeHint.height());
+ setToolTip(msg);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/spacer_widget_p.h b/tools/designer/src/lib/shared/spacer_widget_p.h
new file mode 100644
index 0000000..2b90813
--- /dev/null
+++ b/tools/designer/src/lib/shared/spacer_widget_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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 SPACER_WIDGET_H
+#define SPACER_WIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QSizePolicy>
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+
+class QDESIGNER_SHARED_EXPORT Spacer: public QWidget
+{
+ Q_OBJECT
+
+ Q_ENUMS(SizeType)
+ // Special hack: Make name appear as "spacer name"
+ Q_PROPERTY(QString spacerName READ objectName WRITE setObjectName)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+ Q_PROPERTY(QSizePolicy::Policy sizeType READ sizeType WRITE setSizeType)
+ Q_PROPERTY(QSize sizeHint READ sizeHintProperty WRITE setSizeHintProperty DESIGNABLE true STORED true)
+
+public:
+ Spacer(QWidget *parent = 0);
+
+ QSize sizeHint() const;
+
+ QSize sizeHintProperty() const;
+ void setSizeHintProperty(const QSize &s);
+
+ QSizePolicy::Policy sizeType() const;
+ void setSizeType(QSizePolicy::Policy t);
+
+ Qt::Alignment alignment() const;
+ Qt::Orientation orientation() const;
+
+ void setOrientation(Qt::Orientation o);
+ void setInteractiveMode(bool b) { m_interactive = b; };
+
+ virtual bool event(QEvent *e);
+
+protected:
+ void paintEvent(QPaintEvent *e);
+ void resizeEvent(QResizeEvent* e);
+ void updateMask();
+
+private:
+ bool isInLayout() const;
+ void updateToolTip();
+
+ const QSize m_SizeOffset;
+ QDesignerFormWindowInterface *m_formWindow;
+ Qt::Orientation m_orientation;
+ bool m_interactive;
+ // Cache information about 'being in layout' which is expensive to calculate.
+ enum LayoutState { InLayout, OutsideLayout, UnknownLayoutState };
+ mutable LayoutState m_layoutState;
+ QSize m_sizeHint;
+};
+
+QT_END_NAMESPACE
+
+#endif // SPACER_WIDGET_H
diff --git a/tools/designer/src/lib/shared/stylesheeteditor.cpp b/tools/designer/src/lib/shared/stylesheeteditor.cpp
new file mode 100644
index 0000000..2056fcf
--- /dev/null
+++ b/tools/designer/src/lib/shared/stylesheeteditor.cpp
@@ -0,0 +1,415 @@
+/****************************************************************************
+**
+** 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::StyleSheetEditorDialog
+*/
+
+#include "stylesheeteditor_p.h"
+#include "csshighlighter_p.h"
+#include "iconselector_p.h"
+#include "qtgradientmanager.h"
+#include "qtgradientviewdialog.h"
+#include "qtgradientutils.h"
+#include "qdesigner_integration_p.h"
+#include "qdesigner_utils_p.h"
+#include "abstractsettings_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QSignalMapper>
+#include <QtGui/QAction>
+#include <QtGui/QColorDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QFontDialog>
+#include <QtGui/QMenu>
+#include <QtGui/QPushButton>
+#include <QtGui/QTextDocument>
+#include <QtGui/QToolBar>
+#include <QtGui/QVBoxLayout>
+#include "private/qcssparser_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static const char *styleSheetProperty = "styleSheet";
+static const char *StyleSheetDialogC = "StyleSheetDialog";
+static const char *Geometry = "Geometry";
+
+namespace qdesigner_internal {
+
+StyleSheetEditor::StyleSheetEditor(QWidget *parent)
+ : QTextEdit(parent)
+{
+ setTabStopWidth(fontMetrics().width(QLatin1Char(' '))*4);
+ new CssHighlighter(document());
+}
+
+// --- StyleSheetEditorDialog
+StyleSheetEditorDialog::StyleSheetEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent, Mode mode):
+ QDialog(parent),
+ m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Help)),
+ m_editor(new StyleSheetEditor),
+ m_validityLabel(new QLabel(tr("Valid Style Sheet"))),
+ m_core(core),
+ m_addResourceAction(new QAction(tr("Add Resource..."), this)),
+ m_addGradientAction(new QAction(tr("Add Gradient..."), this)),
+ m_addColorAction(new QAction(tr("Add Color..."), this)),
+ m_addFontAction(new QAction(tr("Add Font..."), this))
+{
+ setWindowTitle(tr("Edit Style Sheet"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(m_buttonBox, SIGNAL(helpRequested()), this, SLOT(slotRequestHelp()));
+ m_buttonBox->button(QDialogButtonBox::Help)->setShortcut(QKeySequence::HelpContents);
+
+ connect(m_editor, SIGNAL(textChanged()), this, SLOT(validateStyleSheet()));
+
+ QToolBar *toolBar = new QToolBar;
+
+ QGridLayout *layout = new QGridLayout;
+ layout->addWidget(toolBar, 0, 0, 1, 2);
+ layout->addWidget(m_editor, 1, 0, 1, 2);
+ layout->addWidget(m_validityLabel, 2, 0, 1, 1);
+ layout->addWidget(m_buttonBox, 2, 1, 1, 1);
+ setLayout(layout);
+
+ m_editor->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(m_editor, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(slotContextMenuRequested(const QPoint &)));
+
+ QSignalMapper *resourceActionMapper = new QSignalMapper(this);
+ QSignalMapper *gradientActionMapper = new QSignalMapper(this);
+ QSignalMapper *colorActionMapper = new QSignalMapper(this);
+
+ resourceActionMapper->setMapping(m_addResourceAction, QString());
+ gradientActionMapper->setMapping(m_addGradientAction, QString());
+ colorActionMapper->setMapping(m_addColorAction, QString());
+
+ connect(m_addResourceAction, SIGNAL(triggered()), resourceActionMapper, SLOT(map()));
+ connect(m_addGradientAction, SIGNAL(triggered()), gradientActionMapper, SLOT(map()));
+ connect(m_addColorAction, SIGNAL(triggered()), colorActionMapper, SLOT(map()));
+ connect(m_addFontAction, SIGNAL(triggered()), this, SLOT(slotAddFont()));
+
+ m_addResourceAction->setEnabled(mode == ModePerForm);
+
+ const char * const resourceProperties[] = {
+ "background-image",
+ "border-image",
+ "image",
+ 0
+ };
+
+ const char * const colorProperties[] = {
+ "color",
+ "background-color",
+ "alternate-background-color",
+ "border-color",
+ "border-top-color",
+ "border-right-color",
+ "border-bottom-color",
+ "border-left-color",
+ "gridline-color",
+ "selection-color",
+ "selection-background-color",
+ 0
+ };
+
+ QMenu *resourceActionMenu = new QMenu(this);
+ QMenu *gradientActionMenu = new QMenu(this);
+ QMenu *colorActionMenu = new QMenu(this);
+
+ for (int resourceProperty = 0; resourceProperties[resourceProperty]; ++resourceProperty) {
+ QAction *action = resourceActionMenu->addAction(QLatin1String(resourceProperties[resourceProperty]));
+ connect(action, SIGNAL(triggered()), resourceActionMapper, SLOT(map()));
+ resourceActionMapper->setMapping(action, QLatin1String(resourceProperties[resourceProperty]));
+ }
+
+ for (int colorProperty = 0; colorProperties[colorProperty]; ++colorProperty) {
+ QAction *gradientAction = gradientActionMenu->addAction(QLatin1String(colorProperties[colorProperty]));
+ QAction *colorAction = colorActionMenu->addAction(QLatin1String(colorProperties[colorProperty]));
+ connect(gradientAction, SIGNAL(triggered()), gradientActionMapper, SLOT(map()));
+ connect(colorAction, SIGNAL(triggered()), colorActionMapper, SLOT(map()));
+ gradientActionMapper->setMapping(gradientAction, QLatin1String(colorProperties[colorProperty]));
+ colorActionMapper->setMapping(colorAction, QLatin1String(colorProperties[colorProperty]));
+ }
+
+ connect(resourceActionMapper, SIGNAL(mapped(QString)), this, SLOT(slotAddResource(QString)));
+ connect(gradientActionMapper, SIGNAL(mapped(QString)), this, SLOT(slotAddGradient(QString)));
+ connect(colorActionMapper, SIGNAL(mapped(QString)), this, SLOT(slotAddColor(QString)));
+
+ m_addResourceAction->setMenu(resourceActionMenu);
+ m_addGradientAction->setMenu(gradientActionMenu);
+ m_addColorAction->setMenu(colorActionMenu);
+
+ toolBar->addAction(m_addResourceAction);
+ toolBar->addAction(m_addGradientAction);
+ toolBar->addAction(m_addColorAction);
+ toolBar->addAction(m_addFontAction);
+
+ m_editor->setFocus();
+
+ QDesignerSettingsInterface *settings = core->settingsManager();
+ settings->beginGroup(QLatin1String(StyleSheetDialogC));
+
+ if (settings->contains(QLatin1String(Geometry)))
+ restoreGeometry(settings->value(QLatin1String(Geometry)).toByteArray());
+
+ settings->endGroup();
+}
+
+StyleSheetEditorDialog::~StyleSheetEditorDialog()
+{
+ QDesignerSettingsInterface *settings = m_core->settingsManager();
+ settings->beginGroup(QLatin1String(StyleSheetDialogC));
+
+ settings->setValue(QLatin1String(Geometry), saveGeometry());
+ settings->endGroup();
+}
+
+void StyleSheetEditorDialog::setOkButtonEnabled(bool v)
+{
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(v);
+ if (QPushButton *applyButton = m_buttonBox->button(QDialogButtonBox::Apply))
+ applyButton->setEnabled(v);
+}
+
+void StyleSheetEditorDialog::slotContextMenuRequested(const QPoint &pos)
+{
+ QMenu *menu = m_editor->createStandardContextMenu();
+ menu->addSeparator();
+ menu->addAction(m_addResourceAction);
+ menu->addAction(m_addGradientAction);
+ menu->exec(mapToGlobal(pos));
+ delete menu;
+}
+
+void StyleSheetEditorDialog::slotAddResource(const QString &property)
+{
+ const QString path = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), QString(), this);
+ if (!path.isEmpty())
+ insertCssProperty(property, QString(QLatin1String("url(%1)")).arg(path));
+}
+
+void StyleSheetEditorDialog::slotAddGradient(const QString &property)
+{
+ bool ok;
+ const QGradient grad = QtGradientViewDialog::getGradient(&ok, m_core->gradientManager(), this);
+ if (ok)
+ insertCssProperty(property, QtGradientUtils::styleSheetCode(grad));
+}
+
+void StyleSheetEditorDialog::slotAddColor(const QString &property)
+{
+ bool ok;
+ QRgb rgba = QColorDialog::getRgba(0xffffffff, &ok, this);
+ if (!ok)
+ return;
+
+ QColor color;
+ color.setRgba(rgba);
+ QString colorStr;
+
+ if (color.alpha() == 255) {
+ colorStr = QString(QLatin1String("rgb(%1, %2, %3)")).arg(
+ color.red()).arg(color.green()).arg(color.blue());
+ } else {
+ colorStr = QString(QLatin1String("rgba(%1, %2, %3, %4)")).arg(
+ color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha());
+ }
+
+ insertCssProperty(property, colorStr);
+}
+
+void StyleSheetEditorDialog::slotAddFont()
+{
+ bool ok;
+ QFont font = QFontDialog::getFont(&ok, this);
+ if (ok) {
+ QString fontStr;
+ if (font.weight() != QFont::Normal) {
+ fontStr += QString::number(font.weight());
+ fontStr += QLatin1Char(' ');
+ }
+
+ switch (font.style()) {
+ case QFont::StyleItalic:
+ fontStr += QLatin1String("italic ");
+ break;
+ case QFont::StyleOblique:
+ fontStr += QLatin1String("oblique ");
+ break;
+ default:
+ break;
+ }
+ fontStr += QString::number(font.pointSize());
+ fontStr += QLatin1String("pt \"");
+ fontStr += font.family();
+ fontStr += QLatin1Char('"');
+
+ insertCssProperty(QLatin1String("font"), fontStr);
+ QString decoration;
+ if (font.underline())
+ decoration += QLatin1String("underline");
+ if (font.strikeOut()) {
+ if (!decoration.isEmpty())
+ decoration += QLatin1Char(' ');
+ decoration += QLatin1String("line-through");
+ }
+ insertCssProperty(QLatin1String("text-decoration"), decoration);
+ }
+}
+
+void StyleSheetEditorDialog::insertCssProperty(const QString &name, const QString &value)
+{
+ if (!value.isEmpty()) {
+ QTextCursor cursor = m_editor->textCursor();
+ if (!name.isEmpty()) {
+ cursor.beginEditBlock();
+ cursor.removeSelectedText();
+ cursor.movePosition(QTextCursor::EndOfLine);
+
+ // Simple check to see if we're in a selector scope
+ const QTextDocument *doc = m_editor->document();
+ const QTextCursor closing = doc->find(QLatin1String("}"), cursor, QTextDocument::FindBackward);
+ const QTextCursor opening = doc->find(QLatin1String("{"), cursor, QTextDocument::FindBackward);
+ const bool inSelector = !opening.isNull() && (closing.isNull() ||
+ closing.position() < opening.position());
+ QString insertion;
+ if (m_editor->textCursor().block().length() != 1)
+ insertion += QLatin1Char('\n');
+ if (inSelector)
+ insertion += QLatin1Char('\t');
+ insertion += name;
+ insertion += QLatin1String(": ");
+ insertion += value;
+ insertion += QLatin1Char(';');
+ cursor.insertText(insertion);
+ cursor.endEditBlock();
+ } else {
+ cursor.insertText(value);
+ }
+ }
+}
+
+void StyleSheetEditorDialog::slotRequestHelp()
+{
+ QDesignerIntegration::requestHelp(m_core, QLatin1String("qt"),
+ QLatin1String("stylesheet-reference.html"));
+}
+
+QDialogButtonBox * StyleSheetEditorDialog::buttonBox() const
+{
+ return m_buttonBox;
+}
+
+QString StyleSheetEditorDialog::text() const
+{
+ return m_editor->toPlainText();
+}
+
+void StyleSheetEditorDialog::setText(const QString &t)
+{
+ m_editor->setText(t);
+}
+
+bool StyleSheetEditorDialog::isStyleSheetValid(const QString &styleSheet)
+{
+ QCss::Parser parser(styleSheet);
+ QCss::StyleSheet sheet;
+ if (parser.parse(&sheet))
+ return true;
+ QString fullSheet = QLatin1String("* { ");
+ fullSheet += styleSheet;
+ fullSheet += QLatin1Char('}');
+ QCss::Parser parser2(fullSheet);
+ return parser2.parse(&sheet);
+}
+
+void StyleSheetEditorDialog::validateStyleSheet()
+{
+ const bool valid = isStyleSheetValid(m_editor->toPlainText());
+ setOkButtonEnabled(valid);
+ if (valid) {
+ m_validityLabel->setText(tr("Valid Style Sheet"));
+ m_validityLabel->setStyleSheet(QLatin1String("color: green"));
+ } else {
+ m_validityLabel->setText(tr("Invalid Style Sheet"));
+ m_validityLabel->setStyleSheet(QLatin1String("color: red"));
+ }
+}
+
+// --- StyleSheetPropertyEditorDialog
+StyleSheetPropertyEditorDialog::StyleSheetPropertyEditorDialog(QWidget *parent,
+ QDesignerFormWindowInterface *fw,
+ QWidget *widget):
+ StyleSheetEditorDialog(fw->core(), parent),
+ m_fw(fw),
+ m_widget(widget)
+{
+ Q_ASSERT(m_fw != 0);
+
+ QPushButton *apply = buttonBox()->addButton(QDialogButtonBox::Apply);
+ QObject::connect(apply, SIGNAL(clicked()), this, SLOT(applyStyleSheet()));
+ QObject::connect(buttonBox(), SIGNAL(accepted()), this, SLOT(applyStyleSheet()));
+
+ QDesignerPropertySheetExtension *sheet =
+ qt_extension<QDesignerPropertySheetExtension*>(m_fw->core()->extensionManager(), m_widget);
+ Q_ASSERT(sheet != 0);
+ const int index = sheet->indexOf(QLatin1String(styleSheetProperty));
+ const PropertySheetStringValue value = qVariantValue<PropertySheetStringValue>(sheet->property(index));
+ setText(value.value());
+}
+
+void StyleSheetPropertyEditorDialog::applyStyleSheet()
+{
+ const PropertySheetStringValue value(text(), false);
+ m_fw->cursor()->setWidgetProperty(m_widget, QLatin1String(styleSheetProperty), qVariantFromValue(value));
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/stylesheeteditor_p.h b/tools/designer/src/lib/shared/stylesheeteditor_p.h
new file mode 100644
index 0000000..c9fd682
--- /dev/null
+++ b/tools/designer/src/lib/shared/stylesheeteditor_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** 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 STYLESHEETEDITOR_H
+#define STYLESHEETEDITOR_H
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+#include "shared_global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDesignerFormWindowInterface;
+class QDesignerFormEditorInterface;
+
+class QDialogButtonBox;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT StyleSheetEditor : public QTextEdit
+{
+ Q_OBJECT
+public:
+ StyleSheetEditor(QWidget *parent = 0);
+};
+
+// Edit a style sheet.
+class QDESIGNER_SHARED_EXPORT StyleSheetEditorDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ ModeGlobal, // resources are disabled (we don't have current resource set loaded), used e.g. in configuration dialog context
+ ModePerForm // resources are available
+ };
+
+ StyleSheetEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent, Mode mode = ModePerForm);
+ ~StyleSheetEditorDialog();
+ QString text() const;
+ void setText(const QString &t);
+
+ static bool isStyleSheetValid(const QString &styleSheet);
+
+
+private slots:
+ void validateStyleSheet();
+ void slotContextMenuRequested(const QPoint &pos);
+ void slotAddResource(const QString &property);
+ void slotAddGradient(const QString &property);
+ void slotAddColor(const QString &property);
+ void slotAddFont();
+ void slotRequestHelp();
+
+protected:
+ QDialogButtonBox *buttonBox() const;
+ void setOkButtonEnabled(bool v);
+
+private:
+ void insertCssProperty(const QString &name, const QString &value);
+
+ QDialogButtonBox *m_buttonBox;
+ StyleSheetEditor *m_editor;
+ QLabel *m_validityLabel;
+ QDesignerFormEditorInterface *m_core;
+ QAction *m_addResourceAction;
+ QAction *m_addGradientAction;
+ QAction *m_addColorAction;
+ QAction *m_addFontAction;
+};
+
+// Edit the style sheet property of the designer selection.
+// Provides an "Apply" button.
+
+class QDESIGNER_SHARED_EXPORT StyleSheetPropertyEditorDialog : public StyleSheetEditorDialog
+{
+ Q_OBJECT
+public:
+ StyleSheetPropertyEditorDialog(QWidget *parent, QDesignerFormWindowInterface *fw, QWidget *widget);
+
+ static bool isStyleSheetValid(const QString &styleSheet);
+
+private slots:
+ void applyStyleSheet();
+
+private:
+ QDesignerFormWindowInterface *m_fw;
+ QWidget *m_widget;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // STYLESHEETEDITOR_H
diff --git a/tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui b/tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000..7ff64b0
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>240</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>10</x>
+ <y>270</y>
+ <width>221</width>
+ <height>41</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui b/tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000..203af78
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>240</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>150</x>
+ <y>10</y>
+ <width>81</width>
+ <height>301</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui b/tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000..0ac856e
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>10</x>
+ <y>200</y>
+ <width>301</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui b/tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000..52f0f66
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>230</x>
+ <y>10</y>
+ <width>81</width>
+ <height>221</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui b/tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000..0d219c9
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>480</width>
+ <height>640</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>10</x>
+ <y>600</y>
+ <width>461</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui b/tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000..c82a78e
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>480</width>
+ <height>640</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>390</x>
+ <y>10</y>
+ <width>81</width>
+ <height>621</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui b/tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000..adc5d48
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>640</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>10</x>
+ <y>440</y>
+ <width>621</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui b/tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000..defb42a
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,67 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>640</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>550</x>
+ <y>10</y>
+ <width>81</width>
+ <height>461</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/Dialog_with_Buttons_Bottom.ui b/tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Bottom.ui
new file mode 100644
index 0000000..18d31ab
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Bottom.ui
@@ -0,0 +1,71 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Dialog</class>
+ <widget class="QDialog" name="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>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>30</x>
+ <y>240</y>
+ <width>341</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/Dialog_with_Buttons_Right.ui b/tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Right.ui
new file mode 100644
index 0000000..703d594
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Right.ui
@@ -0,0 +1,71 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Dialog</class>
+ <widget class="QDialog" name="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>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="geometry" >
+ <rect>
+ <x>290</x>
+ <y>20</y>
+ <width>81</width>
+ <height>241</height>
+ </rect>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</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>Dialog</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/lib/shared/templates/forms/Dialog_without_Buttons.ui b/tools/designer/src/lib/shared/templates/forms/Dialog_without_Buttons.ui
new file mode 100644
index 0000000..1be6298
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/Dialog_without_Buttons.ui
@@ -0,0 +1,18 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="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>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/templates/forms/Main_Window.ui b/tools/designer/src/lib/shared/templates/forms/Main_Window.ui
new file mode 100644
index 0000000..9ae3b50
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/Main_Window.ui
@@ -0,0 +1,24 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>MainWindow</string>
+ </property>
+ <widget class="QMenuBar" name="menubar" />
+ <widget class="QWidget" name="centralwidget" />
+ <widget class="QStatusBar" name="statusbar" />
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/templates/forms/Widget.ui b/tools/designer/src/lib/shared/templates/forms/Widget.ui
new file mode 100644
index 0000000..4b7d6a4
--- /dev/null
+++ b/tools/designer/src/lib/shared/templates/forms/Widget.ui
@@ -0,0 +1,21 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>Form</class>
+ <widget class="QWidget" name="Form" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <connections/>
+</ui>
diff --git a/tools/designer/src/lib/shared/textpropertyeditor.cpp b/tools/designer/src/lib/shared/textpropertyeditor.cpp
new file mode 100644
index 0000000..cf12842
--- /dev/null
+++ b/tools/designer/src/lib/shared/textpropertyeditor.cpp
@@ -0,0 +1,429 @@
+/****************************************************************************
+**
+** 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 "textpropertyeditor_p.h"
+#include "propertylineedit_p.h"
+#include "stylesheeteditor_p.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QRegExpValidator>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QCompleter>
+#include <QtGui/QAbstractItemView>
+#include <QtCore/QRegExp>
+#include <QtCore/QUrl>
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ const QChar NewLineChar(QLatin1Char('\n'));
+ const QLatin1String EscapedNewLine("\\n");
+
+ // A validator that replaces offending strings
+ class ReplacementValidator : public QValidator {
+ public:
+ ReplacementValidator (QObject * parent,
+ const QString &offending,
+ const QString &replacement);
+ virtual void fixup ( QString & input ) const;
+ virtual State validate ( QString & input, int &pos) const;
+ private:
+ const QString m_offending;
+ const QString m_replacement;
+ };
+
+ ReplacementValidator::ReplacementValidator (QObject * parent,
+ const QString &offending,
+ const QString &replacement) :
+ QValidator(parent ),
+ m_offending(offending),
+ m_replacement(replacement)
+ {
+ }
+
+ void ReplacementValidator::fixup ( QString & input ) const {
+ input.replace(m_offending, m_replacement);
+ }
+
+ QValidator::State ReplacementValidator::validate ( QString & input, int &/* pos */) const {
+ fixup (input);
+ return Acceptable;
+ }
+
+ // A validator for style sheets. Does newline handling and validates sheets.
+ class StyleSheetValidator : public ReplacementValidator {
+ public:
+ StyleSheetValidator (QObject * parent);
+ virtual State validate(QString & input, int &pos) const;
+ };
+
+ StyleSheetValidator::StyleSheetValidator (QObject * parent) :
+ ReplacementValidator(parent, NewLineChar, EscapedNewLine)
+ {
+ }
+
+ QValidator::State StyleSheetValidator::validate ( QString & input, int &pos) const
+ {
+ // base class
+ const State state = ReplacementValidator:: validate(input, pos);
+ if (state != Acceptable)
+ return state;
+ // now check style sheet, create string with newlines
+ const QString styleSheet = qdesigner_internal::TextPropertyEditor::editorStringToString(input, qdesigner_internal::ValidationStyleSheet);
+ const bool valid = qdesigner_internal::StyleSheetEditorDialog::isStyleSheetValid(styleSheet);
+ return valid ? Acceptable : Intermediate;
+ }
+
+ // A validator for URLs based on QUrl. Enforces complete protocol
+ // specification with a completer (adds a trailing slash)
+ class UrlValidator : public QValidator {
+ public:
+ UrlValidator(QCompleter *completer, QObject *parent);
+
+ virtual State validate(QString &input, int &pos) const;
+ virtual void fixup(QString &input) const;
+ private:
+ QUrl guessUrlFromString(const QString &string) const;
+ QCompleter *m_completer;
+ };
+
+ UrlValidator::UrlValidator(QCompleter *completer, QObject *parent) :
+ QValidator(parent),
+ m_completer(completer)
+ {
+ }
+
+ QValidator::State UrlValidator::validate(QString &input, int &pos) const
+ {
+ Q_UNUSED(pos);
+
+ if (input.isEmpty())
+ return Acceptable;
+
+ const QUrl url(input, QUrl::StrictMode);
+
+ if (!url.isValid() || url.isEmpty())
+ return Intermediate;
+
+ if (url.scheme().isEmpty())
+ return Intermediate;
+
+ if (url.host().isEmpty() && url.path().isEmpty())
+ return Intermediate;
+
+ return Acceptable;
+ }
+
+ void UrlValidator::fixup(QString &input) const
+ {
+ // Don't try to fixup if the user is busy selecting a completion proposal
+ if (const QAbstractItemView *iv = m_completer->popup()) {
+ if (iv->isVisible())
+ return;
+ }
+
+ input = guessUrlFromString(input).toString();
+ }
+
+ QUrl UrlValidator::guessUrlFromString(const QString &string) const
+ {
+ const QString urlStr = string.trimmed();
+ const QRegExp qualifiedUrl(QLatin1String("^[a-zA-Z]+\\:.*"));
+
+ // Check if it looks like a qualified URL. Try parsing it and see.
+ const bool hasSchema = qualifiedUrl.exactMatch(urlStr);
+ if (hasSchema) {
+ const QUrl url(urlStr, QUrl::TolerantMode);
+ if (url.isValid())
+ return url;
+ }
+
+ // Might be a Qt resource
+ if (string.startsWith(QLatin1String(":/")))
+ return QUrl(QLatin1String("qrc") + string);
+
+ // Might be a file.
+ if (QFile::exists(urlStr))
+ return QUrl::fromLocalFile(urlStr);
+
+ // Might be a short url - try to detect the schema.
+ if (!hasSchema) {
+ const int dotIndex = urlStr.indexOf(QLatin1Char('.'));
+ if (dotIndex != -1) {
+ const QString prefix = urlStr.left(dotIndex).toLower();
+ QString urlString;
+ if (prefix == QLatin1String("ftp"))
+ urlString += prefix;
+ else
+ urlString += QLatin1String("http");
+ urlString += QLatin1String("://");
+ urlString += urlStr;
+ const QUrl url(urlString, QUrl::TolerantMode);
+ if (url.isValid())
+ return url;
+ }
+ }
+
+ // Fall back to QUrl's own tolerant parser.
+ return QUrl(string, QUrl::TolerantMode);
+ }
+}
+
+namespace qdesigner_internal {
+ // TextPropertyEditor
+ TextPropertyEditor::TextPropertyEditor(QWidget *parent,
+ EmbeddingMode embeddingMode,
+ TextPropertyValidationMode validationMode) :
+ QWidget(parent),
+ m_validationMode(ValidationSingleLine),
+ m_updateMode(UpdateAsYouType),
+ m_lineEdit(new PropertyLineEdit(this)),
+ m_textEdited(false)
+ {
+ switch (embeddingMode) {
+ case EmbeddingNone:
+ break;
+ case EmbeddingTreeView:
+ m_lineEdit->setFrame(false);
+ break;
+ case EmbeddingInPlace:
+ m_lineEdit->setFrame(false);
+ Q_ASSERT(parent);
+ m_lineEdit->setBackgroundRole(parent->backgroundRole());
+ break;
+ }
+
+ setFocusProxy(m_lineEdit);
+
+ connect(m_lineEdit,SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
+ connect(m_lineEdit,SIGNAL(returnPressed()), this, SLOT(slotEditingFinished()));
+ connect(m_lineEdit,SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString)));
+ connect(m_lineEdit,SIGNAL(textEdited(QString)), this, SLOT(slotTextEdited()));
+
+ setTextPropertyValidationMode(validationMode);
+ }
+
+ void TextPropertyEditor::setTextPropertyValidationMode(TextPropertyValidationMode vm) {
+ m_validationMode = vm;
+ m_lineEdit->setWantNewLine(multiLine(m_validationMode));
+ switch (m_validationMode) {
+ case ValidationStyleSheet:
+ m_lineEdit->setValidator(new StyleSheetValidator(m_lineEdit));
+ m_lineEdit->setCompleter(0);
+ break;
+ case ValidationMultiLine:
+ case ValidationRichText:
+ // Set a validator that replaces newline characters by literal "\\n".
+ // While it is not possible to actually type a newline characters,
+ // it can be pasted into the line edit.
+ m_lineEdit->setValidator(new ReplacementValidator(m_lineEdit, NewLineChar, EscapedNewLine));
+ m_lineEdit->setCompleter(0);
+ break;
+ case ValidationSingleLine:
+ // Set a validator that replaces newline characters by a blank.
+ m_lineEdit->setValidator(new ReplacementValidator(m_lineEdit, NewLineChar, QString(QLatin1Char(' '))));
+ m_lineEdit->setCompleter(0);
+ break;
+ case ValidationObjectName:
+ setRegExpValidator(QLatin1String("[_a-zA-Z][_a-zA-Z0-9]{,1023}"));
+ m_lineEdit->setCompleter(0);
+ break;
+ case ValidationObjectNameScope:
+ setRegExpValidator(QLatin1String("[_a-zA-Z:][_a-zA-Z0-9:]{,1023}"));
+ m_lineEdit->setCompleter(0);
+ break;
+ case ValidationURL: {
+ static QStringList urlCompletions;
+ if (urlCompletions.empty()) {
+ urlCompletions.push_back(QLatin1String("about:blank"));
+ urlCompletions.push_back(QLatin1String("http://"));
+ urlCompletions.push_back(QLatin1String("http://www."));
+ urlCompletions.push_back(QLatin1String("http://qtsoftware.com/"));
+ urlCompletions.push_back(QLatin1String("file://"));
+ urlCompletions.push_back(QLatin1String("ftp://"));
+ urlCompletions.push_back(QLatin1String("data:"));
+ urlCompletions.push_back(QLatin1String("data:text/html,"));
+ urlCompletions.push_back(QLatin1String("qrc:/"));
+ }
+ QCompleter *completer = new QCompleter(urlCompletions, m_lineEdit);
+ m_lineEdit->setCompleter(completer);
+ m_lineEdit->setValidator(new UrlValidator(completer, m_lineEdit));
+ }
+ break;
+ }
+
+ setFocusProxy(m_lineEdit);
+ markIntermediateState();
+ }
+
+ void TextPropertyEditor::setRegExpValidator(const QString &pattern)
+ {
+ const QRegExp regExp(pattern);
+ Q_ASSERT(regExp.isValid());
+ m_lineEdit->setValidator(new QRegExpValidator(regExp,m_lineEdit));
+ }
+
+ QString TextPropertyEditor::text() const
+ {
+ return m_cachedText;
+ }
+
+ void TextPropertyEditor::markIntermediateState()
+ {
+ if (m_lineEdit->hasAcceptableInput()) {
+ m_lineEdit->setPalette(QPalette());
+ } else {
+ QPalette palette = m_lineEdit->palette();
+ palette.setColor(QPalette::Active, QPalette::Text, Qt::red);
+ m_lineEdit->setPalette(palette);
+ }
+
+ }
+
+ void TextPropertyEditor::setText(const QString &text)
+ {
+ m_cachedText = text;
+ m_lineEdit->setText(stringToEditorString(text, m_validationMode));
+ markIntermediateState();
+ m_textEdited = false;
+ }
+
+ void TextPropertyEditor::slotTextEdited()
+ {
+ m_textEdited = true;
+ }
+
+ void TextPropertyEditor::slotTextChanged(const QString &text) {
+ m_cachedText = editorStringToString(text, m_validationMode);
+ markIntermediateState();
+ if (m_updateMode == UpdateAsYouType)
+ emit textChanged(m_cachedText);
+ }
+
+ void TextPropertyEditor::slotEditingFinished()
+ {
+ if (m_updateMode == UpdateOnFinished && m_textEdited) {
+ emit textChanged(m_cachedText);
+ m_textEdited = false;
+ }
+ }
+
+ void TextPropertyEditor::selectAll() {
+ m_lineEdit->selectAll();
+ }
+
+ void TextPropertyEditor::clear() {
+ m_lineEdit->clear();
+ }
+
+ void TextPropertyEditor::setAlignment(Qt::Alignment alignment) {
+ m_lineEdit->setAlignment(alignment);
+ }
+
+ void TextPropertyEditor::installEventFilter(QObject *filterObject)
+ {
+ if (m_lineEdit)
+ m_lineEdit->installEventFilter(filterObject);
+ }
+
+ void TextPropertyEditor::resizeEvent ( QResizeEvent * event ) {
+ m_lineEdit->resize( event->size());
+ }
+
+ QSize TextPropertyEditor::sizeHint () const {
+ return m_lineEdit->sizeHint ();
+ }
+
+ QSize TextPropertyEditor::minimumSizeHint () const {
+ return m_lineEdit->minimumSizeHint ();
+ }
+
+ // Returns whether newline characters are valid in validationMode.
+ bool TextPropertyEditor::multiLine(TextPropertyValidationMode validationMode) {
+ return validationMode == ValidationMultiLine || validationMode == ValidationStyleSheet || validationMode == ValidationRichText;
+ }
+
+ // Replace newline characters literal "\n" for inline editing in mode ValidationMultiLine
+ QString TextPropertyEditor::stringToEditorString(const QString &s, TextPropertyValidationMode validationMode) {
+ if (s.isEmpty() || !multiLine(validationMode))
+ return s;
+
+ QString rc(s);
+ // protect backslashes
+ rc.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
+ // escape newlines
+ rc.replace(NewLineChar, QString(EscapedNewLine));
+ return rc;
+
+ }
+
+ // Replace literal "\n" by actual new lines for inline editing in mode ValidationMultiLine
+ // Note: As the properties are updated while the user types, it is important
+ // that trailing slashes ('bla\') are not deleted nor ignored, else this will
+ // cause jumping of the cursor
+ QString TextPropertyEditor::editorStringToString(const QString &s, TextPropertyValidationMode validationMode) {
+ if (s.isEmpty() || !multiLine(validationMode))
+ return s;
+
+ QString rc(s);
+ for (int pos = 0; (pos = rc.indexOf(QLatin1Char('\\'),pos)) >= 0 ; ) {
+ // found an escaped character. If not a newline or at end of string, leave as is, else insert '\n'
+ const int nextpos = pos + 1;
+ if (nextpos >= rc.length()) // trailing '\\'
+ break;
+ // Escaped NewLine
+ if (rc.at(nextpos) == QChar(QLatin1Char('n')))
+ rc[nextpos] = NewLineChar;
+ // Remove escape, go past escaped
+ rc.remove(pos,1);
+ pos++;
+ }
+ return rc;
+ }
+
+ bool TextPropertyEditor::hasAcceptableInput() const {
+ return m_lineEdit->hasAcceptableInput();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/textpropertyeditor_p.h b/tools/designer/src/lib/shared/textpropertyeditor_p.h
new file mode 100644
index 0000000..d921135
--- /dev/null
+++ b/tools/designer/src/lib/shared/textpropertyeditor_p.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** 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 TEXTPROPERTYEDITOR_H
+#define TEXTPROPERTYEDITOR_H
+
+#include "shared_global_p.h"
+#include "shared_enums_p.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+
+ class PropertyLineEdit;
+
+ // Inline-Editor for text properties. Does escaping of newline characters
+ // to '\n' and back and provides validation modes. The interface
+ // corresponds to that of QLineEdit.
+ class QDESIGNER_SHARED_EXPORT TextPropertyEditor : public QWidget
+ {
+ TextPropertyEditor(const TextPropertyEditor &);
+ TextPropertyEditor& operator=(const TextPropertyEditor &);
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText USER true)
+ public:
+ enum EmbeddingMode {
+ // Stand-alone widget
+ EmbeddingNone,
+ // Disable frame
+ EmbeddingTreeView,
+ // For editing in forms
+ EmbeddingInPlace
+ };
+
+ enum UpdateMode {
+ // Emit textChanged() as the user types
+ UpdateAsYouType,
+ // Emit textChanged() only when the user finishes (for QUrl, etc.)
+ UpdateOnFinished
+ };
+
+ TextPropertyEditor(QWidget *parent = 0, EmbeddingMode embeddingMode = EmbeddingNone, TextPropertyValidationMode validationMode = ValidationMultiLine);
+
+ TextPropertyValidationMode textPropertyValidationMode() const { return m_validationMode; }
+ void setTextPropertyValidationMode(TextPropertyValidationMode vm);
+
+ UpdateMode updateMode() const { return m_updateMode; }
+ void setUpdateMode(UpdateMode um) { m_updateMode = um; }
+
+ QString text() const;
+
+ virtual QSize sizeHint () const;
+ virtual QSize minimumSizeHint () const;
+
+ void setAlignment(Qt::Alignment alignment);
+
+ bool hasAcceptableInput() const;
+
+ // installs an event filter object on the private QLineEdit
+ void installEventFilter(QObject *filterObject);
+
+ // Replace newline characters by literal "\n" for inline editing
+ // in mode ValidationMultiLine
+ static QString stringToEditorString(const QString &s, TextPropertyValidationMode validationMode = ValidationMultiLine);
+
+ // Replace literal "\n" by actual new lines in mode ValidationMultiLine
+ static QString editorStringToString(const QString &s, TextPropertyValidationMode validationMode = ValidationMultiLine);
+
+ // Returns whether newline characters are valid in validationMode.
+ static bool multiLine(TextPropertyValidationMode validationMode);
+
+ signals:
+ void textChanged(const QString &text);
+ void editingFinished();
+
+ public slots:
+ void setText(const QString &text);
+ void selectAll();
+ void clear();
+
+ protected:
+ void resizeEvent(QResizeEvent * event );
+
+ private slots:
+ void slotTextChanged(const QString &text);
+ void slotTextEdited();
+ void slotEditingFinished();
+
+ private:
+ void setRegExpValidator(const QString &pattern);
+ void markIntermediateState();
+
+ TextPropertyValidationMode m_validationMode;
+ UpdateMode m_updateMode;
+ PropertyLineEdit* m_lineEdit;
+
+ // Cached text containing real newline characters.
+ QString m_cachedText;
+ bool m_textEdited;
+ };
+}
+
+QT_END_NAMESPACE
+
+#endif // TEXTPROPERTYEDITOR_H
diff --git a/tools/designer/src/lib/shared/widgetdatabase.cpp b/tools/designer/src/lib/shared/widgetdatabase.cpp
new file mode 100644
index 0000000..e452eab
--- /dev/null
+++ b/tools/designer/src/lib/shared/widgetdatabase.cpp
@@ -0,0 +1,865 @@
+/****************************************************************************
+**
+** 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 "widgetdatabase_p.h"
+#include "widgetfactory_p.h"
+#include "spacer_widget_p.h"
+#include "abstractlanguage.h"
+#include "pluginmanager_p.h"
+#include "qdesigner_widgetbox_p.h"
+#include "qdesigner_utils_p.h"
+#include <ui4_p.h>
+
+#include <QtDesigner/customwidget.h>
+#include <QtDesigner/propertysheet.h>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtXml/QXmlStreamWriter>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/qdebug.h>
+#include <QtCore/QMetaProperty>
+#include <QtCore/QTextStream>
+#include <QtCore/QRegExp>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ enum { debugWidgetDataBase = 0 };
+}
+
+namespace qdesigner_internal {
+
+// ----------------------------------------------------------
+WidgetDataBaseItem::WidgetDataBaseItem(const QString &name, const QString &group)
+ : m_name(name),
+ m_group(group),
+ m_compat(0),
+ m_container(0),
+ m_form(0),
+ m_custom(0),
+ m_promoted(0)
+{
+}
+
+QString WidgetDataBaseItem::name() const
+{
+ return m_name;
+}
+
+void WidgetDataBaseItem::setName(const QString &name)
+{
+ m_name = name;
+}
+
+QString WidgetDataBaseItem::group() const
+{
+ return m_group;
+}
+
+void WidgetDataBaseItem::setGroup(const QString &group)
+{
+ m_group = group;
+}
+
+QString WidgetDataBaseItem::toolTip() const
+{
+ return m_toolTip;
+}
+
+void WidgetDataBaseItem::setToolTip(const QString &toolTip)
+{
+ m_toolTip = toolTip;
+}
+
+QString WidgetDataBaseItem::whatsThis() const
+{
+ return m_whatsThis;
+}
+
+void WidgetDataBaseItem::setWhatsThis(const QString &whatsThis)
+{
+ m_whatsThis = whatsThis;
+}
+
+QString WidgetDataBaseItem::includeFile() const
+{
+ return m_includeFile;
+}
+
+void WidgetDataBaseItem::setIncludeFile(const QString &includeFile)
+{
+ m_includeFile = includeFile;
+}
+
+QIcon WidgetDataBaseItem::icon() const
+{
+ return m_icon;
+}
+
+void WidgetDataBaseItem::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+}
+
+bool WidgetDataBaseItem::isCompat() const
+{
+ return m_compat;
+}
+
+void WidgetDataBaseItem::setCompat(bool b)
+{
+ m_compat = b;
+}
+
+bool WidgetDataBaseItem::isContainer() const
+{
+ return m_container;
+}
+
+void WidgetDataBaseItem::setContainer(bool b)
+{
+ m_container = b;
+}
+
+bool WidgetDataBaseItem::isCustom() const
+{
+ return m_custom;
+}
+
+void WidgetDataBaseItem::setCustom(bool b)
+{
+ m_custom = b;
+}
+
+QString WidgetDataBaseItem::pluginPath() const
+{
+ return m_pluginPath;
+}
+
+void WidgetDataBaseItem::setPluginPath(const QString &path)
+{
+ m_pluginPath = path;
+}
+
+bool WidgetDataBaseItem::isPromoted() const
+{
+ return m_promoted;
+}
+
+void WidgetDataBaseItem::setPromoted(bool b)
+{
+ m_promoted = b;
+}
+
+QString WidgetDataBaseItem::extends() const
+{
+ return m_extends;
+}
+
+void WidgetDataBaseItem::setExtends(const QString &s)
+{
+ m_extends = s;
+}
+
+void WidgetDataBaseItem::setDefaultPropertyValues(const QList<QVariant> &list)
+{
+ m_defaultPropertyValues = list;
+}
+
+QList<QVariant> WidgetDataBaseItem::defaultPropertyValues() const
+{
+ return m_defaultPropertyValues;
+}
+
+QStringList WidgetDataBaseItem::fakeSlots() const
+{
+ return m_fakeSlots;
+}
+
+void WidgetDataBaseItem::setFakeSlots(const QStringList &fs)
+{
+ m_fakeSlots = fs;
+}
+
+QStringList WidgetDataBaseItem::fakeSignals() const
+{
+ return m_fakeSignals;
+}
+
+void WidgetDataBaseItem::setFakeSignals(const QStringList &fs)
+{
+ m_fakeSignals = fs;
+}
+
+QString WidgetDataBaseItem::addPageMethod() const
+{
+ return m_addPageMethod;
+}
+
+void WidgetDataBaseItem::setAddPageMethod(const QString &m)
+{
+ m_addPageMethod = m;
+}
+
+WidgetDataBaseItem *WidgetDataBaseItem::clone(const QDesignerWidgetDataBaseItemInterface *item)
+{
+ WidgetDataBaseItem *rc = new WidgetDataBaseItem(item->name(), item->group());
+
+ rc->setToolTip(item->toolTip());
+ rc->setWhatsThis(item->whatsThis());
+ rc->setIncludeFile(item->includeFile());
+ rc->setIcon(item->icon());
+ rc->setCompat(item->isCompat());
+ rc->setContainer(item->isContainer());
+ rc->setCustom(item->isCustom() );
+ rc->setPluginPath(item->pluginPath());
+ rc->setPromoted(item->isPromoted());
+ rc->setExtends(item->extends());
+ rc->setDefaultPropertyValues(item->defaultPropertyValues());
+ // container page method, fake slots and signals ignored here.y
+ return rc;
+}
+
+// ----------------------------------------------------------
+WidgetDataBase::WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent)
+ : QDesignerWidgetDataBaseInterface(parent),
+ m_core(core)
+{
+#define DECLARE_LAYOUT(L, C)
+#define DECLARE_COMPAT_WIDGET(W, C) DECLARE_WIDGET(W, C)
+#define DECLARE_WIDGET(W, C) append(new WidgetDataBaseItem(QString::fromUtf8(#W)));
+
+#include "widgets.table"
+
+#undef DECLARE_COMPAT_WIDGET
+#undef DECLARE_LAYOUT
+#undef DECLARE_WIDGET
+#undef DECLARE_WIDGET_1
+
+ append(new WidgetDataBaseItem(QString::fromUtf8("Line")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("Spacer")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QSplitter")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QLayoutWidget")));
+ // QDesignerWidget is used as central widget and as container for tab widgets, etc.
+ WidgetDataBaseItem *designerWidgetItem = new WidgetDataBaseItem(QString::fromUtf8("QDesignerWidget"));
+ designerWidgetItem->setContainer(true);
+ append(designerWidgetItem);
+ append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDialog")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenu")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenuBar")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDockWidget")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerQ3WidgetStack")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QAction")));
+ append(new WidgetDataBaseItem(QString::fromUtf8("QButtonGroup")));
+
+ // ### remove me
+ // ### check the casts
+
+#if 0 // ### enable me after 4.1
+ item(indexOfClassName(QLatin1String("QToolBar")))->setContainer(true);
+#endif
+
+ item(indexOfClassName(QLatin1String("QTabWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QGroupBox")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QScrollArea")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QStackedWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QToolBox")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QFrame")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QLayoutWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDesignerWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDesignerDialog")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QSplitter")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QMainWindow")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDockWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDesignerDockWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDesignerQ3WidgetStack")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QMdiArea")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QWorkspace")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QWizard")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QWizardPage")))->setContainer(true);
+
+ item(indexOfClassName(QLatin1String("QWidget")))->setContainer(true);
+ item(indexOfClassName(QLatin1String("QDialog")))->setContainer(true);
+}
+
+WidgetDataBase::~WidgetDataBase()
+{
+}
+
+QDesignerFormEditorInterface *WidgetDataBase::core() const
+{
+ return m_core;
+}
+
+int WidgetDataBase::indexOfObject(QObject *object, bool /*resolveName*/) const
+{
+ QExtensionManager *mgr = m_core->extensionManager();
+ QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*> (mgr, m_core);
+
+ QString id;
+
+ if (lang)
+ id = lang->classNameOf(object);
+
+ if (id.isEmpty())
+ id = WidgetFactory::classNameOf(m_core,object);
+
+ return QDesignerWidgetDataBaseInterface::indexOfClassName(id);
+}
+
+static WidgetDataBaseItem *createCustomWidgetItem(const QDesignerCustomWidgetInterface *c,
+ const QDesignerCustomWidgetData &data)
+{
+ WidgetDataBaseItem *item = new WidgetDataBaseItem(c->name(), c->group());
+ item->setContainer(c->isContainer());
+ item->setCustom(true);
+ item->setIcon(c->icon());
+ item->setIncludeFile(c->includeFile());
+ item->setToolTip(c->toolTip());
+ item->setWhatsThis(c->whatsThis());
+ item->setPluginPath(data.pluginPath());
+ item->setAddPageMethod(data.xmlAddPageMethod());
+ item->setExtends(data.xmlExtends());
+ return item;
+}
+
+void WidgetDataBase::loadPlugins()
+{
+ typedef QMap<QString, int> NameIndexMap;
+ typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
+ typedef QMap<QString, QDesignerWidgetDataBaseItemInterface*> NameItemMap;
+ typedef QSet<QString> NameSet;
+ // 1) create a map of existing custom classes
+ NameIndexMap existingCustomClasses;
+ NameSet nonCustomClasses;
+ const int count = m_items.size();
+ for (int i = 0; i < count; i++) {
+ const QDesignerWidgetDataBaseItemInterface* item = m_items[i];
+ if (item->isCustom() && !item->isPromoted())
+ existingCustomClasses.insert(item->name(), i);
+ else
+ nonCustomClasses.insert(item->name());
+ }
+ // 2) create a list plugins
+ ItemList pluginList;
+ const QDesignerPluginManager *pm = m_core->pluginManager();
+ foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
+ pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
+
+ // 3) replace custom classes or add new ones, remove them from existingCustomClasses,
+ // leaving behind deleted items
+ unsigned replacedPlugins = 0;
+ unsigned addedPlugins = 0;
+ unsigned removedPlugins = 0;
+ if (!pluginList.empty()) {
+ ItemList::const_iterator cend = pluginList.constEnd();
+ for (ItemList::const_iterator it = pluginList.constBegin();it != cend; ++it ) {
+ QDesignerWidgetDataBaseItemInterface* pluginItem = *it;
+ const QString pluginName = pluginItem->name();
+ NameIndexMap::iterator existingIt = existingCustomClasses.find(pluginName);
+ if (existingIt == existingCustomClasses.end()) {
+ // Add new class.
+ if (nonCustomClasses.contains(pluginName)) {
+ designerWarning(tr("A custom widget plugin whose class name (%1) matches that of an existing class has been found.").arg(pluginName));
+ } else {
+ append(pluginItem);
+ addedPlugins++;
+ }
+ } else {
+ // replace existing info
+ const int existingIndex = existingIt.value();
+ delete m_items[existingIndex];
+ m_items[existingIndex] = pluginItem;
+ existingCustomClasses.erase(existingIt);
+ replacedPlugins++;
+
+ }
+ }
+ }
+ // 4) remove classes that have not been matched. The stored indexes become invalid while deleting.
+ if (!existingCustomClasses.empty()) {
+ NameIndexMap::const_iterator cend = existingCustomClasses.constEnd();
+ for (NameIndexMap::const_iterator it = existingCustomClasses.constBegin();it != cend; ++it ) {
+ const int index = indexOfClassName(it.key());
+ if (index != -1) {
+ remove(index);
+ removedPlugins++;
+ }
+ }
+ }
+ if (debugWidgetDataBase)
+ qDebug() << "WidgetDataBase::loadPlugins(): " << addedPlugins << " added, " << replacedPlugins << " replaced, " << removedPlugins << "deleted.";
+}
+
+void WidgetDataBase::remove(int index)
+{
+ Q_ASSERT(index < m_items.size());
+ delete m_items.takeAt(index);
+}
+
+QList<QVariant> WidgetDataBase::defaultPropertyValues(const QString &name)
+{
+ WidgetFactory *factory = qobject_cast<WidgetFactory *>(m_core->widgetFactory());
+ Q_ASSERT(factory);
+ // Create non-widgets, widgets in order
+ QObject* object = factory->createObject(name, 0);
+ if (!object)
+ object = factory->createWidget(name, 0);
+ if (!object) {
+ qDebug() << "** WARNING Factory failed to create " << name;
+ return QList<QVariant>();
+ }
+ // Get properties from sheet.
+ QList<QVariant> result;
+ if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object)) {
+ const int propertyCount = sheet->count();
+ for (int i = 0; i < propertyCount; ++i) {
+ result.append(sheet->property(i));
+ }
+ }
+ delete object;
+ return result;
+}
+
+void WidgetDataBase::grabDefaultPropertyValues()
+{
+ const int itemCount = count();
+ for (int i = 0; i < itemCount; ++i) {
+ QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
+ const QList<QVariant> default_prop_values = defaultPropertyValues(dbItem->name());
+ dbItem->setDefaultPropertyValues(default_prop_values);
+ }
+}
+
+void WidgetDataBase::grabStandardWidgetBoxIcons()
+{
+ // At this point, grab the default icons for the non-custom widgets from
+ // the widget box. They will show up in the object inspector.
+ if (const QDesignerWidgetBox *wb = qobject_cast<const QDesignerWidgetBox *>(m_core->widgetBox())) {
+ const QString qWidgetClass = QLatin1String("QWidget");
+ const int itemCount = count();
+ for (int i = 0; i < itemCount; ++i) {
+ QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
+ if (!dbItem->isCustom() && dbItem->icon().isNull()) {
+ // Careful not to catch the layout icons when looking for
+ // QWidget
+ const QString name = dbItem->name();
+ if (name == qWidgetClass) {
+ dbItem->setIcon(wb->iconForWidget(name, QLatin1String("Containers")));
+ } else {
+ dbItem->setIcon(wb->iconForWidget(name));
+ }
+ }
+ }
+ }
+}
+
+// --------------------- Functions relevant generation of new forms based on widgets (apart from the standard templates)
+
+enum { NewFormWidth = 400, NewFormHeight = 300 };
+
+// Check if class is suitable to generate a form from
+static inline bool isExistingTemplate(const QString &className)
+{
+ return className == QLatin1String("QWidget") || className == QLatin1String("QDialog") || className == QLatin1String("QMainWindow");
+}
+
+// Check if class is suitable to generate a form from
+static inline bool suitableForNewForm(const QString &className)
+{
+ if (className.isEmpty()) // Missing custom widget information
+ return false;
+ if (className == QLatin1String("QWorkspace"))
+ return false;
+ if (className == QLatin1String("QSplitter"))
+ return false;
+ if (className.startsWith(QLatin1String("QDesigner")) || className.startsWith(QLatin1String("Q3")) || className.startsWith(QLatin1String("QLayout")))
+ return false;
+ return true;
+}
+
+// Return a list of widget classes from which new forms can be generated.
+// Suitable for 'New form' wizards in integrations.
+QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core)
+{
+ static QStringList rc;
+ if (rc.empty()) {
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ const int widgetCount = wdb->count();
+ for (int i = 0; i < widgetCount; i++) {
+ const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
+ if (item->isContainer() && !item->isCustom() && !item->isPromoted()) {
+ const QString name = item->name(); // Standard Widgets: no existing templates
+ if (!isExistingTemplate(name) && suitableForNewForm(name))
+ rc += name;
+ }
+ }
+ }
+ return rc;
+}
+
+// Return a list of custom widget classes from which new forms can be generated.
+// Suitable for 'New form' wizards in integrations.
+QStringList WidgetDataBase::customFormWidgetClasses(const QDesignerFormEditorInterface *core)
+{
+ QStringList rc;
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ const int widgetCount = wdb->count();
+ for (int i = 0; i < widgetCount; i++) { // Custom widgets: check name and base class.
+ const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
+ if (item->isContainer() && item->isCustom() && !item->isPromoted()) {
+ if (suitableForNewForm(item->name()) && suitableForNewForm(item->extends()))
+ rc += item->name();
+ }
+ }
+ return rc;
+}
+
+// Get XML for a new form from the widget box. Change objectName/geometry
+// properties to be suitable for new forms
+static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
+{
+ typedef QList<DomProperty*> PropertyList;
+
+ QDesignerWidgetBoxInterface::Widget widget;
+ const bool found = QDesignerWidgetBox::findWidget(core->widgetBox(), className, QString(), &widget);
+ if (!found)
+ return QString();
+ DomUI *domUI = QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false);
+ domUI->setAttributeVersion(QLatin1String("4.0"));
+ if (!domUI)
+ return QString();
+ DomWidget *domWidget = domUI->elementWidget();
+ if (!domWidget)
+ return QString();
+ // Properties: Remove the "objectName" property in favour of the name attribute and check geometry.
+ domWidget->setAttributeName(objectName);
+ const QString geometryProperty = QLatin1String("geometry");
+ const QString objectNameProperty = QLatin1String("objectName");
+ PropertyList properties = domWidget->elementProperty();
+ for (PropertyList::iterator it = properties.begin(); it != properties.end(); ) {
+ DomProperty *property = *it;
+ if (property->attributeName() == objectNameProperty) { // remove "objectName"
+ it = properties.erase(it);
+ delete property;
+ } else {
+ if (property->attributeName() == geometryProperty) { // Make sure form is at least 400, 300
+ if (DomRect *geom = property->elementRect()) {
+ if (geom->elementWidth() < NewFormWidth)
+ geom->setElementWidth(NewFormWidth);
+ if (geom->elementHeight() < NewFormHeight)
+ geom->setElementHeight(NewFormHeight);
+ }
+ }
+ ++it;
+ }
+ }
+ // Add a window title property
+ DomString *windowTitleString = new DomString;
+ windowTitleString->setText(objectName);
+ DomProperty *windowTitleProperty = new DomProperty;
+ windowTitleProperty->setAttributeName(QLatin1String("windowTitle"));
+ windowTitleProperty->setElementString(windowTitleString);
+ properties.push_back(windowTitleProperty);
+ // ------
+ domWidget->setElementProperty(properties);
+ // Embed in in DomUI and get string. Omit the version number.
+ domUI->setElementClass(objectName);
+
+ QString rc;
+ { // Serialize domUI
+ QXmlStreamWriter writer(&rc);
+ writer.setAutoFormatting(true);
+ writer.setAutoFormattingIndent(1);
+ writer.writeStartDocument();
+ domUI->write(writer);
+ writer.writeEndDocument();
+ }
+ delete domUI;
+ return rc;
+}
+
+// Generate default standard ui new form xml based on the class passed on as similarClassName.
+static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name)
+{
+ QString rc; {
+ QTextStream str(&rc);
+ str << QLatin1String("<ui version=\"4.0\" >\n<class>") << name << QLatin1String("</class>\n")
+ << QLatin1String("<widget class=\"") << className << QLatin1String("\" name=\"") << name << QLatin1String("\" >\n")
+ << QLatin1String("<property name=\"geometry\" >\n<rect><x>0</x><y>0</y><width>")
+ << NewFormWidth << QLatin1String("</width><height>") << NewFormHeight << QLatin1String("</height></rect>\n</property>\n");
+ str << QLatin1String("<property name=\"windowTitle\" >\n<string>") << name << QLatin1String("</string>\n</property>\n");
+
+ if (similarClassName == QLatin1String("QMainWindow")) {
+ str << QLatin1String("<widget class=\"QWidget\" name=\"centralwidget\" />\n");
+ } else {
+ if (similarClassName == QLatin1String("QWizard"))
+ str << QLatin1String("<widget class=\"QWizardPage\" name=\"wizardPage1\" /><widget class=\"QWizardPage\" name=\"wizardPage2\" />\n");
+ }
+ str << QLatin1String("</widget>\n</ui>\n");
+ }
+ return rc;
+}
+
+// Generate a form template using a class name obtained from formWidgetClasses(), customFormWidgetClasses().
+QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
+{
+ // How to find suitable XML for a class:
+ // 1) Look in widget box (as all the required centralwidgets, tab widget pages, etc. should be there).
+ const QString widgetBoxXml = xmlFromWidgetBox(core, className, objectName);
+ if (!widgetBoxXml.isEmpty())
+ return widgetBoxXml;
+ // 2) If that fails, only custom main windows, custom dialogs and unsupported Qt Widgets should
+ // be left over. Generate something that is similar to the default templates. Find a similar class.
+ const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+ QString similarClass = QLatin1String("QWidget");
+ const int index = wdb->indexOfClassName(className);
+ if (index != -1) {
+ const QDesignerWidgetDataBaseItemInterface *item = wdb->item(index);
+ similarClass = item->isCustom() ? item->extends() : item->name();
+ }
+ // Generate standard ui based on the class passed on as baseClassName.
+ const QString rc = generateNewFormXML(className, similarClass, objectName);
+ return rc;
+}
+
+// Set a fixed size on a XML template
+QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed)
+{
+ typedef QList<DomProperty*> PropertyList;
+ DomUI *domUI = QDesignerWidgetBox::xmlToUi(QLatin1String("Form"), xml, false);
+ if (!domUI)
+ return QString();
+ DomWidget *domWidget = domUI->elementWidget();
+ if (!domWidget)
+ return QString();
+ // Properties: Find/Ensure the geometry, minimum and maximum sizes properties
+ const QString geometryPropertyName = QLatin1String("geometry");
+ const QString minimumSizePropertyName = QLatin1String("minimumSize");
+ const QString maximumSizePropertyName = QLatin1String("maximumSize");
+ DomProperty *geomProperty = 0;
+ DomProperty *minimumSizeProperty = 0;
+ DomProperty *maximumSizeProperty = 0;
+
+ PropertyList properties = domWidget->elementProperty();
+ const PropertyList::const_iterator cend = properties.constEnd();
+ for (PropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
+ const QString name = (*it)->attributeName();
+ if (name == geometryPropertyName) {
+ geomProperty = *it;
+ } else {
+ if (name == minimumSizePropertyName) {
+ minimumSizeProperty = *it;
+ } else {
+ if (name == maximumSizePropertyName)
+ maximumSizeProperty = *it;
+ }
+ }
+ }
+ if (!geomProperty) {
+ geomProperty = new DomProperty;
+ geomProperty->setAttributeName(geometryPropertyName);
+ geomProperty->setElementRect(new DomRect);
+ properties.push_front(geomProperty);
+ }
+ if (fixed) {
+ if (!minimumSizeProperty) {
+ minimumSizeProperty = new DomProperty;
+ minimumSizeProperty->setAttributeName(minimumSizePropertyName);
+ minimumSizeProperty->setElementSize(new DomSize);
+ properties.push_back(minimumSizeProperty);
+ }
+ if (!maximumSizeProperty) {
+ maximumSizeProperty = new DomProperty;
+ maximumSizeProperty->setAttributeName(maximumSizePropertyName);
+ maximumSizeProperty->setElementSize(new DomSize);
+ properties.push_back(maximumSizeProperty);
+ }
+ }
+ // Set values of geometry, minimum and maximum sizes properties
+ const int width = size.width();
+ const int height = size.height();
+ if (DomRect *geom = geomProperty->elementRect()) {
+ geom->setElementWidth(width);
+ geom->setElementHeight(height);
+ }
+ if (fixed) {
+ if (DomSize *s = minimumSizeProperty->elementSize()) {
+ s->setElementWidth(width);
+ s->setElementHeight(height);
+ }
+ if (DomSize *s = maximumSizeProperty->elementSize()) {
+ s->setElementWidth(width);
+ s->setElementHeight(height);
+ }
+ }
+ // write back
+ domWidget->setElementProperty(properties);
+
+ QString rc;
+ { // serialize domUI
+ QXmlStreamWriter writer(&rc);
+ writer.setAutoFormatting(true);
+ writer.setAutoFormattingIndent(1);
+ writer.writeStartDocument();
+ domUI->write(writer);
+ writer.writeEndDocument();
+ }
+
+ delete domUI;
+ return rc;
+}
+
+// ---- free functions
+QDESIGNER_SHARED_EXPORT IncludeSpecification includeSpecification(QString includeFile)
+{
+ const bool global = !includeFile.isEmpty() &&
+ includeFile[0] == QLatin1Char('<') &&
+ includeFile[includeFile.size() - 1] == QLatin1Char('>');
+ if (global) {
+ includeFile.remove(includeFile.size() - 1, 1);
+ includeFile.remove(0, 1);
+ }
+ return IncludeSpecification(includeFile, global ? IncludeGlobal : IncludeLocal);
+}
+
+QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType) {
+ if (includeType == IncludeGlobal && !includeFile.isEmpty()) {
+ includeFile.append(QLatin1Char('>'));
+ includeFile.insert(0, QLatin1Char('<'));
+ }
+ return includeFile;
+}
+
+
+/* Appends a derived class to the database inheriting the data of the base class. Used
+ for custom and promoted widgets.
+
+ Depending on whether an entry exists, the existing or a newly created entry is
+ returned. A return value of 0 indicates that the base class could not be found. */
+
+QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface *
+ appendDerived(QDesignerWidgetDataBaseInterface *db,
+ const QString &className, const QString &group,
+ const QString &baseClassName,
+ const QString &includeFile,
+ bool promoted, bool custom)
+{
+ if (debugWidgetDataBase)
+ qDebug() << "appendDerived " << className << " derived from " << baseClassName;
+ // Check.
+ if (className.isEmpty() || baseClassName.isEmpty()) {
+ qWarning("** WARNING %s called with an empty class names: '%s' extends '%s'.",
+ Q_FUNC_INFO, className.toUtf8().constData(), baseClassName.toUtf8().constData());
+ return 0;
+ }
+ // Check whether item already exists.
+ QDesignerWidgetDataBaseItemInterface *derivedItem = 0;
+ const int existingIndex = db->indexOfClassName(className);
+ if ( existingIndex != -1)
+ derivedItem = db->item(existingIndex);
+ if (derivedItem) {
+ // Check the existing item for base class mismatch. This will likely
+ // happen when loading a file written by an instance with missing plugins.
+ // In that case, just warn and ignore the file properties.
+ //
+ // An empty base class indicates that it is not known (for example, for custom plugins).
+ // In this case, the widget DB is later updated once the widget is created
+ // by DOM (by querying the metaobject). Suppress the warning.
+ const QString existingBaseClass = derivedItem->extends();
+ if (existingBaseClass.isEmpty() || baseClassName == existingBaseClass)
+ return derivedItem;
+
+ // Warn about mismatches
+ designerWarning(QCoreApplication::translate("WidgetDataBase",
+ "The file contains a custom widget '%1' whose base class (%2)"
+ " differs from the current entry in the widget database (%3)."
+ " The widget database is left unchanged.").
+ arg(className, baseClassName, existingBaseClass));
+ return derivedItem;
+ }
+ // Create this item, inheriting its base properties
+ const int baseIndex = db->indexOfClassName(baseClassName);
+ if (baseIndex == -1) {
+ if (debugWidgetDataBase)
+ qDebug() << "appendDerived failed due to missing base class";
+ return 0;
+ }
+ const QDesignerWidgetDataBaseItemInterface *baseItem = db->item(baseIndex);
+ derivedItem = WidgetDataBaseItem::clone(baseItem);
+ // Sort of hack: If base class is QWidget, we most likely
+ // do not want to inherit the container attribute.
+ static const QString qWidgetName = QLatin1String("QWidget");
+ if (baseItem->name() == qWidgetName)
+ derivedItem->setContainer(false);
+ // set new props
+ derivedItem->setName(className);
+ derivedItem->setGroup(group);
+ derivedItem->setCustom(custom);
+ derivedItem->setPromoted(promoted);
+ derivedItem->setExtends(baseClassName);
+ derivedItem->setIncludeFile(includeFile);
+ db->append(derivedItem);
+ return derivedItem;
+}
+
+/* Return a list of database items to which a class can be promoted to. */
+
+QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
+ promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
+ const QString &baseClassName)
+{
+ WidgetDataBaseItemList rc;
+ // find existing promoted widgets deriving from base.
+ const int count = db->count();
+ for (int i = 0; i < count; ++i) {
+ QDesignerWidgetDataBaseItemInterface *item = db->item(i);
+ if (item->isPromoted() && item->extends() == baseClassName) {
+ rc.push_back(item);
+ }
+ }
+ return rc;
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/widgetdatabase_p.h b/tools/designer/src/lib/shared/widgetdatabase_p.h
new file mode 100644
index 0000000..4414bbe
--- /dev/null
+++ b/tools/designer/src/lib/shared/widgetdatabase_p.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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 WIDGETDATABASE_H
+#define WIDGETDATABASE_H
+
+#include "shared_global_p.h"
+
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtGui/QIcon>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QPair>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QDesignerCustomWidgetInterface;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT WidgetDataBaseItem: public QDesignerWidgetDataBaseItemInterface
+{
+public:
+ WidgetDataBaseItem(const QString &name = QString(),
+ const QString &group = QString());
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString group() const;
+ void setGroup(const QString &group);
+
+ QString toolTip() const;
+ void setToolTip(const QString &toolTip);
+
+ QString whatsThis() const;
+ void setWhatsThis(const QString &whatsThis);
+
+ QString includeFile() const;
+ void setIncludeFile(const QString &includeFile);
+
+
+ QIcon icon() const;
+ void setIcon(const QIcon &icon);
+
+ bool isCompat() const;
+ void setCompat(bool compat);
+
+ bool isContainer() const;
+ void setContainer(bool b);
+
+ bool isCustom() const;
+ void setCustom(bool b);
+
+ QString pluginPath() const;
+ void setPluginPath(const QString &path);
+
+ bool isPromoted() const;
+ void setPromoted(bool b);
+
+ QString extends() const;
+ void setExtends(const QString &s);
+
+ void setDefaultPropertyValues(const QList<QVariant> &list);
+ QList<QVariant> defaultPropertyValues() const;
+
+ static WidgetDataBaseItem *clone(const QDesignerWidgetDataBaseItemInterface *item);
+
+ QStringList fakeSlots() const;
+ void setFakeSlots(const QStringList &);
+
+ QStringList fakeSignals() const;
+ void setFakeSignals(const QStringList &);
+
+ QString addPageMethod() const;
+ void setAddPageMethod(const QString &m);
+
+private:
+ QString m_name;
+ QString m_group;
+ QString m_toolTip;
+ QString m_whatsThis;
+ QString m_includeFile;
+ QString m_pluginPath;
+ QString m_extends;
+ QString m_addPageMethod;
+ QIcon m_icon;
+ uint m_compat: 1;
+ uint m_container: 1;
+ uint m_form: 1;
+ uint m_custom: 1;
+ uint m_promoted: 1;
+ QList<QVariant> m_defaultPropertyValues;
+ QStringList m_fakeSlots;
+ QStringList m_fakeSignals;
+};
+
+enum IncludeType { IncludeLocal, IncludeGlobal };
+
+typedef QPair<QString, IncludeType> IncludeSpecification;
+
+QDESIGNER_SHARED_EXPORT IncludeSpecification includeSpecification(QString includeFile);
+QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType);
+
+class QDESIGNER_SHARED_EXPORT WidgetDataBase: public QDesignerWidgetDataBaseInterface
+{
+ Q_OBJECT
+public:
+ WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent = 0);
+ virtual ~WidgetDataBase();
+
+ virtual QDesignerFormEditorInterface *core() const;
+
+ virtual int indexOfObject(QObject *o, bool resolveName = true) const;
+
+ void remove(int index);
+
+
+ void grabDefaultPropertyValues();
+ void grabStandardWidgetBoxIcons();
+
+ // Helpers for 'New Form' wizards in integrations. Obtain a list of suitable classes and generate XML for them.
+ static QStringList formWidgetClasses(const QDesignerFormEditorInterface *core);
+ static QStringList customFormWidgetClasses(const QDesignerFormEditorInterface *core);
+ static QString formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName);
+
+ // Helpers for 'New Form' wizards: Set a fixed size on a XML form template
+ static QString scaleFormTemplate(const QString &xml, const QSize &size, bool fixed);
+
+public slots:
+ void loadPlugins();
+
+private:
+ QList<QVariant> defaultPropertyValues(const QString &name);
+
+ QDesignerFormEditorInterface *m_core;
+};
+
+QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface
+ *appendDerived(QDesignerWidgetDataBaseInterface *db,
+ const QString &className,
+ const QString &group,
+ const QString &baseClassName,
+ const QString &includeFile,
+ bool promoted,
+ bool custom);
+
+typedef QList<QDesignerWidgetDataBaseItemInterface*> WidgetDataBaseItemList;
+
+QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
+ promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
+ const QString &baseClassName);
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // WIDGETDATABASE_H
diff --git a/tools/designer/src/lib/shared/widgetfactory.cpp b/tools/designer/src/lib/shared/widgetfactory.cpp
new file mode 100644
index 0000000..3822fec
--- /dev/null
+++ b/tools/designer/src/lib/shared/widgetfactory.cpp
@@ -0,0 +1,897 @@
+/****************************************************************************
+**
+** 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::WidgetFactory
+*/
+
+#include "widgetfactory_p.h"
+#include "widgetdatabase_p.h"
+#include "metadatabase_p.h"
+#include "qlayout_widget_p.h"
+#include "qdesigner_widget_p.h"
+#include "qdesigner_tabwidget_p.h"
+#include "qdesigner_toolbox_p.h"
+#include "qdesigner_stackedbox_p.h"
+#include "qdesigner_toolbar_p.h"
+#include "qdesigner_menubar_p.h"
+#include "qdesigner_menu_p.h"
+#include "qdesigner_dockwidget_p.h"
+#include "qdesigner_utils_p.h"
+#include "formwindowbase_p.h"
+
+// shared
+#include "layoutinfo_p.h"
+#include "spacer_widget_p.h"
+#include "layout_p.h"
+#include "abstractintrospection_p.h"
+
+// sdk
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerContainerExtension>
+#include <QtDesigner/QDesignerCustomWidgetInterface>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerPropertySheetExtension>
+#include <QtDesigner/QDesignerLanguageExtension>
+#include <QtDesigner/QDesignerFormWindowManagerInterface>
+#include <QtDesigner/QDesignerFormWindowCursorInterface>
+
+#include <QtGui/QtGui>
+#include <QtGui/QScrollBar>
+#include <QtGui/QFontComboBox>
+#include <QtGui/QAbstractSpinBox>
+#include <QtGui/QLineEdit>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QStyle>
+#include <QtGui/QStyleFactory>
+#include <QtGui/QWizard>
+#include <QtCore/qdebug.h>
+#include <QtCore/QMetaObject>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+static inline bool isAxWidget(const QObject *o)
+{
+ // Is it one of QDesignerAxWidget/QDesignerAxPluginWidget?
+ static const char *axWidgetName = "QDesignerAx";
+ static const unsigned axWidgetNameLen = qstrlen(axWidgetName);
+ return qstrncmp(o->metaObject()->className(), axWidgetName, axWidgetNameLen) == 0;
+}
+#endif
+
+/* Dynamic boolean property indicating object was created by the factory
+ * for the form editor. */
+
+static const char *formEditorDynamicProperty = "_q_formEditorObject";
+
+namespace qdesigner_internal {
+
+// A friendly SpinBox that grants access to its QLineEdit
+class FriendlySpinBox : public QAbstractSpinBox {
+public:
+ friend class WidgetFactory;
+};
+
+// An event filter for form-combo boxes that prevents the embedded line edit
+// from getting edit focus (and drawing blue artifacts/lines). It catches the
+// ChildPolished event when the "editable" property flips to true and the
+// QLineEdit is created and turns off the LineEdit's focus policy.
+
+class ComboEventFilter : public QObject {
+public:
+ explicit ComboEventFilter(QComboBox *parent) : QObject(parent) {}
+ virtual bool eventFilter(QObject *watched, QEvent *event);
+};
+
+bool ComboEventFilter::eventFilter(QObject *watched, QEvent *event)
+{
+ if (event->type() == QEvent::ChildPolished) {
+ QComboBox *cb = static_cast<QComboBox*>(watched);
+ if (QLineEdit *le = cb->lineEdit())
+ le->setFocusPolicy(Qt::NoFocus);
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+/* Watch out for QWizards changing their pages and make sure that not some
+ * selected widget becomes invisible on a hidden page (causing the selection
+ * handles to shine through). Select the wizard in that case in analogy to
+ * the QTabWidget event filters, etc. */
+
+class WizardPageChangeWatcher : public QObject {
+ Q_OBJECT
+public:
+ explicit WizardPageChangeWatcher(QWizard *parent);
+
+public slots:
+ void pageChanged();
+};
+
+WizardPageChangeWatcher::WizardPageChangeWatcher(QWizard *parent) :
+ QObject(parent)
+{
+ connect(parent, SIGNAL(currentIdChanged(int)), this, SLOT(pageChanged()));
+}
+
+void WizardPageChangeWatcher::pageChanged()
+{
+ /* Use a bit more conservative approach than that for the QTabWidget,
+ * change the selection only if a selected child becomes invisible by
+ * changing the page. */
+ QWizard *wizard = static_cast<QWizard *>(parent());
+ QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(wizard);
+ if (!fw)
+ return;
+ QDesignerFormWindowCursorInterface *cursor = fw->cursor();
+ const int selCount = cursor->selectedWidgetCount();
+ for (int i = 0; i < selCount; i++) {
+ if (!cursor->selectedWidget(i)->isVisible()) {
+ fw->clearSelection(false);
+ fw->selectWidget(wizard, true);
+ break;
+ }
+ }
+}
+
+// ---------------- WidgetFactory::Strings
+WidgetFactory::Strings::Strings() :
+ m_alignment(QLatin1String("alignment")),
+ m_bottomMargin(QLatin1String("bottomMargin")),
+ m_geometry(QLatin1String("geometry")),
+ m_leftMargin(QLatin1String("leftMargin")),
+ m_line(QLatin1String("Line")),
+ m_objectName(QLatin1String("objectName")),
+ m_spacerName(QLatin1String("spacerName")),
+ m_orientation(QLatin1String("orientation")),
+ m_q3WidgetStack(QLatin1String("Q3WidgetStack")),
+ m_qAction(QLatin1String("QAction")),
+ m_qButtonGroup(QLatin1String("QButtonGroup")),
+ m_qAxWidget(QLatin1String("QAxWidget")),
+ m_qDialog(QLatin1String("QDialog")),
+ m_qDockWidget(QLatin1String("QDockWidget")),
+ m_qLayoutWidget(QLatin1String("QLayoutWidget")),
+ m_qMenu(QLatin1String("QMenu")),
+ m_qMenuBar(QLatin1String("QMenuBar")),
+ m_qWidget(QLatin1String("QWidget")),
+ m_rightMargin(QLatin1String("rightMargin")),
+ m_sizeHint(QLatin1String("sizeHint")),
+ m_spacer(QLatin1String("Spacer")),
+ m_text(QLatin1String("text")),
+ m_title(QLatin1String("title")),
+ m_topMargin(QLatin1String("topMargin")),
+ m_windowIcon(QLatin1String("windowIcon")),
+ m_windowTitle(QLatin1String("windowTitle"))
+{
+}
+// ---------------- WidgetFactory
+QPointer<QWidget> *WidgetFactory::m_lastPassiveInteractor = new QPointer<QWidget>();
+bool WidgetFactory::m_lastWasAPassiveInteractor = false;
+const char *WidgetFactory::disableStyleCustomPaintingPropertyC = "_q_custom_style_disabled";
+
+WidgetFactory::WidgetFactory(QDesignerFormEditorInterface *core, QObject *parent)
+ : QDesignerWidgetFactoryInterface(parent),
+ m_core(core),
+ m_formWindow(0),
+ m_currentStyle(0)
+{
+}
+
+WidgetFactory::~WidgetFactory()
+{
+}
+
+QDesignerFormWindowInterface *WidgetFactory::currentFormWindow(QDesignerFormWindowInterface *fw)
+{
+ QDesignerFormWindowInterface *was = m_formWindow;
+ m_formWindow = fw;
+ return was;
+}
+
+void WidgetFactory::loadPlugins()
+{
+ m_customFactory.clear();
+
+ QDesignerPluginManager *pluginManager = m_core->pluginManager();
+
+ QList<QDesignerCustomWidgetInterface*> lst = pluginManager->registeredCustomWidgets();
+ foreach (QDesignerCustomWidgetInterface *c, lst) {
+ m_customFactory.insert(c->name(), c);
+ }
+}
+
+// Convencience to create non-widget objects. Returns 0 if unknown
+QObject* WidgetFactory::createObject(const QString &className, QObject* parent) const
+{
+ if (className.isEmpty()) {
+ qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO);
+ return 0;
+ }
+ if (className == m_strings.m_qAction)
+ return new QAction(parent);
+ if (className == m_strings.m_qButtonGroup)
+ return new QButtonGroup(parent);
+ return 0;
+}
+
+QWidget* WidgetFactory::createCustomWidget(const QString &className, QWidget *parentWidget, bool *creationError) const
+{
+ *creationError = false;
+ CustomWidgetFactoryMap::const_iterator it = m_customFactory.constFind(className);
+ if (it == m_customFactory.constEnd())
+ return 0;
+
+ QDesignerCustomWidgetInterface *factory = it.value();
+ QWidget *rc = factory->createWidget(parentWidget);
+ // shouldn't happen
+ if (!rc) {
+ *creationError = true;
+ designerWarning(tr("The custom widget factory registered for widgets of class %1 returned 0.").arg(className));
+ return 0;
+ }
+ // Figure out the base class unless it is known
+ static QSet<QString> knownCustomClasses;
+ if (!knownCustomClasses.contains(className)) {
+ QDesignerWidgetDataBaseInterface *wdb = m_core->widgetDataBase();
+ const int widgetInfoIndex = wdb->indexOfObject(rc, false);
+ if (widgetInfoIndex != -1) {
+ if (wdb->item(widgetInfoIndex)->extends().isEmpty()) {
+ const QDesignerMetaObjectInterface *mo = core()->introspection()->metaObject(rc)->superClass();
+ // If we hit on a 'Q3DesignerXXWidget' that claims to be a 'Q3XXWidget', step
+ // over.
+ if (mo && mo->className() == className)
+ mo = mo->superClass();
+ while (mo != 0) {
+ if (core()->widgetDataBase()->indexOfClassName(mo->className()) != -1) {
+ wdb->item(widgetInfoIndex)->setExtends(mo->className());
+ break;
+ }
+ mo = mo->superClass();
+ }
+ }
+ knownCustomClasses.insert(className);
+ }
+ }
+ // Since a language plugin may lie about its names, like Qt Jambi
+ // does, return immediately here...
+ QDesignerLanguageExtension *lang =
+ qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core);
+ if (lang)
+ return rc;
+
+#ifdef Q_OS_WIN
+ if (isAxWidget(rc))
+ return rc;
+#endif
+ // Check for mismatched class names which is hard to track.
+ // Perform literal comparison first for QAxWidget, for which a meta object hack is in effect.
+ const char *createdClassNameC = rc->metaObject()->className();
+ const QByteArray classNameB = className.toUtf8();
+ const char *classNameC = classNameB.constData();
+
+ if (qstrcmp(createdClassNameC, classNameC) && !rc->inherits(classNameC))
+ designerWarning(tr("A class name mismatch occurred when creating a widget using the custom widget factory registered for widgets of class %1."
+ " It returned a widget of class %2.").arg(className).arg(QString::fromUtf8(createdClassNameC)));
+ return rc;
+}
+
+
+QWidget *WidgetFactory::createWidget(const QString &widgetName, QWidget *parentWidget) const
+{
+ if (widgetName.isEmpty()) {
+ qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO);
+ return 0;
+ }
+ // Preview or for form window?
+ QDesignerFormWindowInterface *fw = m_formWindow;
+ if (! fw)
+ fw = QDesignerFormWindowInterface::findFormWindow(parentWidget);
+
+ QWidget *w = 0;
+ do {
+ // 1) custom. If there is an explicit failure(factory wants to indicate something is wrong),
+ // return 0, do not try to find fallback, which might be worse in the case of Q3 widget.
+ bool customWidgetCreationError;
+ w = createCustomWidget(widgetName, parentWidget, &customWidgetCreationError);
+ if (w) {
+ break;
+ } else {
+ if (customWidgetCreationError)
+ return 0;
+ }
+
+ // 2) Special widgets
+ if (widgetName == m_strings.m_line) {
+ w = new Line(parentWidget);
+ } else if (widgetName == m_strings.m_qDockWidget) {
+ w = new QDesignerDockWidget(parentWidget);
+ } else if (widgetName == m_strings.m_qMenuBar) {
+ w = new QDesignerMenuBar(parentWidget);
+ } else if (widgetName == m_strings.m_qMenu) {
+ w = new QDesignerMenu(parentWidget);
+ } else if (widgetName == m_strings.m_spacer) {
+ w = new Spacer(parentWidget);
+ } else if (widgetName == m_strings.m_qDockWidget) {
+ w = new QDesignerDockWidget(parentWidget);
+ } else if (widgetName == m_strings.m_qLayoutWidget) {
+ w = fw ? new QLayoutWidget(fw, parentWidget) : new QWidget(parentWidget);
+ } else if (widgetName == m_strings.m_qDialog) {
+ if (fw) {
+ w = new QDesignerDialog(fw, parentWidget);
+ } else {
+ w = new QDialog(parentWidget);
+ }
+ } else if (widgetName == m_strings.m_qWidget) {
+ /* We want a 'QDesignerWidget' that draws a grid only for widget
+ * forms and container extension pages (not for preview and not
+ * for normal QWidget children on forms (legacy) */
+ if (fw && parentWidget) {
+ if (qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), parentWidget)) {
+ w = new QDesignerWidget(fw, parentWidget);
+ } else {
+ if (const FormWindowBase *fwb = qobject_cast<FormWindowBase *>(fw))
+ if (parentWidget == fwb->formContainer())
+ w = new QDesignerWidget(fw, parentWidget);
+ }
+ }
+ if (!w)
+ w = new QWidget(parentWidget);
+ }
+ if (w)
+ break;
+
+ // 3) table
+ const QByteArray widgetNameBA = widgetName.toUtf8();
+ const char *widgetNameC = widgetNameBA.constData();
+
+ if (w) { // symmetry for macro
+ }
+
+#define DECLARE_LAYOUT(L, C)
+#define DECLARE_COMPAT_WIDGET(W, C) /*DECLARE_WIDGET(W, C)*/
+#define DECLARE_WIDGET(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(parentWidget); }
+#define DECLARE_WIDGET_1(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(0, parentWidget); }
+
+#include "widgets.table"
+
+#undef DECLARE_COMPAT_WIDGET
+#undef DECLARE_LAYOUT
+#undef DECLARE_WIDGET
+#undef DECLARE_WIDGET_1
+
+ if (w)
+ break;
+ // 4) fallBack
+ const QString fallBackBaseClass = m_strings.m_qWidget;
+ QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
+ QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfClassName(widgetName));
+ if (item == 0) {
+ // Emergency: Create, derived from QWidget
+ QString includeFile = widgetName.toLower();
+ includeFile += QLatin1String(".h");
+ item = appendDerived(db,widgetName, tr("%1 Widget").arg(widgetName),fallBackBaseClass,
+ includeFile, true, true);
+ Q_ASSERT(item);
+ }
+ QString baseClass = item->extends();
+ if (baseClass.isEmpty()) {
+ // Currently happens in the case of Q3-Support widgets
+ baseClass =fallBackBaseClass;
+ }
+ w = createWidget(baseClass, parentWidget);
+ promoteWidget(core(),w,widgetName);
+ } while (false);
+
+ Q_ASSERT(w != 0);
+ if (m_currentStyle)
+ w->setStyle(m_currentStyle);
+ initializeCommon(w);
+ if (fw) { // form editor initialization
+ initialize(w);
+ } else { // preview-only initialization
+ initializePreview(w);
+ }
+ return w;
+}
+
+QString WidgetFactory::classNameOf(QDesignerFormEditorInterface *c, const QObject* o)
+{
+ if (o == 0)
+ return QString();
+
+ const char *className = o->metaObject()->className();
+ if (!o->isWidgetType())
+ return QLatin1String(className);
+ const QWidget *w = static_cast<const QWidget*>(o);
+ // check promoted before designer special
+ const QString customClassName = promotedCustomClassName(c, const_cast<QWidget*>(w));
+ if (!customClassName.isEmpty())
+ return customClassName;
+ if (qobject_cast<const QDesignerMenuBar*>(w))
+ return QLatin1String("QMenuBar");
+ else if (qobject_cast<const QDesignerMenu*>(w))
+ return QLatin1String("QMenu");
+ else if (qobject_cast<const QDesignerDockWidget*>(w))
+ return QLatin1String("QDockWidget");
+ else if (qobject_cast<const QDesignerDialog*>(w))
+ return QLatin1String("QDialog");
+ else if (qobject_cast<const QDesignerWidget*>(w))
+ return QLatin1String("QWidget");
+#ifdef Q_OS_WIN
+ else if (isAxWidget(w))
+ return QLatin1String("QAxWidget");
+#endif
+ else if (qstrcmp(className, "QDesignerQ3WidgetStack") == 0)
+ return QLatin1String("Q3WidgetStack");
+
+ return QLatin1String(className);
+}
+
+QLayout *WidgetFactory::createUnmanagedLayout(QWidget *parentWidget, int type)
+{
+ switch (type) {
+ case LayoutInfo::HBox:
+ return new QHBoxLayout(parentWidget);
+ case LayoutInfo::VBox:
+ return new QVBoxLayout(parentWidget);
+ case LayoutInfo::Grid:
+ return new QGridLayout(parentWidget);
+ case LayoutInfo::Form:
+ return new QFormLayout(parentWidget);
+ default:
+ Q_ASSERT(0);
+ break;
+ }
+ return 0;
+}
+
+
+/*! Creates a layout on the widget \a widget of the type \a type
+ which can be \c HBox, \c VBox or \c Grid.
+*/
+
+QLayout *WidgetFactory::createLayout(QWidget *widget, QLayout *parentLayout, int type) const // ### (sizepolicy)
+{
+ QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
+
+ if (parentLayout == 0) {
+ QWidget *page = containerOfWidget(widget);
+ if (page) {
+ widget = page;
+ } else {
+ const QString msg = tr("The current page of the container '%1' (%2) could not be determined while creating a layout."
+"This indicates an inconsistency in the ui-file, probably a layout being constructed on a container widget.").arg(widget->objectName()).arg(classNameOf(core(), widget));
+ designerWarning(msg);
+ }
+ }
+
+ Q_ASSERT(metaDataBase->item(widget) != 0); // ensure the widget is managed
+
+ if (parentLayout == 0 && metaDataBase->item(widget->layout()) == 0) {
+ parentLayout = widget->layout();
+ }
+
+ QWidget *parentWidget = parentLayout != 0 ? 0 : widget;
+
+ QLayout *layout = createUnmanagedLayout(parentWidget, type);
+ metaDataBase->add(layout); // add the layout in the MetaDataBase
+
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), layout);
+
+ sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true);
+ if (widget->inherits("Q3GroupBox")) {
+ layout->setContentsMargins(widget->style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
+ widget->style()->pixelMetric(QStyle::PM_LayoutTopMargin),
+ widget->style()->pixelMetric(QStyle::PM_LayoutRightMargin),
+ widget->style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
+ QGridLayout *grid = qobject_cast<QGridLayout *>(layout);
+ if (grid) {
+ grid->setHorizontalSpacing(-1);
+ grid->setVerticalSpacing(-1);
+ } else {
+ layout->setSpacing(-1);
+ }
+ layout->setAlignment(Qt::AlignTop);
+ // Just to ensure; before 4.3 orientation property was always set (now only for QSplitter class).
+ // Calling Q3GroupBox::setOrientation() invoked in turn setSpacing(0). Below fixes that
+ widget->layout()->setSpacing(-1);
+ } else if (widget->inherits("QLayoutWidget")) {
+ sheet->setProperty(sheet->indexOf(m_strings.m_leftMargin), 0);
+ sheet->setProperty(sheet->indexOf(m_strings.m_topMargin), 0);
+ sheet->setProperty(sheet->indexOf(m_strings.m_rightMargin), 0);
+ sheet->setProperty(sheet->indexOf(m_strings.m_bottomMargin), 0);
+ }
+
+ if (sheet) {
+ const int index = sheet->indexOf(m_strings.m_alignment);
+ if (index != -1)
+ sheet->setChanged(index, true);
+ }
+
+ if (metaDataBase->item(widget->layout()) == 0) {
+ Q_ASSERT(layout->parent() == 0);
+ QBoxLayout *box = qobject_cast<QBoxLayout*>(widget->layout());
+ if (!box) { // we support only unmanaged box layouts
+ const QString msg = tr("Attempt to add a layout to a widget '%1' (%2) which already has an unmanaged layout of type %3.\n"
+ "This indicates an inconsistency in the ui-file.").
+ arg(widget->objectName()).arg(classNameOf(core(), widget)).arg(classNameOf(core(), widget->layout()));
+ designerWarning(msg);
+ return 0;
+ }
+ box->addLayout(layout);
+ }
+
+ return layout;
+}
+
+/*! Returns the widget into which children should be inserted when \a
+ w is a container known to designer.
+
+ Usually, it is \a w itself, but there are exceptions (for example, a
+ tabwidget is known to designer as a container, but the child
+ widgets should be inserted into the current page of the
+ tabwidget. In this case, the current page of
+ the tabwidget would be returned.)
+ */
+QWidget* WidgetFactory::containerOfWidget(QWidget *w) const
+{
+ if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), w))
+ return container->widget(container->currentIndex());
+
+ return w;
+}
+
+/*! Returns the actual designer widget of the container \a w. This is
+ normally \a w itself, but it might be a parent or grand parent of \a w
+ (for example, when working with a tabwidget and \a w is the container which
+ contains and layouts children, but the actual widget known to
+ designer is the tabwidget which is the parent of \a w. In this case,
+ the tabwidget would be returned.)
+*/
+
+QWidget* WidgetFactory::widgetOfContainer(QWidget *w) const
+{
+ // ### cleanup
+ if (!w)
+ return 0;
+ if (w->parentWidget() && w->parentWidget()->parentWidget() &&
+ w->parentWidget()->parentWidget()->parentWidget() &&
+ qobject_cast<QToolBox*>(w->parentWidget()->parentWidget()->parentWidget()))
+ return w->parentWidget()->parentWidget()->parentWidget();
+
+ while (w != 0) {
+ if (core()->widgetDataBase()->isContainer(w) ||
+ (w && qobject_cast<QDesignerFormWindowInterface*>(w->parentWidget())))
+ return w;
+
+ w = w->parentWidget();
+ }
+
+ return w;
+}
+
+QDesignerFormEditorInterface *WidgetFactory::core() const
+{
+ return m_core;
+}
+
+// Necessary initializations for form editor/preview objects
+void WidgetFactory::initializeCommon(QWidget *widget) const
+{
+ // Apply style
+ if (m_currentStyle)
+ widget->setStyle(m_currentStyle);
+ // Prevent the wizard from emulating the Windows Vista Theme.
+ // This theme (in both Aero and Basic mode) is tricky to
+ // emulate properly in designer due to 1) the manipulation of the non-client area of
+ // the top-level window, and 2) the upper-right location of the Back button.
+ // The wizard falls back to QWizard::ModernStyle whenever the Vista theme
+ // would normally apply.
+ if (QWizard *wizard = qobject_cast<QWizard *>(widget)) {
+ wizard->setProperty("_q_wizard_vista_off", QVariant(true));
+ return;
+ }
+}
+
+// Necessary initializations for preview objects
+void WidgetFactory::initializePreview(QWidget *widget) const
+{
+
+ if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
+ QStackedWidgetPreviewEventFilter::install(stackedWidget); // Add browse button only.
+ return;
+ }
+}
+
+// Necessary initializations for form editor objects
+void WidgetFactory::initialize(QObject *object) const
+{
+ // Indicate that this is a form object (for QDesignerFormWindowInterface::findFormWindow)
+ object->setProperty(formEditorDynamicProperty, QVariant(true));
+ QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object);
+ if (!sheet)
+ return;
+
+ sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true);
+
+ if (!object->isWidgetType()) {
+ if (qobject_cast<QAction*>(object))
+ sheet->setChanged(sheet->indexOf(m_strings.m_text), true);
+ return;
+ }
+
+ QWidget *widget = static_cast<QWidget*>(object);
+ const bool isMenu = qobject_cast<QMenu*>(widget);
+ const bool isMenuBar = !isMenu && qobject_cast<QMenuBar*>(widget);
+
+ widget->setAttribute(Qt::WA_TransparentForMouseEvents, false);
+ widget->setFocusPolicy((isMenu || isMenuBar) ? Qt::StrongFocus : Qt::NoFocus);
+
+ if (!isMenu)
+ sheet->setChanged(sheet->indexOf(m_strings.m_geometry), true);
+
+ if (qobject_cast<Spacer*>(widget)) {
+ sheet->setChanged(sheet->indexOf(m_strings.m_spacerName), true);
+ return;
+ }
+
+ const int o = sheet->indexOf(m_strings.m_orientation);
+ if (o != -1 && widget->inherits("QSplitter"))
+ sheet->setChanged(o, true);
+
+ if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
+ ToolBarEventFilter::install(toolBar);
+ sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true);
+ toolBar->setFloatable(false); // prevent toolbars from being dragged off
+ return;
+ }
+
+ if (qobject_cast<QDockWidget*>(widget)) {
+ sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true);
+ sheet->setVisible(sheet->indexOf(m_strings.m_windowIcon), true);
+ return;
+ }
+
+ if (isMenu) {
+ sheet->setChanged(sheet->indexOf(m_strings.m_title), true);
+ return;
+ }
+ // helpers
+ if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget)) {
+ QToolBoxHelper::install(toolBox);
+ return;
+ }
+ if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
+ QStackedWidgetEventFilter::install(stackedWidget);
+ return;
+ }
+ if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget)) {
+ QTabWidgetEventFilter::install(tabWidget);
+ return;
+ }
+ // Prevent embedded line edits from getting focus
+ if (QAbstractSpinBox *asb = qobject_cast<QAbstractSpinBox *>(widget)) {
+ if (QLineEdit *lineEdit = static_cast<FriendlySpinBox*>(asb)->lineEdit())
+ lineEdit->setFocusPolicy(Qt::NoFocus);
+ return;
+ }
+ if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
+ if (QFontComboBox *fcb = qobject_cast<QFontComboBox *>(widget)) {
+ fcb->lineEdit()->setFocusPolicy(Qt::NoFocus); // Always present
+ return;
+ }
+ cb->installEventFilter(new ComboEventFilter(cb));
+ return;
+ }
+ if (QWizard *wz = qobject_cast<QWizard *>(widget)) {
+ WizardPageChangeWatcher *pw = new WizardPageChangeWatcher(wz);
+ Q_UNUSED(pw);
+ }
+}
+
+static inline QString classNameOfStyle(const QStyle *s)
+{
+ return QLatin1String(s->metaObject()->className());
+}
+
+QString WidgetFactory::styleName() const
+{
+ return classNameOfStyle(style());
+}
+
+static inline bool isApplicationStyle(const QString &styleName)
+{
+ return styleName.isEmpty() || styleName == classNameOfStyle(qApp->style());
+}
+
+void WidgetFactory::setStyleName(const QString &styleName)
+{
+ m_currentStyle = isApplicationStyle(styleName) ? static_cast<QStyle*>(0) : getStyle(styleName);
+}
+
+QStyle *WidgetFactory::style() const
+{
+ return m_currentStyle ? m_currentStyle : qApp->style();
+}
+
+QStyle *WidgetFactory::getStyle(const QString &styleName)
+{
+ if (isApplicationStyle(styleName))
+ return qApp->style();
+
+ StyleCache::iterator it = m_styleCache.find(styleName);
+ if (it == m_styleCache.end()) {
+ QStyle *style = QStyleFactory::create(styleName);
+ if (!style) {
+ const QString msg = tr("Cannot create style '%1'.").arg(styleName);
+ designerWarning(msg);
+ return 0;
+ }
+ it = m_styleCache.insert(styleName, style);
+ }
+ return it.value();
+}
+
+void WidgetFactory::applyStyleTopLevel(const QString &styleName, QWidget *w)
+{
+ if (QStyle *style = getStyle(styleName))
+ applyStyleToTopLevel(style, w);
+}
+
+void WidgetFactory::applyStyleToTopLevel(QStyle *style, QWidget *widget)
+{
+ const QPalette standardPalette = style->standardPalette();
+ if (widget->style() == style && widget->palette() == standardPalette)
+ return;
+
+ widget->setStyle(style);
+ widget->setPalette(standardPalette);
+ const QWidgetList lst = qFindChildren<QWidget*>(widget);
+ const QWidgetList::const_iterator cend = lst.constEnd();
+ for (QWidgetList::const_iterator it = lst.constBegin(); it != cend; ++it)
+ (*it)->setStyle(style);
+}
+
+// Check for 'interactor' click on a tab bar,
+// which can appear within a QTabWidget or as a standalone widget.
+
+static bool isTabBarInteractor(const QTabBar *tabBar)
+{
+ // Tabbar embedded in Q(Designer)TabWidget, ie, normal tab widget case
+ if (qobject_cast<const QTabWidget*>(tabBar->parentWidget()))
+ return true;
+
+ // Standalone tab bar on the form. Return true for tab rect areas
+ // only to allow the user to select the tab bar by clicking outside the actual tabs.
+ const int count = tabBar->count();
+ if (count == 0)
+ return false;
+
+ // click into current tab: No Interaction
+ const int currentIndex = tabBar->currentIndex();
+ const QPoint pos = tabBar->mapFromGlobal(QCursor::pos());
+ if (tabBar->tabRect(currentIndex).contains(pos))
+ return false;
+
+ // click outside: No Interaction
+ const QRect geometry = QRect(QPoint(0, 0), tabBar->size());
+ if (!geometry.contains(pos))
+ return false;
+ // click into another tab: Let's interact, switch tabs.
+ for (int i = 0; i < count; i++)
+ if (tabBar->tabRect(i).contains(pos))
+ return true;
+ return false;
+}
+
+bool WidgetFactory::isPassiveInteractor(QWidget *widget)
+{
+ static const QString qtPassive = QLatin1String("__qt__passive_");
+ if (m_lastPassiveInteractor != 0 && (QWidget*)(*m_lastPassiveInteractor) == widget)
+ return m_lastWasAPassiveInteractor;
+
+ if (QApplication::activePopupWidget() || widget == 0) // if a popup is open, we have to make sure that this one is closed, else X might do funny things
+ return true;
+
+ m_lastWasAPassiveInteractor = false;
+ (*m_lastPassiveInteractor) = widget;
+
+ if (const QTabBar *tabBar = qobject_cast<const QTabBar*>(widget)) {
+ if (isTabBarInteractor(tabBar))
+ m_lastWasAPassiveInteractor = true;
+ return m_lastWasAPassiveInteractor;
+ } else if (qobject_cast<QSizeGrip*>(widget))
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qobject_cast<QMdiSubWindow*>(widget))
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qobject_cast<QAbstractButton*>(widget) && (qobject_cast<QTabBar*>(widget->parent()) || qobject_cast<QToolBox*>(widget->parent())))
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qobject_cast<QMenuBar*>(widget))
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qobject_cast<QToolBar*>(widget))
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qobject_cast<QScrollBar*>(widget)) {
+ // A scroll bar is an interactor on a QAbstractScrollArea only.
+ if (const QWidget *parent = widget->parentWidget()) {
+ const QString objectName = parent->objectName();
+ static const QString scrollAreaVContainer = QLatin1String("qt_scrollarea_vcontainer");
+ void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow);
+ void formWindowAdded(QDesignerFormWindowInterface *formWindow);
+ static const QString scrollAreaHContainer = QLatin1String("qt_scrollarea_hcontainer");
+ if (objectName == scrollAreaVContainer || objectName == scrollAreaHContainer) {
+ m_lastWasAPassiveInteractor = true;
+ return m_lastWasAPassiveInteractor;
+ }
+ }
+ } else if (qstrcmp(widget->metaObject()->className(), "QDockWidgetTitle") == 0)
+ return (m_lastWasAPassiveInteractor = true);
+ else if (qstrcmp(widget->metaObject()->className(), "QWorkspaceTitleBar") == 0)
+ return (m_lastWasAPassiveInteractor = true);
+ else if (widget->objectName().startsWith(qtPassive))
+ return (m_lastWasAPassiveInteractor = true);
+ return m_lastWasAPassiveInteractor;
+}
+
+void WidgetFactory::formWindowAdded(QDesignerFormWindowInterface *formWindow)
+{
+ setFormWindowStyle(formWindow);
+}
+
+void WidgetFactory::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow)
+{
+ setFormWindowStyle(formWindow);
+}
+
+void WidgetFactory::setFormWindowStyle(QDesignerFormWindowInterface *formWindow)
+{
+ if (FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow))
+ setStyleName(fwb->styleName());
+}
+
+bool WidgetFactory::isFormEditorObject(const QObject *object)
+{
+ return object->property(formEditorDynamicProperty).isValid();
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#include "widgetfactory.moc"
diff --git a/tools/designer/src/lib/shared/widgetfactory_p.h b/tools/designer/src/lib/shared/widgetfactory_p.h
new file mode 100644
index 0000000..1a053ed
--- /dev/null
+++ b/tools/designer/src/lib/shared/widgetfactory_p.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** 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 WIDGETFACTORY_H
+#define WIDGETFACTORY_H
+
+#include "shared_global_p.h"
+#include "pluginmanager_p.h"
+
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+
+#include <QtCore/QMap>
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QWidget;
+class QLayout;
+class QDesignerFormEditorInterface;
+class QDesignerCustomWidgetInterface;
+class QDesignerFormWindowInterface;
+class QStyle;
+
+namespace qdesigner_internal {
+
+class QDESIGNER_SHARED_EXPORT WidgetFactory: public QDesignerWidgetFactoryInterface
+{
+ Q_OBJECT
+public:
+ explicit WidgetFactory(QDesignerFormEditorInterface *core, QObject *parent = 0);
+ ~WidgetFactory();
+
+ virtual QWidget* containerOfWidget(QWidget *widget) const;
+ virtual QWidget* widgetOfContainer(QWidget *widget) const;
+
+ QObject* createObject(const QString &className, QObject* parent) const;
+
+ virtual QWidget *createWidget(const QString &className, QWidget *parentWidget) const;
+ virtual QLayout *createLayout(QWidget *widget, QLayout *layout, int type) const;
+
+ virtual bool isPassiveInteractor(QWidget *widget);
+ virtual void initialize(QObject *object) const;
+ void initializeCommon(QWidget *object) const;
+ void initializePreview(QWidget *object) const;
+
+
+ virtual QDesignerFormEditorInterface *core() const;
+
+ static QString classNameOf(QDesignerFormEditorInterface *core, const QObject* o);
+
+ QDesignerFormWindowInterface *currentFormWindow(QDesignerFormWindowInterface *fw);
+
+ static QLayout *createUnmanagedLayout(QWidget *parentWidget, int type);
+
+ // The widget factory maintains a cache of styles which it owns.
+ QString styleName() const;
+ void setStyleName(const QString &styleName);
+
+ /* Return a cached style matching the name or QApplication's style if
+ * it is the default. */
+ QStyle *getStyle(const QString &styleName);
+ // Return the current style used by the factory. This either a cached one
+ // or QApplication's style */
+ QStyle *style() const;
+
+ // Apply one of the cached styles or QApplication's style to a toplevel widget.
+ void applyStyleTopLevel(const QString &styleName, QWidget *w);
+ static void applyStyleToTopLevel(QStyle *style, QWidget *widget);
+
+ // Return whether object was created by the factory for the form editor.
+ static bool isFormEditorObject(const QObject *o);
+
+ // Boolean dynamic property to set on widgets to prevent custom
+ // styles from interfering
+ static const char *disableStyleCustomPaintingPropertyC;
+
+public slots:
+ void loadPlugins();
+
+private slots:
+ void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow);
+ void formWindowAdded(QDesignerFormWindowInterface *formWindow);
+
+private:
+ struct Strings { // Reduce string allocations by storing predefined strings
+ Strings();
+ const QString m_alignment;
+ const QString m_bottomMargin;
+ const QString m_geometry;
+ const QString m_leftMargin;
+ const QString m_line;
+ const QString m_objectName;
+ const QString m_spacerName;
+ const QString m_orientation;
+ const QString m_q3WidgetStack;
+ const QString m_qAction;
+ const QString m_qButtonGroup;
+ const QString m_qAxWidget;
+ const QString m_qDialog;
+ const QString m_qDockWidget;
+ const QString m_qLayoutWidget;
+ const QString m_qMenu;
+ const QString m_qMenuBar;
+ const QString m_qWidget;
+ const QString m_rightMargin;
+ const QString m_sizeHint;
+ const QString m_spacer;
+ const QString m_text;
+ const QString m_title;
+ const QString m_topMargin;
+ const QString m_windowIcon;
+ const QString m_windowTitle;
+ };
+
+ QWidget* createCustomWidget(const QString &className, QWidget *parentWidget, bool *creationError) const;
+ QDesignerFormWindowInterface *findFormWindow(QWidget *parentWidget) const;
+ void setFormWindowStyle(QDesignerFormWindowInterface *formWindow);
+
+ const Strings m_strings;
+ QDesignerFormEditorInterface *m_core;
+ typedef QMap<QString, QDesignerCustomWidgetInterface*> CustomWidgetFactoryMap;
+ CustomWidgetFactoryMap m_customFactory;
+ QDesignerFormWindowInterface *m_formWindow;
+
+ // Points to the cached style or 0 if the default (qApp) is active
+ QStyle *m_currentStyle;
+ typedef QHash<QString, QStyle *> StyleCache;
+ StyleCache m_styleCache;
+
+ static QPointer<QWidget> *m_lastPassiveInteractor;
+ static bool m_lastWasAPassiveInteractor;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif // WIDGETFACTORY_H
diff --git a/tools/designer/src/lib/shared/zoomwidget.cpp b/tools/designer/src/lib/shared/zoomwidget.cpp
new file mode 100644
index 0000000..f4ab48e
--- /dev/null
+++ b/tools/designer/src/lib/shared/zoomwidget.cpp
@@ -0,0 +1,578 @@
+/****************************************************************************
+**
+** 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 "zoomwidget_p.h"
+
+#include <QtGui/QGraphicsScene>
+#include <QtGui/QGraphicsProxyWidget>
+#include <QtGui/QMenu>
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#include <QtGui/QContextMenuEvent>
+#include <QtGui/QScrollBar>
+
+#include <QtCore/QTextStream>
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+typedef QList<QAction*> ActionList;
+typedef QList<QGraphicsItem *> GraphicsItemList;
+
+enum { debugZoomWidget = 0 };
+
+static const int menuZoomList[] = { 100, 25, 50, 75, 125, 150 , 175, 200 };
+
+static inline QSize qCeiling(const QSizeF &s)
+{
+ return QSize(qCeil(s.width()), qCeil(s.height()));
+}
+
+namespace qdesigner_internal {
+
+// ---------- ZoomMenu
+
+ZoomMenu::ZoomMenu(QObject *parent) :
+ QObject(parent),
+ m_menuActions(new QActionGroup(this))
+{
+ connect(m_menuActions, SIGNAL(triggered(QAction*)), this, SLOT(slotZoomMenu(QAction*)));
+ const int nz = sizeof(menuZoomList)/sizeof(int);
+ for (int i = 0; i < nz; i++) {
+ const int zoom = menuZoomList[i];
+ //: Zoom factor
+ QAction *a = m_menuActions->addAction(tr("%1 %").arg(zoom));
+ a->setCheckable(true);
+ a->setData(QVariant(zoom));
+ if (zoom == 100)
+ a->setChecked(true);
+ m_menuActions->addAction(a);
+ }
+}
+
+int ZoomMenu::zoomOf(const QAction *a)
+{
+ return a->data().toInt();
+}
+
+void ZoomMenu::addActions(QMenu *m)
+{
+ const ActionList za = m_menuActions->actions();
+ const ActionList::const_iterator cend = za.constEnd();
+ for (ActionList::const_iterator it = za.constBegin(); it != cend; ++it) {
+ m->addAction(*it);
+ if (zoomOf(*it) == 100)
+ m->addSeparator();
+ }
+}
+
+int ZoomMenu::zoom() const
+{
+ return m_menuActions->checkedAction()->data().toInt();
+}
+
+void ZoomMenu::setZoom(int percent)
+{
+ const ActionList za = m_menuActions->actions();
+ const ActionList::const_iterator cend = za.constEnd();
+ for (ActionList::const_iterator it = za.constBegin(); it != cend; ++it)
+ if (zoomOf(*it) == percent) {
+ (*it)->setChecked(true);
+ return;
+ }
+}
+
+void ZoomMenu::slotZoomMenu(QAction *a)
+{
+ emit zoomChanged(zoomOf(a));
+}
+
+QList<int> ZoomMenu::zoomValues()
+{
+ QList<int> rc;
+ const int nz = sizeof(menuZoomList)/sizeof(int);
+ for (int i = 0; i < nz; i++)
+ rc.push_back(menuZoomList[i]);
+ return rc;
+}
+
+// --------- ZoomView
+ZoomView::ZoomView(QWidget *parent) :
+ QGraphicsView(parent),
+ m_scene(new QGraphicsScene(this)),
+ m_zoom(100),
+ m_zoomFactor(1.0),
+ m_zoomContextMenuEnabled(false),
+ m_autoScrollSuppressed(true),
+ m_zoomMenu(0)
+{
+ setFrameShape(QFrame::NoFrame);
+ setScene(m_scene);
+ if (debugZoomWidget)
+ qDebug() << "scene" << m_scene->sceneRect();
+
+}
+
+int ZoomView::zoom() const
+{
+ return m_zoom;
+}
+
+void ZoomView::scrollToOrigin()
+{
+ const QPoint origin(0 ,0);
+ const QPoint current = scrollPosition();
+ if (current != origin) {
+ if (debugZoomWidget)
+ qDebug() << "ZoomView::scrollToOrigin from " << current;
+ setScrollPosition(origin);
+ }
+}
+
+void ZoomView::setZoom(int percent)
+{
+ if (debugZoomWidget)
+ qDebug() << "ZoomView::setZoom" << percent;
+
+ if (m_zoom == percent)
+ return;
+
+ m_zoom = percent;
+ const qreal hundred = 100.0;
+ m_zoomFactor = static_cast<qreal>(m_zoom) / hundred;
+
+ applyZoom();
+ if (m_zoomMenu) // Do not force them into existence
+ m_zoomMenu->setZoom(m_zoom);
+
+ resetTransform();
+ scale(m_zoomFactor, m_zoomFactor);
+ if (m_autoScrollSuppressed)
+ scrollToOrigin();
+}
+
+void ZoomView::applyZoom()
+{
+}
+
+qreal ZoomView::zoomFactor() const
+{
+ return m_zoomFactor;
+}
+
+bool ZoomView::isZoomContextMenuEnabled() const
+{
+ return m_zoomContextMenuEnabled;
+}
+
+void ZoomView::setZoomContextMenuEnabled(bool e)
+{
+ m_zoomContextMenuEnabled = e;
+}
+
+bool ZoomView::isAutoScrollSuppressed() const
+{
+ return m_autoScrollSuppressed;
+}
+
+void ZoomView::setAutoScrollSuppressed(bool s)
+{
+ m_autoScrollSuppressed = s;
+}
+
+ZoomMenu *ZoomView::zoomMenu()
+{
+ if (!m_zoomMenu) {
+ m_zoomMenu = new ZoomMenu(this);
+ m_zoomMenu->setZoom(m_zoom);
+ connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SLOT(setZoom(int)));
+ }
+ return m_zoomMenu;
+}
+
+void ZoomView::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (debugZoomWidget > 1)
+ qDebug() << "ZoomView::contextMenuEvent" << event->pos() << event->globalPos() << zoom() << '%';
+
+ if (m_zoomContextMenuEnabled) {
+ showContextMenu(event->globalPos());
+ } else {
+ QGraphicsView::contextMenuEvent(event);
+ }
+}
+
+void ZoomView::showContextMenu(const QPoint &globalPos)
+{
+ QMenu menu;
+ zoomMenu()->addActions(&menu);
+ if (debugZoomWidget) {
+ menu.addSeparator();
+ QAction *da = menu.addAction(QLatin1String("Dump"));
+ connect(da, SIGNAL(triggered()), this, SLOT(dump()));
+ }
+ menu.exec(globalPos);
+}
+
+QPoint ZoomView::scrollPosition() const
+{
+ return QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
+}
+
+void ZoomView::setScrollPosition(const QPoint& pos)
+{
+ horizontalScrollBar()->setValue(pos.x());
+ verticalScrollBar()->setValue(pos.y());
+}
+
+// -------------- ZoomProxyWidget
+ZoomProxyWidget::ZoomProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) :
+ QGraphicsProxyWidget(parent, wFlags)
+{
+}
+
+QVariant ZoomProxyWidget::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ switch (change) {
+ case ItemPositionChange: {
+ const QPointF newPos = value.toPointF();
+ const QPointF desiredPos = QPointF(0, 0);
+ if (newPos != desiredPos && debugZoomWidget)
+ qDebug() << "ZoomProxyWidget::itemChange: refusing " << newPos;
+ return desiredPos;
+ }
+ default:
+ break;
+ }
+ return QGraphicsProxyWidget::itemChange(change, value);
+}
+
+/* ZoomedEventFilterRedirector: Event filter for the zoomed widget.
+ * It redirects the events to another handler of ZoomWidget as its
+ * base class QScrollArea also implements eventFilter() for its viewport. */
+
+static const char *zoomedEventFilterRedirectorNameC = "__qt_ZoomedEventFilterRedirector";
+
+class ZoomedEventFilterRedirector : public QObject {
+ Q_DISABLE_COPY(ZoomedEventFilterRedirector)
+
+public:
+ explicit ZoomedEventFilterRedirector(ZoomWidget *zw, QObject *parent);
+ virtual bool eventFilter(QObject *watched, QEvent *event);
+
+private:
+ ZoomWidget *m_zw;
+};
+
+ZoomedEventFilterRedirector::ZoomedEventFilterRedirector(ZoomWidget *zw, QObject *parent) :
+ QObject(parent),
+ m_zw(zw)
+{
+ setObjectName(QLatin1String(zoomedEventFilterRedirectorNameC));
+}
+
+bool ZoomedEventFilterRedirector::eventFilter(QObject *watched, QEvent *event)
+{
+ return m_zw->zoomedEventFilter(watched, event);
+}
+
+
+// --------- ZoomWidget
+
+ZoomWidget::ZoomWidget(QWidget *parent) :
+ ZoomView(parent),
+ m_proxy(0),
+ m_viewResizeBlocked(false),
+ m_widgetResizeBlocked(false),
+ m_widgetZoomContextMenuEnabled(false)
+{
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+void ZoomWidget::setWidget(QWidget *w, Qt::WindowFlags wFlags)
+{
+ if (debugZoomWidget)
+ qDebug() << "ZoomWidget::setWidget" << w << bin << wFlags;
+
+ if (m_proxy) {
+ scene().removeItem(m_proxy);
+ if (QWidget *w = m_proxy->widget()) {
+ // remove the event filter
+ if (QObject *evf = qFindChild<QObject*>(w, QLatin1String(zoomedEventFilterRedirectorNameC)))
+ w->removeEventFilter(evf);
+ }
+ m_proxy->deleteLater();
+ }
+ // Set window flags on the outer proxy for them to take effect
+ m_proxy = createProxyWidget(0, Qt::Window);
+ m_proxy->setWidget(w);
+
+ m_proxy->setWindowFlags(wFlags);
+ scene().addItem(m_proxy);
+ w->installEventFilter(new ZoomedEventFilterRedirector(this, w));
+ resizeToWidgetSize(); // Do manually for new widget
+ m_proxy->show();
+}
+
+bool ZoomWidget::isWidgetZoomContextMenuEnabled() const
+{
+ return m_widgetZoomContextMenuEnabled;
+}
+void ZoomWidget::setWidgetZoomContextMenuEnabled(bool e)
+{
+ m_widgetZoomContextMenuEnabled = e;
+}
+
+QSize ZoomWidget::viewPortMargin() const
+{
+ return QSize(0, 0);
+}
+
+QSizeF ZoomWidget::widgetDecorationSizeF() const
+{
+ qreal left, top, right, bottom;
+ m_proxy->getWindowFrameMargins (&left, &top, &right, &bottom);
+ const QSizeF rc = QSizeF(left + right, top + bottom);
+ return rc;
+}
+
+QSize ZoomWidget::widgetSize() const
+{
+ if (m_proxy)
+ return m_proxy->widget()->size();
+ return QSize(0, 0);
+}
+
+/* Convert widget size to QGraphicsView size.
+ * Watch out for limits (0, QWIDGETSIZE_MAX); just pass them on */
+
+QSize ZoomWidget::widgetSizeToViewSize(const QSize &s, bool *ptrToValid) const
+{
+ const QSize vpMargin = viewPortMargin();
+ const QSizeF deco = widgetDecorationSizeF();
+ const int width = s.width();
+
+ QSize rc = s;
+ bool valid = false;
+ if (width != 0 && width != QWIDGETSIZE_MAX) {
+ valid = true;
+ rc.setWidth(vpMargin.width() + qCeil(deco.width() + zoomFactor() * static_cast<qreal>(width)));
+ }
+
+ const int height = s.height();
+ if (height != 0 && height != QWIDGETSIZE_MAX) {
+ valid = true;
+ rc.setHeight(vpMargin.height() + qCeil(deco.height() + zoomFactor() * static_cast<qreal>(height)));
+ }
+
+ if (ptrToValid)
+ *ptrToValid = valid;
+
+ return rc;
+}
+
+// On changing zoom: Make QGraphicsView big enough to hold the widget
+void ZoomWidget::resizeToWidgetSize()
+{
+ if (!m_proxy)
+ return;
+
+ m_viewResizeBlocked = true;
+ // Convert size, apply transformed min/max size if applicable
+ const QSize wsize = widgetSize();
+ const QSize viewSize = widgetSizeToViewSize(wsize);
+
+ bool hasMinimumSize = false;
+ const QSize minimumSize = m_proxy->widget()->minimumSize();
+ const QSize viewMinimumSize = widgetSizeToViewSize(minimumSize, &hasMinimumSize);
+
+ bool hasMaximumSize = false;
+ const QSize maximumSize = m_proxy->widget()->maximumSize();
+ const QSize viewMaximumSize = widgetSizeToViewSize(maximumSize, &hasMaximumSize);
+
+ if (debugZoomWidget) {
+ qDebug()
+ << "ZoomWidget::resizeToWidgetSize()\n"
+ << "Widget: " << wsize << "(scaled)" << (wsize * zoomFactor()) << " Min/Max" << minimumSize << maximumSize << '\n'
+ << " View: " << viewSize << hasMinimumSize << viewMinimumSize << hasMaximumSize << viewMaximumSize;
+ }
+ // Apply
+ if (hasMinimumSize)
+ setMinimumSize(viewMinimumSize);
+ if (hasMaximumSize)
+ setMaximumSize(viewMaximumSize);
+ // now resize
+ doResize(viewSize);
+ if (debugZoomWidget)
+ qDebug() << "ZoomWidget::resizeToWidgetSize(): resulting view size" << size();
+ m_viewResizeBlocked = false;
+}
+
+void ZoomWidget::applyZoom()
+{
+ resizeToWidgetSize();
+}
+
+/* virtual */ void ZoomWidget::doResize(const QSize &s)
+{
+ if (debugZoomWidget > 1)
+ qDebug() << ">ZoomWidget::doResize() " << s;
+ resize(s);
+}
+
+void ZoomWidget::resizeEvent(QResizeEvent *event)
+{
+ /* QGraphicsView Resized from outside: Adapt widget. For some reason,
+ * the size passed in the event is not to be trusted. This might be due
+ * to some QScrollArea event fiddling. Have QScrollArea resize first
+ * and the use the size ZoomView::resizeEvent(event); */
+ if (m_proxy && !m_viewResizeBlocked) {
+ if (debugZoomWidget > 1)
+ qDebug() << ">ZoomWidget (" << size() << ")::resizeEvent from " << event->oldSize() << " to " << event->size();
+ const QSizeF newViewPortSize = size() - viewPortMargin();
+ const QSizeF widgetSizeF = newViewPortSize / zoomFactor() - widgetDecorationSizeF();
+ m_widgetResizeBlocked = true;
+ m_proxy->widget()->resize(widgetSizeF.toSize());
+ scrollToOrigin();
+ m_widgetResizeBlocked = false;
+ }
+}
+
+QSize ZoomWidget::minimumSizeHint() const
+{
+ if (!m_proxy)
+ return QGraphicsView::minimumSizeHint();
+
+ const QSizeF wmsh = m_proxy->widget()->minimumSizeHint();
+ const QSize rc = viewPortMargin() + (wmsh * zoomFactor()).toSize();
+ if (debugZoomWidget > 1)
+ qDebug() << "minimumSizeHint()" << rc;
+ return rc;
+}
+
+QSize ZoomWidget::sizeHint() const
+{
+ if (!m_proxy)
+ return QGraphicsView::sizeHint();
+
+ const QSizeF wsh = m_proxy->widget()->sizeHint();
+ const QSize rc = viewPortMargin() + (wsh * zoomFactor()).toSize();
+ if (debugZoomWidget > 1)
+ qDebug() << "sizeHint()" << rc;
+ return rc;
+}
+
+bool ZoomWidget::zoomedEventFilter(QObject * /*watched*/, QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ if (debugZoomWidget) { // Debug helper: Press 'D' on the zoomed widget
+ const QKeyEvent *kevent = static_cast<QKeyEvent*>(event);
+ if (kevent->key() == Qt::Key_D)
+ dump();
+ }
+ break;
+ case QEvent::Resize:
+ if (debugZoomWidget > 1) {
+ const QResizeEvent *re = static_cast<const QResizeEvent *>(event);
+ qDebug() << "ZoomWidget::zoomedEventFilter" << re->oldSize() << re->size() << " at " << m_proxy->widget()->geometry();
+ }
+ if (!m_widgetResizeBlocked)
+ resizeToWidgetSize();
+
+ break;
+ case QEvent::ContextMenu:
+ if (m_widgetZoomContextMenuEnabled) {
+ // Calculate global position from scaled
+ QContextMenuEvent *ce = static_cast<QContextMenuEvent*>(event);
+ const QPointF origin = mapToGlobal(QPoint(0, 0)) - scrollPosition();
+ const QPointF pos = QPointF(origin + (QPointF(ce->pos()) * zoomFactor()));
+ showContextMenu(pos.toPoint());
+ ce->accept();
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void ZoomWidget::setItemAcceptDrops(bool)
+{
+ if (m_proxy)
+ m_proxy->setAcceptDrops(true);
+}
+
+bool ZoomWidget::itemAcceptDrops() const
+{
+ return m_proxy ? m_proxy->acceptDrops() : false;
+}
+
+ // Factory function for QGraphicsProxyWidgets which can be overwritten. Default creates a ZoomProxyWidget
+QGraphicsProxyWidget *ZoomWidget::createProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) const
+{
+ return new ZoomProxyWidget(parent, wFlags);
+}
+
+void ZoomWidget::dump() const
+{
+
+ qDebug() << "ZoomWidget " << geometry() << " Viewport " << viewport()->geometry()
+ << "Scroll: " << scrollPosition() << "Matrix: " << matrix() << " SceneRect: " << sceneRect();
+ if (m_proxy) {
+ qDebug() << "Proxy Pos: " << m_proxy->pos() << "Proxy " << m_proxy->size()
+ << "\nProxy size hint"
+ << m_proxy->effectiveSizeHint(Qt::MinimumSize)
+ << m_proxy->effectiveSizeHint(Qt::PreferredSize)
+ << m_proxy->effectiveSizeHint(Qt::MaximumSize)
+ << "\nMatrix: " << m_proxy->matrix()
+ << "\nWidget: " << m_proxy->widget()->geometry()
+ << "scaled" << (zoomFactor() * m_proxy->widget()->size());
+ }
+}
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
diff --git a/tools/designer/src/lib/shared/zoomwidget_p.h b/tools/designer/src/lib/shared/zoomwidget_p.h
new file mode 100644
index 0000000..fe850f7
--- /dev/null
+++ b/tools/designer/src/lib/shared/zoomwidget_p.h
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** 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 ZOOMWIDGET_H
+#define ZOOMWIDGET_H
+
+#include "shared_global_p.h"
+
+#include <QtGui/QGraphicsView>
+#include <QtGui/QGraphicsProxyWidget>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsScene;
+class QMenu;
+class QAction;
+class QActionGroup;
+
+namespace qdesigner_internal {
+
+// A checkable zoom menu action group. Operates in percent.
+
+class QDESIGNER_SHARED_EXPORT ZoomMenu : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(ZoomMenu)
+
+public:
+ ZoomMenu(QObject *parent = 0);
+ void addActions(QMenu *m);
+
+ int zoom() const;
+
+ // Return a list of available zoom values.
+ static QList<int> zoomValues();
+
+public slots:
+ void setZoom(int percent);
+
+signals:
+ void zoomChanged(int);
+
+private slots:
+ void slotZoomMenu(QAction *);
+
+private:
+ static int zoomOf(const QAction *a);
+
+ QActionGroup *m_menuActions;
+};
+
+/* Zoom view: A QGraphicsView with a zoom menu */
+
+class QDESIGNER_SHARED_EXPORT ZoomView : public QGraphicsView
+{
+ Q_PROPERTY(int zoom READ zoom WRITE setZoom DESIGNABLE true SCRIPTABLE true)
+ Q_PROPERTY(bool zoomContextMenuEnabled READ isZoomContextMenuEnabled WRITE setZoomContextMenuEnabled DESIGNABLE true SCRIPTABLE true)
+ Q_PROPERTY(bool autoScrollSuppressed READ isAutoScrollSuppressed WRITE setAutoScrollSuppressed DESIGNABLE true SCRIPTABLE true)
+
+ Q_OBJECT
+ Q_DISABLE_COPY(ZoomView)
+public:
+ ZoomView(QWidget *parent = 0);
+
+ /* Zoom in percent (for easily implementing menus) and qreal zoomFactor
+ * in sync */
+ int zoom() const; // in percent
+ qreal zoomFactor() const;
+
+ // Zoom Menu on QGraphicsView.
+ bool isZoomContextMenuEnabled() const;
+ void setZoomContextMenuEnabled(bool e);
+
+ // Suppress scrolling when changing zoom. Default: on
+ bool isAutoScrollSuppressed() const;
+ void setAutoScrollSuppressed(bool s);
+
+ QGraphicsScene &scene() { return *m_scene; }
+ const QGraphicsScene &scene() const { return *m_scene; }
+
+ // Helpers for menu
+ ZoomMenu *zoomMenu();
+
+ QPoint scrollPosition() const;
+ void setScrollPosition(const QPoint& pos);
+ void scrollToOrigin();
+
+public slots:
+ void setZoom(int percent);
+ void showContextMenu(const QPoint &globalPos);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *event);
+
+ // Overwrite for implementing additional behaviour when doing setZoom();
+ virtual void applyZoom();
+
+private:
+ QGraphicsScene *m_scene;
+ int m_zoom;
+ qreal m_zoomFactor;
+
+ bool m_zoomContextMenuEnabled;
+ bool m_autoScrollSuppressed;
+ bool m_resizeBlocked;
+ ZoomMenu *m_zoomMenu;
+};
+
+/* The proxy widget used in ZoomWidget. It refuses to move away from 0,0,
+ * This behaviour is required for Windows only. */
+
+class QDESIGNER_SHARED_EXPORT ZoomProxyWidget : public QGraphicsProxyWidget {
+ Q_DISABLE_COPY(ZoomProxyWidget)
+public:
+ explicit ZoomProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+
+protected:
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+};
+
+/* Zoom widget: A QGraphicsView-based container for a widget that allows for
+ * zooming it. Communicates changes in size in the following ways:
+ * 1) Embedded widget wants to resize: Listen for its resize in event filter
+ * and resize
+ * 2) Zoom is changed: resize to fully display the embedded widget
+ * 3) Outer widget changes (by manually resizing the window:
+ * Pass the scaled change on to the embedded widget.
+ * Provides helper functions for a zoom context menu on the widget. */
+
+class QDESIGNER_SHARED_EXPORT ZoomWidget : public ZoomView
+{
+ Q_PROPERTY(bool widgetZoomContextMenuEnabled READ isWidgetZoomContextMenuEnabled WRITE setWidgetZoomContextMenuEnabled DESIGNABLE true SCRIPTABLE true)
+ Q_PROPERTY(bool itemAcceptDrops READ itemAcceptDrops WRITE setItemAcceptDrops DESIGNABLE true SCRIPTABLE true)
+ Q_OBJECT
+ Q_DISABLE_COPY(ZoomWidget)
+
+public:
+ ZoomWidget(QWidget *parent = 0);
+ void setWidget(QWidget *w, Qt::WindowFlags wFlags = 0);
+
+ const QGraphicsProxyWidget *proxy() const { return m_proxy; }
+ QGraphicsProxyWidget *proxy() { return m_proxy; }
+
+ /* Enable the zoom Menu on the Widget (as opposed ZoomView's menu which
+ * is on the canvas). */
+ bool isWidgetZoomContextMenuEnabled() const;
+ void setWidgetZoomContextMenuEnabled(bool e);
+
+ void setItemAcceptDrops(bool);
+ bool itemAcceptDrops() const;
+
+ virtual QSize minimumSizeHint() const;
+ virtual QSize sizeHint() const;
+
+ bool zoomedEventFilter(QObject *watched, QEvent *event);
+
+public slots:
+ // debug state
+ void dump() const;
+
+protected:
+ void resizeEvent(QResizeEvent * event);
+
+ // Overwritten from ZoomView
+ virtual void applyZoom();
+ // Overwrite to actually perform a resize. This is required if we are in a layout. Default does resize().
+ virtual void doResize(const QSize &s);
+
+private:
+ // Factory function for QGraphicsProxyWidgets which can be overwritten. Default creates a ZoomProxyWidget
+ virtual QGraphicsProxyWidget *createProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0) const;
+ QSize widgetSizeToViewSize(const QSize &s, bool *ptrToValid = 0) const;
+
+ void resizeToWidgetSize();
+ QSize viewPortMargin() const;
+ QSize widgetSize() const;
+ QSizeF widgetDecorationSizeF() const;
+
+ QGraphicsProxyWidget *m_proxy;
+ bool m_viewResizeBlocked;
+ bool m_widgetResizeBlocked;
+ bool m_widgetZoomContextMenuEnabled;
+};
+
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE
+
+#endif