diff options
Diffstat (limited to 'tools/designer/src/components/widgetbox')
12 files changed, 3385 insertions, 0 deletions
diff --git a/tools/designer/src/components/widgetbox/widgetbox.cpp b/tools/designer/src/components/widgetbox/widgetbox.cpp new file mode 100644 index 0000000..d8c6aa3 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox.h" +#include "widgetboxtreewidget.h" +#include "widgetbox_dnditem.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <iconloader_p.h> +#include <qdesigner_utils_p.h> +#include <filterwidget_p.h> + +#include <QtGui/QDropEvent> +#include <QtGui/QVBoxLayout> +#include <QtGui/QApplication> +#include <QtGui/QToolBar> +#include <QtGui/QIcon> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +WidgetBox::WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) + : QDesignerWidgetBox(parent, flags), + m_core(core), + m_view(new WidgetBoxTreeWidget(m_core)) +{ + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + // Prevent the filter from grabbing focus since Our view has Qt::NoFocus + FilterWidget *filterWidget = new FilterWidget(0, FilterWidget::LayoutAlignNone); + filterWidget->setRefuseFocus(true); + connect(filterWidget, SIGNAL(filterChanged(QString)), m_view, SLOT(filter(QString))); + l->addWidget(filterWidget); + + // View + connect(m_view, SIGNAL(pressed(QString,QString,QPoint)), + this, SLOT(handleMousePress(QString,QString,QPoint))); + l->addWidget(m_view); + + setAcceptDrops (true); +} + +WidgetBox::~WidgetBox() +{ +} + +QDesignerFormEditorInterface *WidgetBox::core() const +{ + return m_core; +} + +void WidgetBox::handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos) +{ + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + DomUI *ui = xmlToUi(name, xml, true); + if (ui == 0) + return; + QList<QDesignerDnDItemInterface*> item_list; + item_list.append(new WidgetBoxDnDItem(core(), ui, global_mouse_pos)); + m_core->formWindowManager()->dragItems(item_list); +} + +int WidgetBox::categoryCount() const +{ + return m_view->categoryCount(); +} + +QDesignerWidgetBoxInterface::Category WidgetBox::category(int cat_idx) const +{ + return m_view->category(cat_idx); +} + +void WidgetBox::addCategory(const Category &cat) +{ + m_view->addCategory(cat); +} + +void WidgetBox::removeCategory(int cat_idx) +{ + m_view->removeCategory(cat_idx); +} + +int WidgetBox::widgetCount(int cat_idx) const +{ + return m_view->widgetCount(cat_idx); +} + +QDesignerWidgetBoxInterface::Widget WidgetBox::widget(int cat_idx, int wgt_idx) const +{ + return m_view->widget(cat_idx, wgt_idx); +} + +void WidgetBox::addWidget(int cat_idx, const Widget &wgt) +{ + m_view->addWidget(cat_idx, wgt); +} + +void WidgetBox::removeWidget(int cat_idx, int wgt_idx) +{ + m_view->removeWidget(cat_idx, wgt_idx); +} + +void WidgetBox::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, const QPoint&) +{ + m_view->dropWidgets(item_list); +} + +void WidgetBox::setFileName(const QString &file_name) +{ + m_view->setFileName(file_name); +} + +QString WidgetBox::fileName() const +{ + return m_view->fileName(); +} + +bool WidgetBox::load() +{ + return m_view->load(loadMode()); +} + +bool WidgetBox::loadContents(const QString &contents) +{ + return m_view->loadContents(contents); +} + +bool WidgetBox::save() +{ + return m_view->save(); +} + +static const QDesignerMimeData *checkDragEvent(QDropEvent * event, + bool acceptEventsFromWidgetBox) +{ + const QDesignerMimeData *mimeData = qobject_cast<const QDesignerMimeData *>(event->mimeData()); + if (!mimeData) { + event->ignore(); + return 0; + } + // If desired, ignore a widget box drag and drop, where widget==0. + if (!acceptEventsFromWidgetBox) { + const bool fromWidgetBox = !mimeData->items().first()->widget(); + if (fromWidgetBox) { + event->ignore(); + return 0; + } + } + + mimeData->acceptEvent(event); + return mimeData; +} + +void WidgetBox::dragEnterEvent (QDragEnterEvent * event) +{ + // We accept event originating from the widget box also here, + // because otherwise Windows will not show the DnD pixmap. + checkDragEvent(event, true); +} + +void WidgetBox::dragMoveEvent(QDragMoveEvent * event) +{ + checkDragEvent(event, true); +} + +void WidgetBox::dropEvent(QDropEvent * event) +{ + const QDesignerMimeData *mimeData = checkDragEvent(event, false); + if (!mimeData) + return; + + dropWidgets(mimeData->items(), event->pos()); + QDesignerMimeData::removeMovedWidgetsFromSourceForm(mimeData->items()); +} + +QIcon WidgetBox::iconForWidget(const QString &className, const QString &category) const +{ + Widget widgetData; + if (!findWidget(this, className, category, &widgetData)) + return QIcon(); + return m_view->iconForWidget(widgetData.iconName()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetbox.h b/tools/designer/src/components/widgetbox/widgetbox.h new file mode 100644 index 0000000..e77c0ed --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_H +#define WIDGETBOX_H + +#include "widgetbox_global.h" +#include <qdesigner_widgetbox_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class WidgetBoxTreeWidget; + +class QT_WIDGETBOX_EXPORT WidgetBox : public QDesignerWidgetBox +{ + Q_OBJECT +public: + explicit WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~WidgetBox(); + + QDesignerFormEditorInterface *core() const; + + virtual int categoryCount() const; + virtual Category category(int cat_idx) const; + virtual void addCategory(const Category &cat); + virtual void removeCategory(int cat_idx); + + virtual int widgetCount(int cat_idx) const; + virtual Widget widget(int cat_idx, int wgt_idx) const; + virtual void addWidget(int cat_idx, const Widget &wgt); + virtual void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list, const QPoint &global_mouse_pos); + + virtual void setFileName(const QString &file_name); + virtual QString fileName() const; + virtual bool load(); + virtual bool save(); + + virtual bool loadContents(const QString &contents); + virtual QIcon iconForWidget(const QString &className, const QString &category = QString()) const; + +protected: + virtual void dragEnterEvent (QDragEnterEvent * event); + virtual void dragMoveEvent(QDragMoveEvent * event); + virtual void dropEvent (QDropEvent * event); + +private slots: + void handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos); + +private: + QDesignerFormEditorInterface *m_core; + WidgetBoxTreeWidget *m_view; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_H diff --git a/tools/designer/src/components/widgetbox/widgetbox.pri b/tools/designer/src/components/widgetbox/widgetbox.pri new file mode 100644 index 0000000..dd8ad00 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.pri @@ -0,0 +1,14 @@ + +INCLUDEPATH += $$PWD + +SOURCES += $$PWD/widgetboxcategorylistview.cpp \ + $$PWD/widgetboxtreewidget.cpp \ + $$PWD/widgetbox.cpp \ + $$PWD/widgetbox_dnditem.cpp +HEADERS += $$PWD/widgetboxcategorylistview.h \ + $$PWD/widgetboxtreewidget.h \ + $$PWD/widgetbox.h \ + $$PWD/widgetbox_global.h \ + $$PWD/widgetbox_dnditem.h + +RESOURCES += $$PWD/widgetbox.qrc diff --git a/tools/designer/src/components/widgetbox/widgetbox.qrc b/tools/designer/src/components/widgetbox/widgetbox.qrc new file mode 100644 index 0000000..7ecf78c --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/trolltech/widgetbox"> + <file>widgetbox.xml</file> + </qresource> +</RCC> diff --git a/tools/designer/src/components/widgetbox/widgetbox.xml b/tools/designer/src/components/widgetbox/widgetbox.xml new file mode 100644 index 0000000..462ac7d --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox.xml @@ -0,0 +1,932 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--************************************************************************ +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +**************************************************************************--> +<widgetbox version="4.2"> + <category name="Layouts"> + + <categoryentry name="Vertical Layout" icon="win/editvlayout.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">verticalLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Layout" icon="win/edithlayout.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">horizontalLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Grid Layout" icon="win/editgrid.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">gridLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Form Layout" icon="win/editform.png"> + <ui> + <widget class="QWidget"> + <property name="objectName"> + <string notr="true">formLayoutWidget</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>160</width> + <height>80</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> + </layout> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Spacers"> + + <categoryentry name="Horizontal Spacer" icon="widgets/spacer.png"> + <ui> + <widget class="Spacer"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="objectName"> + <string notr="true">horizontalSpacer</string> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Spacer" icon="widgets/vspacer.png"> + <ui> + <widget class="Spacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="objectName"> + <string notr="true">verticalSpacer</string> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Buttons"> + + <categoryentry name="Push Button" icon="widgets/pushbutton.png"> + <ui> + <widget class="QPushButton"> + <property name="text" > + <string>PushButton</string> + </property> + <property name="objectName"> + <string notr="true">pushButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tool Button" icon="widgets/toolbutton.png"> + <ui> + <widget class="QToolButton"> + <property name="objectName"> + <string notr="true">toolButton</string> + </property> + <property name="text" > + <string>...</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Radio Button" icon="widgets/radiobutton.png"> + <ui> + <widget class="QRadioButton"> + <property name="text" > + <string>RadioButton</string> + </property> + <property name="objectName"> + <string notr="true">radioButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Check Box" icon="widgets/checkbox.png"> + <ui> + <widget class="QCheckBox"> + <property name="text" > + <string>CheckBox</string> + </property> + <property name="objectName"> + <string notr="true">checkBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Command Link Button" icon="widgets/commandlinkbutton.png"> + <ui> + <widget class="QCommandLinkButton"> + <property name="text" > + <string>CommandLinkButton</string> + </property> + <property name="objectName"> + <string notr="true">commandLinkButton</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Button Box" icon="widgets/dialogbuttonbox.png"> + <ui> + <widget class="QDialogButtonBox"> + <property name="standardButtons" > + <set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set> + </property> + <property name="objectName"> + <string notr="true">buttonBox</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Item Views (Model-Based)"> + + <categoryentry name="List View" icon="widgets/listbox.png"> + <ui> + <widget class="QListView"> + <property name="objectName"> + <string notr="true">listView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tree View" icon="widgets/listview.png"> + <ui> + <widget class="QTreeView"> + <property name="objectName"> + <string notr="true">treeView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Table View" icon="widgets/table.png"> + <ui> + <widget class="QTableView"> + <property name="objectName"> + <string notr="true">tableView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Column View" icon="widgets/columnview.png"> + <ui> + <widget class="QColumnView"> + <property name="objectName"> + <string notr="true">columnView</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Item Widgets (Item-Based)"> + <categoryentry name="List Widget" icon="widgets/listbox.png"> + <ui> + <widget class="QListWidget"> + <property name="objectName"> + <string notr="true">listWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tree Widget" icon="widgets/listview.png"> + <ui> + <widget class="QTreeWidget"> + <property name="objectName"> + <string notr="true">treeWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Table Widget" icon="widgets/table.png"> + <ui> + <widget class="QTableWidget"> + <property name="objectName"> + <string notr="true">tableWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Containers"> + + <categoryentry name="Group Box" icon="widgets/groupbox.png"> + <ui> + <widget class="QGroupBox"> + <property name="title" > + <string>GroupBox</string> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">groupBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry icon="widgets/scrollarea.png" type="default" name="Scroll Area"> + <ui> + <widget class="QScrollArea"> + <property name="objectName" > + <string notr="true" >scrollArea</string> + </property> + <property name="widgetResizable" > + <bool>true</bool> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tool Box" icon="widgets/toolbox.png"> + <ui> + <widget class="QToolBox"> + <property name="currentIndex" > + <number>0</number> + </property> + <property name="objectName"> + <string notr="true">toolBox</string> + </property> + <widget class="QWidget" name="page" > + <attribute name="label"> + <string>Page 1</string> + </attribute> + </widget> + <widget class="QWidget" name="page" > + <attribute name="label"> + <string>Page 2</string> + </attribute> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Tab Widget" icon="widgets/tabwidget.png"> + <ui> + <widget class="QTabWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">tabWidget</string> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Tab 1</string> + </attribute> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Tab 2</string> + </attribute> + </widget> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Stacked Widget" icon="widgets/widgetstack.png"> + <ui> + <widget class="QStackedWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">stackedWidget</string> + </property> + <widget class="QWidget" name="page" /> + <widget class="QWidget" name="page" /> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Frame" icon="widgets/frame.png"> + <ui> + <widget class="QFrame"> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="objectName"> + <string notr="true">frame</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Widget" icon="widgets/widget.png"> + <ui> + <widget class="QWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">widget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="MdiArea" icon="widgets/mdiarea.png"> + <ui> + <widget class="QMdiArea"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>200</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">mdiArea</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Dock Widget" icon="widgets/dockwidget.png"> + <ui> + <widget class="QDockWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>120</width> + <height>80</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dockWidget</string> + </property> + <widget class="QWidget" name="dockWidgetContents" /> + </widget> + </ui> + </categoryentry> + + </category> + + <category name="Input Widgets"> + + <categoryentry name="Combo Box" icon="widgets/combobox.png"> + <ui> + <widget class="QComboBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>28</y> + <width>41</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">comboBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Font Combo Box" icon="widgets/fontcombobox.png"> + <ui> + <widget class="QFontComboBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>28</y> + <width>41</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">fontComboBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Line Edit" icon="widgets/lineedit.png"> + <ui> + <widget class="QLineEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>1</y> + <width>113</width> + <height>20</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">lineEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Text Edit" icon="widgets/textedit.png"> + <ui> + <widget class="QTextEdit"> + <property name="objectName"> + <string notr="true">textEdit</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>104</width> + <height>64</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Plain Text Edit" icon="widgets/plaintextedit.png"> + <ui> + <widget class="QPlainTextEdit"> + <property name="objectName"> + <string notr="true">plainTextEdit</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>104</width> + <height>64</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Spin Box" icon="widgets/spinbox.png"> + <ui> + <widget class="QSpinBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>0</y> + <width>42</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">spinBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Double Spin Box" icon="widgets/doublespinbox.png"> + <ui> + <widget class="QDoubleSpinBox"> + <property name="geometry" > + <rect> + <x>119</x> + <y>0</y> + <width>62</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">doubleSpinBox</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Time Edit" icon="widgets/timeedit.png"> + <ui> + <widget class="QTimeEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>28</y> + <width>118</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">timeEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Date Edit" icon="widgets/dateedit.png"> + <ui> + <widget class="QDateEdit"> + <property name="geometry" > + <rect> + <x>0</x> + <y>28</y> + <width>110</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dateEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Date/Time Edit" icon="widgets/datetimeedit.png"> + <ui> + <widget class="QDateTimeEdit"> + <property name="geometry"> + <rect> + <x>0</x> + <y>28</y> + <width>194</width> + <height>22</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dateTimeEdit</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Dial" icon="widgets/dial.png"> + <ui> + <widget class="QDial"> + <property name="geometry" > + <rect> + <x>110</x> + <y>0</y> + <width>50</width> + <height>64</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">dial</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Scroll Bar" icon="widgets/hscrollbar.png"> + <ui> + <widget class="QScrollBar"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>160</width> + <height>16</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">horizontalScrollBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Scroll Bar" icon="widgets/vscrollbar.png"> + <ui> + <widget class="QScrollBar"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>16</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">verticalScrollBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Slider" icon="widgets/hslider.png"> + <ui> + <widget class="QSlider"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>160</width> + <height>16</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">horizontalSlider</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Slider" icon="widgets/vslider.png"> + <ui> + <widget class="QSlider"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>126</y> + <width>16</width> + <height>160</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">verticalSlider</string> + </property> + </widget> + </ui> + </categoryentry> + + </category> + + + <category name="Display Widgets"> + + <categoryentry name="Label" icon="widgets/label.png"> + <ui> + <widget class="QLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + <property name="objectName"> + <string notr="true">label</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Text Browser" icon="widgets/textedit.png"> + <ui> + <widget class="QTextBrowser"> + <property name="objectName"> + <string notr="true">textBrowser</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Graphics View" icon="widgets/graphicsview.png"> + <ui> + <widget class="QGraphicsView"> + <property name="objectName"> + <string notr="true">graphicsView</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Calendar" icon="widgets/calendarwidget.png"> + <ui> + <widget class="QCalendarWidget"> + <property name="objectName"> + <string notr="true">calendarWidget</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="LCD Number" icon="widgets/lcdnumber.png"> + <ui> + <widget class="QLCDNumber"> + <property name="objectName"> + <string notr="true">lcdNumber</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Progress Bar" icon="widgets/progress.png"> + <ui> + <widget class="QProgressBar"> + <property name="value" > + <number>24</number> + </property> + <property name="geometry" > + <rect> + <x>9</x> + <y>38</y> + <width>118</width> + <height>23</height> + </rect> + </property> + <property name="objectName"> + <string notr="true">progressBar</string> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Horizontal Line" icon="widgets/line.png"> + <ui> + <widget class="Line"> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="objectName"> + <string notr="true">line</string> + </property> + <property name="geometry" > + <rect> + <x>9</x> + <y>67</y> + <width>118</width> + <height>3</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + <categoryentry name="Vertical Line" icon="widgets/vline.png"> + <ui> + <widget class="Line"> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="objectName"> + <string notr="true">line</string> + </property> + <property name="geometry" > + <rect> + <x>133</x> + <y>9</y> + <width>3</width> + <height>61</height> + </rect> + </property> + </widget> + </ui> + </categoryentry> + + </category> +</widgetbox> diff --git a/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp new file mode 100644 index 0000000..1dc63a5 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox_dnditem.h" +#include "ui4_p.h" + +#include <widgetfactory_p.h> +#include <spacer_widget_p.h> +#include <qdesigner_formbuilder_p.h> +#include <qtresourcemodel_p.h> +#include <formscriptrunner_p.h> +#include <formwindowbase_p.h> +#include <qdesigner_utils_p.h> +#include <qdesigner_dockwidget_p.h> + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtGui/QStyle> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +/******************************************************************************* +** WidgetBoxResource +*/ + +static inline DeviceProfile currentDeviceProfile(const QDesignerFormEditorInterface *core) +{ + if (QDesignerFormWindowInterface *cfw = core->formWindowManager()->activeFormWindow()) + if (const FormWindowBase *fwb = qobject_cast<const FormWindowBase *>(cfw)) + return fwb->deviceProfile(); + return DeviceProfile(); +} + +class WidgetBoxResource : public QDesignerFormBuilder +{ +public: + WidgetBoxResource(QDesignerFormEditorInterface *core); + + // protected->public + QWidget *createUI(DomUI *ui, QWidget *parents) { return QDesignerFormBuilder::create(ui, parents); } + +protected: + + virtual QWidget *create(DomWidget *ui_widget, QWidget *parents); + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); +}; + +WidgetBoxResource::WidgetBoxResource(QDesignerFormEditorInterface *core) : + QDesignerFormBuilder(core, DisableScripts, currentDeviceProfile(core)) +{ +} + + +QWidget *WidgetBoxResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) +{ + if (widgetName == QLatin1String("Spacer")) { + Spacer *spacer = new Spacer(parentWidget); + spacer->setObjectName(name); + return spacer; + } + + return QDesignerFormBuilder::createWidget(widgetName, parentWidget, name); +} + +QWidget *WidgetBoxResource::create(DomWidget *ui_widget, QWidget *parent) +{ + QWidget *result = QDesignerFormBuilder::create(ui_widget, parent); + // It is possible to have a syntax error or something in custom + // widget XML, so, try to recover here by creating an artificial + // top level + widget. + if (!result) { + const QString msg = QApplication::translate("qdesigner_internal::WidgetBox", "Warning: Widget creation failed in the widget box. This could be caused by invalid custom widget XML."); + qdesigner_internal::designerWarning(msg); + result = new QWidget(parent); + new QWidget(result); + } + result->setFocusPolicy(Qt::NoFocus); + result->setObjectName(ui_widget->attributeName()); + return result; +} + +/******************************************************************************* +** WidgetBoxResource +*/ + +static QSize geometryProp(const DomWidget *dw) +{ + const QList<DomProperty*> prop_list = dw->elementProperty(); + const QString geometry = QLatin1String("geometry"); + foreach (DomProperty *prop, prop_list) { + if (prop->attributeName() != geometry) + continue; + DomRect *dr = prop->elementRect(); + if (dr == 0) + continue; + return QSize(dr->elementWidth(), dr->elementHeight()); + } + return QSize(); +} + +static QSize domWidgetSize(const DomWidget *dw) +{ + QSize size = geometryProp(dw); + if (size.isValid()) + return size; + + foreach (const DomWidget *child, dw->elementWidget()) { + size = geometryProp(child); + if (size.isValid()) + return size; + } + + foreach (const DomLayout *dl, dw->elementLayout()) { + foreach (DomLayoutItem *item, dl->elementItem()) { + const DomWidget *child = item->elementWidget(); + if (child == 0) + continue; + size = geometryProp(child); + if (size.isValid()) + return size; + } + } + + return QSize(); +} + +static QWidget *decorationFromDomWidget(DomUI *dom_ui, QDesignerFormEditorInterface *core) +{ + WidgetBoxResource builder(core); + // We have the builder create the articial QWidget fake top level as a tooltip + // because the size algorithm works better at weird DPI settings + // if the actual widget is created as a child of a container + QWidget *fakeTopLevel = builder.createUI(dom_ui, static_cast<QWidget*>(0)); + fakeTopLevel->setParent(0, Qt::ToolTip); // Container + // Actual widget + const DomWidget *domW = dom_ui->elementWidget()->elementWidget().front(); + QWidget *w = qFindChildren<QWidget*>(fakeTopLevel).front(); + Q_ASSERT(w); + // hack begin; + // We set _q_dockDrag dynamic property which will be detected in drag enter event of form window. + // Dock drop is handled in special way (highlight goes to central widget of main window) + if (qobject_cast<QDesignerDockWidget *>(w)) + fakeTopLevel->setProperty("_q_dockDrag", QVariant(true)); + // hack end; + w->setAutoFillBackground(true); // Different style for embedded + QSize size = domWidgetSize(domW); + const QSize minimumSize = w->minimumSizeHint(); + if (!size.isValid()) + size = w->sizeHint(); + if (size.width() < minimumSize.width()) + size.setWidth(minimumSize.width()); + if (size.height() < minimumSize.height()) + size.setHeight(minimumSize.height()); + // A QWidget might have size -1,-1 if no geometry property is specified in the widget box. + if (size.isEmpty()) + size = size.expandedTo(QSize(16, 16)); + w->setGeometry(QRect(QPoint(0, 0), size)); + fakeTopLevel->resize(size); + return fakeTopLevel; +} + +WidgetBoxDnDItem::WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos) : + QDesignerDnDItem(CopyDrop) +{ + QWidget *decoration = decorationFromDomWidget(dom_ui, core); + decoration->move(global_mouse_pos - QPoint(5, 5)); + + init(dom_ui, 0, decoration, global_mouse_pos); +} +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetbox_dnditem.h b/tools/designer/src/components/widgetbox/widgetbox_dnditem.h new file mode 100644 index 0000000..0641f69 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_dnditem.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_DNDITEM_H +#define WIDGETBOX_DNDITEM_H + +#include <qdesigner_dnditem_p.h> +#include "widgetbox_global.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class DomUI; + +namespace qdesigner_internal { + +class QT_WIDGETBOX_EXPORT WidgetBoxDnDItem : public QDesignerDnDItem +{ +public: + WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_DNDITEM_H diff --git a/tools/designer/src/components/widgetbox/widgetbox_global.h b/tools/designer/src/components/widgetbox/widgetbox_global.h new file mode 100644 index 0000000..3e95063 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetbox_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_GLOBAL_H +#define WIDGETBOX_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_WIDGETBOX_LIBRARY +# define QT_WIDGETBOX_EXPORT +#else +# define QT_WIDGETBOX_EXPORT +#endif +#else +#define QT_WIDGETBOX_EXPORT +#endif + +#endif // WIDGETBOX_GLOBAL_H diff --git a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp new file mode 100644 index 0000000..fad13f2 --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp @@ -0,0 +1,494 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxcategorylistview.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> + +#include <QtXml/QDomDocument> + +#include <QtGui/QIcon> +#include <QtGui/QListView> +#include <QtGui/QLineEdit> +#include <QtGui/QItemDelegate> +#include <QtGui/QSortFilterProxyModel> + +#include <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QTextStream> +#include <QtCore/QRegExp> + +static const char *widgetElementC = "widget"; +static const char *nameAttributeC = "name"; +static const char *uiOpeningTagC = "<ui>"; +static const char *uiClosingTagC = "</ui>"; + +QT_BEGIN_NAMESPACE + +enum { FilterRole = Qt::UserRole + 11 }; + +static QString domToString(const QDomElement &elt) +{ + QString result; + QTextStream stream(&result, QIODevice::WriteOnly); + elt.save(stream, 2); + stream.flush(); + return result; +} + +static QDomDocument stringToDom(const QString &xml) +{ + QDomDocument result; + result.setContent(xml); + return result; +} + +namespace qdesigner_internal { + +// Entry of the model list + +struct WidgetBoxCategoryEntry { + WidgetBoxCategoryEntry(); + explicit WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + + QDesignerWidgetBoxInterface::Widget widget; + QString toolTip; + QString whatsThis; + QIcon icon; + bool editable; +}; + + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry() : + editable(false) +{ +} + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &w, const QIcon &i, bool e) : + widget(w), + icon(i), + editable(e) +{ +} + +/* WidgetBoxCategoryModel, representing a list of category entries. Uses a + * QAbstractListModel since the behaviour depends on the view mode of the list + * view, it does not return text in the case of IconMode. */ + +class WidgetBoxCategoryModel : public QAbstractListModel { +public: + explicit WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent = 0); + + // QAbstractListModel + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); + virtual Qt::ItemFlags flags (const QModelIndex & index ) const; + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + + // The model returns no text in icon mode, so, it also needs to know it + QListView::ViewMode viewMode() const; + void setViewMode(QListView::ViewMode vm); + + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + + QDesignerWidgetBoxInterface::Widget widgetAt(const QModelIndex & index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(int row) const; + + int indexOfWidget(const QString &name); + + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + +private: + typedef QList<WidgetBoxCategoryEntry> WidgetBoxCategoryEntrys; + + QDesignerFormEditorInterface *m_core; + WidgetBoxCategoryEntrys m_items; + QListView::ViewMode m_viewMode; +}; + +WidgetBoxCategoryModel::WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent) : + QAbstractListModel(parent), + m_core(core), + m_viewMode(QListView::ListMode) +{ +} + +QListView::ViewMode WidgetBoxCategoryModel::viewMode() const +{ + return m_viewMode; +} + +void WidgetBoxCategoryModel::setViewMode(QListView::ViewMode vm) +{ + if (m_viewMode == vm) + return; + m_viewMode = vm; + if (!m_items.empty()) + reset(); +} + +int WidgetBoxCategoryModel::indexOfWidget(const QString &name) +{ + const int count = m_items.size(); + for (int i = 0; i < count; i++) + if (m_items.at(i).widget.name() == name) + return i; + return -1; +} + +QDesignerWidgetBoxInterface::Category WidgetBoxCategoryModel::category() const +{ + QDesignerWidgetBoxInterface::Category rc; + const WidgetBoxCategoryEntrys::const_iterator cend = m_items.constEnd(); + for (WidgetBoxCategoryEntrys::const_iterator it = m_items.constBegin(); it != cend; ++it) + rc.addWidget(it->widget); + return rc; +} + +bool WidgetBoxCategoryModel::removeCustomWidgets() +{ + // Typically, we are a whole category of custom widgets, so, remove all + // and do reset. + bool changed = false; + for (WidgetBoxCategoryEntrys::iterator it = m_items.begin(); it != m_items.end(); ) + if (it->widget.type() == QDesignerWidgetBoxInterface::Widget::Custom) { + it = m_items.erase(it); + changed = true; + } else { + ++it; + } + if (changed) + reset(); + return changed; +} + +void WidgetBoxCategoryModel::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon,bool editable) +{ + // build item + WidgetBoxCategoryEntry item(widget, icon, editable); + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const int dbIndex = db->indexOfClassName(widget.name()); + if (dbIndex != -1) { + const QDesignerWidgetDataBaseItemInterface *dbItem = db->item(dbIndex); + const QString toolTip = dbItem->toolTip(); + if (!toolTip.isEmpty()) + item.toolTip = toolTip; + const QString whatsThis = dbItem->whatsThis(); + if (!whatsThis.isEmpty()) + item.whatsThis = whatsThis; + } + // insert + const int row = m_items.size(); + beginInsertRows(QModelIndex(), row, row); + m_items.push_back(item); + endInsertRows(); +} + +QVariant WidgetBoxCategoryModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return QVariant(); + + const WidgetBoxCategoryEntry &item = m_items.at(row); + switch (role) { + case Qt::DisplayRole: + // No text in icon mode + return QVariant(m_viewMode == QListView::ListMode ? item.widget.name() : QString()); + case Qt::DecorationRole: + return QVariant(item.icon); + case Qt::EditRole: + return QVariant(item.widget.name()); + case Qt::ToolTipRole: { + if (m_viewMode == QListView::ListMode) + return QVariant(item.toolTip); + // Icon mode tooltip should contain the class name + QString tt = item.widget.name(); + if (!item.toolTip.isEmpty()) { + tt += QLatin1Char('\n'); + tt += item.toolTip; + } + return QVariant(tt); + + } + case Qt::WhatsThisRole: + return QVariant(item.whatsThis); + case FilterRole: + return item.widget.name(); + } + return QVariant(); +} + +bool WidgetBoxCategoryModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int row = index.row(); + if (role != Qt::EditRole || row < 0 || row >= m_items.size() || value.type() != QVariant::String) + return false; + // Set name and adapt Xml + WidgetBoxCategoryEntry &item = m_items[row]; + const QString newName = value.toString(); + item.widget.setName(newName); + + const QDomDocument doc = stringToDom(WidgetBoxCategoryListView::widgetDomXml(item.widget)); + QDomElement widget_elt = doc.firstChildElement(QLatin1String(widgetElementC)); + if (!widget_elt.isNull()) { + widget_elt.setAttribute(QLatin1String(nameAttributeC), newName); + item.widget.setDomXml(domToString(widget_elt)); + } + emit dataChanged(index, index); + return true; +} + +Qt::ItemFlags WidgetBoxCategoryModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags rc = Qt::ItemIsEnabled; + const int row = index.row(); + if (row >= 0 && row < m_items.size()) + if (m_items.at(row).editable) { + rc |= Qt::ItemIsSelectable; + // Can change name in list mode only + if (m_viewMode == QListView::ListMode) + rc |= Qt::ItemIsEditable; + } + return rc; +} + +int WidgetBoxCategoryModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_items.size(); +} + +bool WidgetBoxCategoryModel::removeRows(int row, int count, const QModelIndex & parent) +{ + if (row < 0 || count < 1) + return false; + const int size = m_items.size(); + const int last = row + count - 1; + if (row >= size || last >= size) + return false; + beginRemoveRows(parent, row, last); + for (int r = last; r >= row; r--) + m_items.removeAt(r); + endRemoveRows(); + return true; +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(const QModelIndex & index) const +{ + return widgetAt(index.row()); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(int row) const +{ + if (row < 0 || row >= m_items.size()) + return QDesignerWidgetBoxInterface::Widget(); + return m_items.at(row).widget; +} + +/* WidgetSubBoxItemDelegate, ensures a valid name using a regexp validator */ + +class WidgetBoxCategoryEntryDelegate : public QItemDelegate +{ +public: + explicit WidgetBoxCategoryEntryDelegate(QWidget *parent = 0) : QItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; +}; + +QWidget *WidgetBoxCategoryEntryDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QWidget *result = QItemDelegate::createEditor(parent, option, index); + if (QLineEdit *line_edit = qobject_cast<QLineEdit*>(result)) { + const QRegExp re = QRegExp(QLatin1String("[_a-zA-Z][_a-zA-Z0-9]*")); + Q_ASSERT(re.isValid()); + line_edit->setValidator(new QRegExpValidator(re, line_edit)); + } + return result; +} + +// ---------------------- WidgetBoxCategoryListView + +WidgetBoxCategoryListView::WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent) : + QListView(parent), + m_proxyModel(new QSortFilterProxyModel(this)), + m_model(new WidgetBoxCategoryModel(core, this)) +{ + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setIconSize(QSize(22, 22)); + setSpacing(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setResizeMode(QListView::Adjust); + setUniformItemSizes(true); + + setItemDelegate(new WidgetBoxCategoryEntryDelegate(this)); + + connect(this, SIGNAL(pressed(QModelIndex)), this, SLOT(slotPressed(QModelIndex))); + setEditTriggers(QAbstractItemView::AnyKeyPressed); + + m_proxyModel->setSourceModel(m_model); + m_proxyModel->setFilterRole(FilterRole); + setModel(m_proxyModel); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SIGNAL(scratchPadChanged())); +} + +void WidgetBoxCategoryListView::setViewMode(ViewMode vm) +{ + QListView::setViewMode(vm); + m_model->setViewMode(vm); +} + +void WidgetBoxCategoryListView::setCurrentItem(AccessMode am, int row) +{ + const QModelIndex index = am == FilteredAccess ? + m_proxyModel->index(row, 0) : + m_proxyModel->mapFromSource(m_model->index(row, 0)); + + if (index.isValid()) + setCurrentIndex(index); +} + +void WidgetBoxCategoryListView::slotPressed(const QModelIndex &index) +{ + const QDesignerWidgetBoxInterface::Widget wgt = m_model->widgetAt(m_proxyModel->mapToSource(index)); + if (wgt.isNull()) + return; + emit pressed(wgt.name(), widgetDomXml(wgt), QCursor::pos()); +} + +void WidgetBoxCategoryListView::removeCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (!index.isValid() || !m_proxyModel->removeRow(index.row())) + return; + + // We check the unfiltered item count here, we don't want to get removed if the + // filtered view is empty + if (m_model->rowCount()) { + emit itemRemoved(); + } else { + emit lastItemRemoved(); + } +} + +void WidgetBoxCategoryListView::editCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (index.isValid()) + edit(index); +} + +int WidgetBoxCategoryListView::count(AccessMode am) const +{ + return am == FilteredAccess ? m_proxyModel->rowCount() : m_model->rowCount(); +} + +int WidgetBoxCategoryListView::mapRowToSource(int filterRow) const +{ + const QModelIndex filterIndex = m_proxyModel->index(filterRow, 0); + return m_proxyModel->mapToSource(filterIndex).row(); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, const QModelIndex & index) const +{ + const QModelIndex unfilteredIndex = am == FilteredAccess ? m_proxyModel->mapToSource(index) : index; + return m_model->widgetAt(unfilteredIndex); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, int row) const +{ + return m_model->widgetAt(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +void WidgetBoxCategoryListView::removeRow(AccessMode am, int row) +{ + m_model->removeRow(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +bool WidgetBoxCategoryListView::containsWidget(const QString &name) +{ + return m_model->indexOfWidget(name) != -1; +} + +void WidgetBoxCategoryListView::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable) +{ + m_model->addWidget(widget, icon, editable); +} + +QString WidgetBoxCategoryListView::widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget) +{ + QString domXml = widget.domXml(); + + if (domXml.isEmpty()) { + domXml = QLatin1String(uiOpeningTagC); + domXml += QLatin1String("<widget class=\""); + domXml += widget.name(); + domXml += QLatin1String("\"/>"); + domXml += QLatin1String(uiClosingTagC); + } + return domXml; +} + +void WidgetBoxCategoryListView::filter(const QRegExp &re) +{ + m_proxyModel->setFilterRegExp(re); +} + +QDesignerWidgetBoxInterface::Category WidgetBoxCategoryListView::category() const +{ + return m_model->category(); +} + +bool WidgetBoxCategoryListView::removeCustomWidgets() +{ + return m_model->removeCustomWidgets(); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h new file mode 100644 index 0000000..c8c5d3a --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXCATEGORYLISTVIEW_H +#define WIDGETBOXCATEGORYLISTVIEW_H + +#include <QtDesigner/QDesignerWidgetBoxInterface> + +#include <QtGui/QListView> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QSortFilterProxyModel; +class QRegExp; + +namespace qdesigner_internal { + +class WidgetBoxCategoryModel; + +// List view of a category, switchable between icon and list mode. +// Provides a filtered view. +class WidgetBoxCategoryListView : public QListView +{ + Q_OBJECT +public: + // Whether to access the filtered or unfiltered view + enum AccessMode { FilteredAccess, UnfilteredAccess }; + + explicit WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent = 0); + void setViewMode(ViewMode vm); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list); + + using QListView::contentsSize; + + // These methods operate on the filtered/unfiltered model according to accessmode + int count(AccessMode am) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, const QModelIndex &index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, int row) const; + void removeRow(AccessMode am, int row); + void setCurrentItem(AccessMode am, int row); + + // These methods operate on the unfiltered model and are used for serialization + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + bool containsWidget(const QString &name); + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + + // Helper: Ensure a <ui> tag in the case of empty XML + static QString widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget); + +signals: + void scratchPadChanged(); + void pressed(const QString &name, const QString &xml, const QPoint &globalPos); + void itemRemoved(); + void lastItemRemoved(); + +public slots: + void filter(const QRegExp &re); + +private slots: + void slotPressed(const QModelIndex &index); + void removeCurrentItem(); + void editCurrentItem(); + +private: + int mapRowToSource(int filterRow) const; + QSortFilterProxyModel *m_proxyModel; + WidgetBoxCategoryModel *m_model; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXCATEGORYLISTVIEW_H diff --git a/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp b/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp new file mode 100644 index 0000000..799f96f --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp @@ -0,0 +1,998 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxtreewidget.h" +#include "widgetboxcategorylistview.h" + +// shared +#include <iconloader_p.h> +#include <sheet_delegate_p.h> +#include <QtDesigner/private/abstractsettings_p.h> +#include <ui4_p.h> +#include <qdesigner_utils_p.h> +#include <pluginmanager_p.h> + +// sdk +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerDnDItemInterface> +#include <QtDesigner/QDesignerCustomWidgetInterface> +#include <QtDesigner/private/abstractsettings_p.h> + +#include <QtGui/QHeaderView> +#include <QtGui/QApplication> +#include <QtGui/QTreeWidgetItem> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QAction> +#include <QtGui/QActionGroup> +#include <QtGui/QMenu> + +#include <QtCore/QFile> +#include <QtCore/QTimer> +#include <QtCore/QDebug> + +static const char *widgetBoxRootElementC = "widgetbox"; +static const char *widgetElementC = "widget"; +static const char *uiElementC = "ui"; +static const char *categoryElementC = "category"; +static const char *categoryEntryElementC = "categoryentry"; +static const char *nameAttributeC = "name"; +static const char *typeAttributeC = "type"; +static const char *iconAttributeC = "icon"; +static const char *defaultTypeValueC = "default"; +static const char *customValueC = "custom"; +static const char *iconPrefixC = "__qt_icon__"; +static const char *scratchPadValueC = "scratchpad"; +static const char *qtLogoC = "qtlogo.png"; +static const char *invisibleNameC = "[invisible]"; + +enum TopLevelRole { NORMAL_ITEM, SCRATCHPAD_ITEM, CUSTOM_ITEM }; + +QT_BEGIN_NAMESPACE + +static void setTopLevelRole(TopLevelRole tlr, QTreeWidgetItem *item) +{ + item->setData(0, Qt::UserRole, QVariant(tlr)); +} + +static TopLevelRole topLevelRole(const QTreeWidgetItem *item) +{ + return static_cast<TopLevelRole>(item->data(0, Qt::UserRole).toInt()); +} + +namespace qdesigner_internal { + +WidgetBoxTreeWidget::WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent) : + QTreeWidget(parent), + m_core(core), + m_iconMode(false), + m_scratchPadDeleteTimer(0) +{ + setFocusPolicy(Qt::NoFocus); + setIndentation(0); + setRootIsDecorated(false); + setColumnCount(1); + header()->hide(); + header()->setResizeMode(QHeaderView::Stretch); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollMode(ScrollPerPixel); + + setItemDelegate(new SheetDelegate(this, this)); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), + this, SLOT(handleMousePress(QTreeWidgetItem*))); +} + +QIcon WidgetBoxTreeWidget::iconForWidget(QString iconName) const +{ + if (iconName.isEmpty()) + iconName = QLatin1String(qtLogoC); + + if (iconName.startsWith(QLatin1String(iconPrefixC))) { + const IconCache::const_iterator it = m_pluginIcons.constFind(iconName); + if (it != m_pluginIcons.constEnd()) + return it.value(); + } + return createIconSet(iconName); +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::categoryViewAt(int idx) const +{ + WidgetBoxCategoryListView *rc = 0; + if (QTreeWidgetItem *cat_item = topLevelItem(idx)) + if (QTreeWidgetItem *embedItem = cat_item->child(0)) + rc = qobject_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + Q_ASSERT(rc); + return rc; +} + +void WidgetBoxTreeWidget::saveExpandedState() const +{ + QStringList closedCategories; + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + const QTreeWidgetItem *cat_item = topLevelItem(i); + if (!isItemExpanded(cat_item)) + closedCategories.append(cat_item->text(0)); + } + } + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(widgetBoxRootElementC)); + settings->setValue(QLatin1String("Closed categories"), closedCategories); + settings->setValue(QLatin1String("View mode"), m_iconMode); + settings->endGroup(); +} + +void WidgetBoxTreeWidget::restoreExpandedState() +{ + typedef QSet<QString> StringSet; + QDesignerSettingsInterface *settings = m_core->settingsManager(); + m_iconMode = settings->value(QLatin1String("WidgetBox/View mode")).toBool(); + updateViewMode(); + const StringSet closedCategories = settings->value(QLatin1String("WidgetBox/Closed categories"), QStringList()).toStringList().toSet(); + expandAll(); + if (closedCategories.empty()) + return; + + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + QTreeWidgetItem *item = topLevelItem(i); + if (closedCategories.contains(item->text(0))) + item->setExpanded(false); + } + } +} + +WidgetBoxTreeWidget::~WidgetBoxTreeWidget() +{ + saveExpandedState(); +} + +void WidgetBoxTreeWidget::setFileName(const QString &file_name) +{ + m_file_name = file_name; +} + +QString WidgetBoxTreeWidget::fileName() const +{ + return m_file_name; +} + +bool WidgetBoxTreeWidget::save() +{ + if (fileName().isEmpty()) + return false; + + QFile file(fileName()); + if (!file.open(QIODevice::WriteOnly)) + return false; + + CategoryList cat_list; + const int count = categoryCount(); + for (int i = 0; i < count; ++i) + cat_list.append(category(i)); + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + writeCategories(writer, cat_list); + writer.writeEndDocument(); + + return true; +} + +void WidgetBoxTreeWidget::slotSave() +{ + save(); +} + +void WidgetBoxTreeWidget::handleMousePress(QTreeWidgetItem *item) +{ + if (item == 0) + return; + + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + if (item->parent() == 0) { + setItemExpanded(item, !isItemExpanded(item)); + return; + } +} + +int WidgetBoxTreeWidget::ensureScratchpad() +{ + const int existingIndex = indexOfScratchpad(); + if (existingIndex != -1) + return existingIndex; + + QTreeWidgetItem *scratch_item = new QTreeWidgetItem(this); + scratch_item->setText(0, tr("Scratchpad")); + setTopLevelRole(SCRATCHPAD_ITEM, scratch_item); + addCategoryView(scratch_item, false); // Scratchpad in list mode. + return categoryCount() - 1; +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::addCategoryView(QTreeWidgetItem *parent, bool iconMode) +{ + QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent); + embed_item->setFlags(Qt::ItemIsEnabled); + WidgetBoxCategoryListView *categoryView = new WidgetBoxCategoryListView(m_core, this); + categoryView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode); + connect(categoryView, SIGNAL(scratchPadChanged()), this, SLOT(slotSave())); + connect(categoryView, SIGNAL(pressed(QString,QString,QPoint)), this, SIGNAL(pressed(QString,QString,QPoint))); + connect(categoryView, SIGNAL(itemRemoved()), this, SLOT(slotScratchPadItemDeleted())); + connect(categoryView, SIGNAL(lastItemRemoved()), this, SLOT(slotLastScratchPadItemDeleted())); + setItemWidget(embed_item, 0, categoryView); + return categoryView; +} + +int WidgetBoxTreeWidget::indexOfScratchpad() const +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + if (topLevelRole(topLevelItem(i)) == SCRATCHPAD_ITEM) + return i; + } + } + return -1; +} + +int WidgetBoxTreeWidget::indexOfCategory(const QString &name) const +{ + const int topLevelCount = topLevelItemCount(); + for (int i = 0; i < topLevelCount; ++i) { + if (topLevelItem(i)->text(0) == name) + return i; + } + return -1; +} + +bool WidgetBoxTreeWidget::load(QDesignerWidgetBox::LoadMode loadMode) +{ + switch (loadMode) { + case QDesignerWidgetBox::LoadReplace: + clear(); + break; + case QDesignerWidgetBox::LoadCustomWidgetsOnly: + addCustomCategories(true); + updateGeometries(); + return true; + default: + break; + } + + const QString name = fileName(); + + QFile f(name); + if (!f.open(QIODevice::ReadOnly)) // Might not exist at first startup + return false; + + const QString contents = QString::fromUtf8(f.readAll()); + return loadContents(contents); +} + +bool WidgetBoxTreeWidget::loadContents(const QString &contents) +{ + QString errorMessage; + CategoryList cat_list; + if (!readCategories(m_file_name, contents, &cat_list, &errorMessage)) { + qdesigner_internal::designerWarning(errorMessage); + return false; + } + + foreach(const Category &cat, cat_list) + addCategory(cat); + + addCustomCategories(false); + // Restore which items are expanded + restoreExpandedState(); + return true; +} + +void WidgetBoxTreeWidget::addCustomCategories(bool replace) +{ + if (replace) { + // clear out all existing custom widgets + if (const int numTopLevels = topLevelItemCount()) { + for (int t = 0; t < numTopLevels ; ++t) + categoryViewAt(t)->removeCustomWidgets(); + } + } + // re-add + const CategoryList customList = loadCustomCategoryList(); + const CategoryList::const_iterator cend = customList.constEnd(); + for (CategoryList::const_iterator it = customList.constBegin(); it != cend; ++it) + addCategory(*it); +} + +static inline QString msgXmlError(const QString &fileName, const QXmlStreamReader &r) +{ + return QDesignerWidgetBox::tr("An error has been encountered at line %1 of %2: %3") + .arg(r.lineNumber()).arg(fileName, r.errorString()); +} + +bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString &contents, + CategoryList *cats, QString *errorMessage) +{ + // Read widget box XML: + // + //<widgetbox version="4.5"> + // <category name="Layouts"> + // <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default"> + // <widget class="QListWidget" ...> + // ... + + QXmlStreamReader reader(contents); + + + // Entries of category with name="invisible" should be ignored + bool ignoreEntries = false; + + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + //<widgetbox version="4.5"> + continue; + } + if (tag == QLatin1String(categoryElementC)) { + // <category name="Layouts"> + const QXmlStreamAttributes attributes = reader.attributes(); + const QString categoryName = attributes.value(QLatin1String(nameAttributeC)).toString(); + if (categoryName == QLatin1String(invisibleNameC)) { + ignoreEntries = true; + } else { + Category category(categoryName); + if (attributes.value(QLatin1String(typeAttributeC)) == QLatin1String(scratchPadValueC)) + category.setType(Category::Scratchpad); + cats->push_back(category); + } + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + // <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default"> + if (!ignoreEntries) { + QXmlStreamAttributes attr = reader.attributes(); + const QString widgetName = attr.value(QLatin1String(nameAttributeC)).toString(); + const QString widgetIcon = attr.value(QLatin1String(iconAttributeC)).toString(); + const WidgetBoxTreeWidget::Widget::Type widgetType = + attr.value(QLatin1String(typeAttributeC)).toString() + == QLatin1String(customValueC) ? + WidgetBoxTreeWidget::Widget::Custom : + WidgetBoxTreeWidget::Widget::Default; + + Widget w; + w.setName(widgetName); + w.setIconName(widgetIcon); + w.setType(widgetType); + if (!readWidget(&w, contents, reader)) + continue; + + cats->back().addWidget(w); + } // ignoreEntries + continue; + } + break; + } + case QXmlStreamReader::EndElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + continue; + } + if (tag == QLatin1String(categoryElementC)) { + ignoreEntries = false; + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + continue; + } + break; + } + default: break; + } + } + + if (reader.hasError()) { + *errorMessage = msgXmlError(fileName, reader); + return false; + } + + return true; +} + +/*! + * Read out a widget within a category. This can either be + * enclosed in a <ui> element or a (legacy) <widget> element which may + * contain nested <widget> elements. + * + * Examples: + * + * <ui language="c++"> + * <widget class="MultiPageWidget" name="multipagewidget"> ... </widget> + * <customwidgets>...</customwidgets> + * <ui> + * + * or + * + * <widget> + * <widget> ... </widget> + * ... + * <widget> + * + * Returns true on success, false if end was reached or an error has been encountered + * in which case the reader has its error flag set. If successful, the current item + * of the reader will be the closing element (</ui> or </widget>) + */ +bool WidgetBoxTreeWidget::readWidget(Widget *w, const QString &xml, QXmlStreamReader &r) +{ + qint64 startTagPosition =0, endTagPosition = 0; + + int nesting = 0; + bool endEncountered = false; + bool parsedWidgetTag = false; + QString outmostElement; + while (!endEncountered) { + const qint64 currentPosition = r.characterOffset(); + switch(r.readNext()) { + case QXmlStreamReader::StartElement: + if (nesting++ == 0) { + // First element must be <ui> or (legacy) <widget> + const QStringRef name = r.name(); + if (name == QLatin1String(uiElementC)) { + startTagPosition = currentPosition; + } else { + if (name == QLatin1String(widgetElementC)) { + startTagPosition = currentPosition; + parsedWidgetTag = true; + } else { + r.raiseError(QDesignerWidgetBox::tr("Unexpected element <%1> encountered when parsing for <widget> or <ui>").arg(name.toString())); + return false; + } + } + } else { + // We are within <ui> looking for the first <widget> tag + if (!parsedWidgetTag && r.name() == QLatin1String(widgetElementC)) { + parsedWidgetTag = true; + } + } + break; + case QXmlStreamReader::EndElement: + // Reached end of widget? + if (--nesting == 0) { + endTagPosition = r.characterOffset(); + endEncountered = true; + } + break; + case QXmlStreamReader::EndDocument: + r.raiseError(QDesignerWidgetBox::tr("Unexpected end of file encountered when parsing widgets.")); + return false; + case QXmlStreamReader::Invalid: + return false; + default: + break; + } + } + if (!parsedWidgetTag) { + r.raiseError(QDesignerWidgetBox::tr("A widget element could not be found.")); + return false; + } + // Oddity: Startposition is 1 off + QString widgetXml = xml.mid(startTagPosition, endTagPosition - startTagPosition); + const QChar lessThan = QLatin1Char('<'); + if (!widgetXml.startsWith(lessThan)) + widgetXml.prepend(lessThan); + w->setDomXml(widgetXml); + return true; +} + +void WidgetBoxTreeWidget::writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const +{ + const QString widgetbox = QLatin1String(widgetBoxRootElementC); + const QString name = QLatin1String(nameAttributeC); + const QString type = QLatin1String(typeAttributeC); + const QString icon = QLatin1String(iconAttributeC); + const QString defaultType = QLatin1String(defaultTypeValueC); + const QString category = QLatin1String(categoryElementC); + const QString categoryEntry = QLatin1String(categoryEntryElementC); + const QString iconPrefix = QLatin1String(iconPrefixC); + const QString widgetTag = QLatin1String(widgetElementC); + + // + // <widgetbox> + // <category name="Layouts"> + // <categoryEntry name="Vertical Layout" type="default" icon="win/editvlayout.png"> + // <ui> + // ... + // </ui> + // </categoryEntry> + // ... + // </category> + // ... + // </widgetbox> + // + + writer.writeStartElement(widgetbox); + + foreach (const Category &cat, cat_list) { + writer.writeStartElement(category); + writer.writeAttribute(name, cat.name()); + if (cat.type() == Category::Scratchpad) + writer.writeAttribute(type, QLatin1String(scratchPadValueC)); + + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget wgt = cat.widget(i); + if (wgt.type() == Widget::Custom) + continue; + + writer.writeStartElement(categoryEntry); + writer.writeAttribute(name, wgt.name()); + if (!wgt.iconName().startsWith(iconPrefix)) + writer.writeAttribute(icon, wgt.iconName()); + writer.writeAttribute(type, defaultType); + + const DomUI *domUI = QDesignerWidgetBox::xmlToUi(wgt.name(), WidgetBoxCategoryListView::widgetDomXml(wgt), false); + if (domUI) { + domUI->write(writer); + delete domUI; + } + + writer.writeEndElement(); // categoryEntry + } + writer.writeEndElement(); // categoryEntry + } + + writer.writeEndElement(); // widgetBox +} + +static int findCategory(const QString &name, const WidgetBoxTreeWidget::CategoryList &list) +{ + int idx = 0; + foreach (const WidgetBoxTreeWidget::Category &cat, list) { + if (cat.name() == name) + return idx; + ++idx; + } + return -1; +} + +static inline bool isValidIcon(const QIcon &icon) +{ + if (!icon.isNull()) { + const QList<QSize> availableSizes = icon.availableSizes(); + if (!availableSizes.empty()) + return !availableSizes.front().isEmpty(); + } + return false; +} + +WidgetBoxTreeWidget::CategoryList WidgetBoxTreeWidget::loadCustomCategoryList() const +{ + CategoryList result; + + const QDesignerPluginManager *pm = m_core->pluginManager(); + const QDesignerPluginManager::CustomWidgetList customWidgets = pm->registeredCustomWidgets(); + if (customWidgets.empty()) + return result; + + static const QString customCatName = tr("Custom Widgets"); + + const QString invisible = QLatin1String(invisibleNameC); + const QString iconPrefix = QLatin1String(iconPrefixC); + + foreach(QDesignerCustomWidgetInterface *c, customWidgets) { + const QString dom_xml = c->domXml(); + if (dom_xml.isEmpty()) + continue; + + const QString pluginName = c->name(); + const QDesignerCustomWidgetData data = pm->customWidgetData(c); + QString displayName = data.xmlDisplayName(); + if (displayName.isEmpty()) + displayName = pluginName; + + QString cat_name = c->group(); + if (cat_name.isEmpty()) + cat_name = customCatName; + else if (cat_name == invisible) + continue; + + int idx = findCategory(cat_name, result); + if (idx == -1) { + result.append(Category(cat_name)); + idx = result.size() - 1; + } + Category &cat = result[idx]; + + const QIcon icon = c->icon(); + + QString icon_name; + if (isValidIcon(icon)) { + icon_name = iconPrefix; + icon_name += pluginName; + m_pluginIcons.insert(icon_name, icon); + } else { + icon_name = QLatin1String(qtLogoC); + } + + cat.addWidget(Widget(displayName, dom_xml, icon_name, Widget::Custom)); + } + + return result; +} + +void WidgetBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item) +{ + QTreeWidgetItem *embedItem = cat_item->child(0); + WidgetBoxCategoryListView *list_widget = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + list_widget->setFixedWidth(header()->width()); + list_widget->doItemsLayout(); + const int height = qMax(list_widget->contentsSize().height() ,1); + list_widget->setFixedHeight(height); + embedItem->setSizeHint(0, QSize(-1, height - 1)); +} + +int WidgetBoxTreeWidget::categoryCount() const +{ + return topLevelItemCount(); +} + +WidgetBoxTreeWidget::Category WidgetBoxTreeWidget::category(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Category(); + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + + QTreeWidgetItem *embedItem = cat_item->child(0); + WidgetBoxCategoryListView *categoryView = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0)); + + Category result = categoryView->category(); + result.setName(cat_item->text(0)); + + switch (topLevelRole(cat_item)) { + case SCRATCHPAD_ITEM: + result.setType(Category::Scratchpad); + break; + default: + result.setType(Category::Default); + break; + } + return result; +} + +void WidgetBoxTreeWidget::addCategory(const Category &cat) +{ + if (cat.widgetCount() == 0) + return; + + const bool isScratchPad = cat.type() == Category::Scratchpad; + WidgetBoxCategoryListView *categoryView; + QTreeWidgetItem *cat_item; + + if (isScratchPad) { + const int idx = ensureScratchpad(); + categoryView = categoryViewAt(idx); + cat_item = topLevelItem(idx); + } else { + const int existingIndex = indexOfCategory(cat.name()); + if (existingIndex == -1) { + cat_item = new QTreeWidgetItem(); + cat_item->setText(0, cat.name()); + setTopLevelRole(NORMAL_ITEM, cat_item); + // insert before scratchpad + const int scratchPadIndex = indexOfScratchpad(); + if (scratchPadIndex == -1) { + addTopLevelItem(cat_item); + } else { + insertTopLevelItem(scratchPadIndex, cat_item); + } + setItemExpanded(cat_item, true); + categoryView = addCategoryView(cat_item, m_iconMode); + } else { + categoryView = categoryViewAt(existingIndex); + cat_item = topLevelItem(existingIndex); + } + } + // The same categories are read from the file $HOME, avoid duplicates + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget w = cat.widget(i); + if (!categoryView->containsWidget(w.name())) + categoryView->addWidget(w, iconForWidget(w.iconName()), isScratchPad); + } + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeCategory(int cat_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + delete takeTopLevelItem(cat_idx); +} + +int WidgetBoxTreeWidget::widgetCount(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return 0; + // SDK functions want unfiltered access + return categoryViewAt(cat_idx)->count(WidgetBoxCategoryListView::UnfilteredAccess); +} + +WidgetBoxTreeWidget::Widget WidgetBoxTreeWidget::widget(int cat_idx, int wgt_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Widget(); + // SDK functions want unfiltered access + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + return categoryView->widgetAt(WidgetBoxCategoryListView::UnfilteredAccess, wgt_idx); +} + +void WidgetBoxTreeWidget::addWidget(int cat_idx, const Widget &wgt) +{ + if (cat_idx >= topLevelItemCount()) + return; + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + const bool scratch = topLevelRole(cat_item) == SCRATCHPAD_ITEM; + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), scratch); + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeWidget(int cat_idx, int wgt_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + // SDK functions want unfiltered access + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::UnfilteredAccess; + if (wgt_idx >= categoryView->count(am)) + return; + + categoryView->removeRow(am, wgt_idx); +} + +void WidgetBoxTreeWidget::slotScratchPadItemDeleted() +{ + const int scratch_idx = indexOfScratchpad(); + QTreeWidgetItem *scratch_item = topLevelItem(scratch_idx); + adjustSubListSize(scratch_item); + save(); +} + +void WidgetBoxTreeWidget::slotLastScratchPadItemDeleted() +{ + // Remove the scratchpad in the next idle loop + if (!m_scratchPadDeleteTimer) { + m_scratchPadDeleteTimer = new QTimer(this); + m_scratchPadDeleteTimer->setSingleShot(true); + m_scratchPadDeleteTimer->setInterval(0); + connect(m_scratchPadDeleteTimer, SIGNAL(timeout()), this, SLOT(deleteScratchpad())); + } + if (!m_scratchPadDeleteTimer->isActive()) + m_scratchPadDeleteTimer->start(); +} + +void WidgetBoxTreeWidget::deleteScratchpad() +{ + const int idx = indexOfScratchpad(); + if (idx == -1) + return; + delete takeTopLevelItem(idx); + save(); +} + + +void WidgetBoxTreeWidget::slotListMode() +{ + m_iconMode = false; + updateViewMode(); +} + +void WidgetBoxTreeWidget::slotIconMode() +{ + m_iconMode = true; + updateViewMode(); +} + +void WidgetBoxTreeWidget::updateViewMode() +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + QTreeWidgetItem *topLevel = topLevelItem(i); + // Scratch pad stays in list mode. + const QListView::ViewMode viewMode = m_iconMode && (topLevelRole(topLevel) != SCRATCHPAD_ITEM) ? QListView::IconMode : QListView::ListMode; + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + if (viewMode != categoryView->viewMode()) { + categoryView->setViewMode(viewMode); + adjustSubListSize(topLevelItem(i)); + } + } + } + + updateGeometries(); +} + +void WidgetBoxTreeWidget::resizeEvent(QResizeEvent *e) +{ + QTreeWidget::resizeEvent(e); + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) + adjustSubListSize(topLevelItem(i)); + } +} + +void WidgetBoxTreeWidget::contextMenuEvent(QContextMenuEvent *e) +{ + QTreeWidgetItem *item = itemAt(e->pos()); + + const bool scratchpad_menu = item != 0 + && item->parent() != 0 + && topLevelRole(item->parent()) == SCRATCHPAD_ITEM; + + QMenu menu; + menu.addAction(tr("Expand all"), this, SLOT(expandAll())); + menu.addAction(tr("Collapse all"), this, SLOT(collapseAll())); + menu.addSeparator(); + + QAction *listModeAction = menu.addAction(tr("List View")); + QAction *iconModeAction = menu.addAction(tr("Icon View")); + listModeAction->setCheckable(true); + iconModeAction->setCheckable(true); + QActionGroup *viewModeGroup = new QActionGroup(&menu); + viewModeGroup->addAction(listModeAction); + viewModeGroup->addAction(iconModeAction); + if (m_iconMode) + iconModeAction->setChecked(true); + else + listModeAction->setChecked(true); + connect(listModeAction, SIGNAL(triggered()), SLOT(slotListMode())); + connect(iconModeAction, SIGNAL(triggered()), SLOT(slotIconMode())); + + if (scratchpad_menu) { + menu.addSeparator(); + menu.addAction(tr("Remove"), itemWidget(item, 0), SLOT(removeCurrentItem())); + if (!m_iconMode) + menu.addAction(tr("Edit name"), itemWidget(item, 0), SLOT(editCurrentItem())); + } + e->accept(); + menu.exec(mapToGlobal(e->pos())); +} + +void WidgetBoxTreeWidget::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list) +{ + QTreeWidgetItem *scratch_item = 0; + WidgetBoxCategoryListView *categoryView = 0; + bool added = false; + + foreach (QDesignerDnDItemInterface *item, item_list) { + QWidget *w = item->widget(); + if (w == 0) + continue; + + DomUI *dom_ui = item->domUi(); + if (dom_ui == 0) + continue; + + const int scratch_idx = ensureScratchpad(); + scratch_item = topLevelItem(scratch_idx); + categoryView = categoryViewAt(scratch_idx); + + // Temporarily remove the fake toplevel in-between + DomWidget *fakeTopLevel = dom_ui->takeElementWidget(); + DomWidget *firstWidget = 0; + if (fakeTopLevel && !fakeTopLevel->elementWidget().isEmpty()) { + firstWidget = fakeTopLevel->elementWidget().first(); + dom_ui->setElementWidget(firstWidget); + } else { + dom_ui->setElementWidget(fakeTopLevel); + continue; + } + + // Serialize to XML + QString xml; + { + QXmlStreamWriter writer(&xml); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + dom_ui->write(writer); + writer.writeEndDocument(); + } + + // Insert fake toplevel again + dom_ui->takeElementWidget(); + dom_ui->setElementWidget(fakeTopLevel); + + const Widget wgt = Widget(w->objectName(), xml); + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), true); + setItemExpanded(scratch_item, true); + added = true; + } + + if (added) { + save(); + QApplication::setActiveWindow(this); + // Is the new item visible in filtered mode? + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::FilteredAccess; + if (const int count = categoryView->count(am)) + categoryView->setCurrentItem(am, count - 1); + categoryView->adjustSize(); // XXX + adjustSubListSize(scratch_item); + } +} + +void WidgetBoxTreeWidget::filter(const QString &f) +{ + const bool empty = f.isEmpty(); + const QRegExp re = empty ? QRegExp() : QRegExp(f, Qt::CaseInsensitive, QRegExp::FixedString); + const int numTopLevels = topLevelItemCount(); + bool changed = false; + for (int i = 0; i < numTopLevels; i++) { + QTreeWidgetItem *tl = topLevelItem(i); + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + // Anything changed? -> Enable the category + const int oldCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + categoryView->filter(re); + const int newCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + if (oldCount != newCount) { + changed = true; + const bool categoryEnabled = newCount > 0 || empty; + if (categoryEnabled) { + categoryView->adjustSize(); + adjustSubListSize(tl); + } + setRowHidden (i, QModelIndex(), !categoryEnabled); + } + } + if (changed) + updateGeometries(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/widgetbox/widgetboxtreewidget.h b/tools/designer/src/components/widgetbox/widgetboxtreewidget.h new file mode 100644 index 0000000..9282a0f --- /dev/null +++ b/tools/designer/src/components/widgetbox/widgetboxtreewidget.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXTREEWIDGET_H +#define WIDGETBOXTREEWIDGET_H + +#include <qdesigner_widgetbox_p.h> + +#include <QtGui/QTreeWidget> +#include <QtGui/QIcon> +#include <QtCore/QList> +#include <QtCore/QHash> +#include <QtCore/QXmlStreamReader> // Cannot forward declare them on Mac +#include <QtCore/QXmlStreamWriter> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QTimer; + +namespace qdesigner_internal { + +class WidgetBoxCategoryListView; + +// WidgetBoxTreeWidget: A tree of categories + +class WidgetBoxTreeWidget : public QTreeWidget +{ + Q_OBJECT + +public: + typedef QDesignerWidgetBoxInterface::Widget Widget; + typedef QDesignerWidgetBoxInterface::Category Category; + typedef QDesignerWidgetBoxInterface::CategoryList CategoryList; + + explicit WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~WidgetBoxTreeWidget(); + + int categoryCount() const; + Category category(int cat_idx) const; + void addCategory(const Category &cat); + void removeCategory(int cat_idx); + + int widgetCount(int cat_idx) const; + Widget widget(int cat_idx, int wgt_idx) const; + void addWidget(int cat_idx, const Widget &wgt); + void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list); + + void setFileName(const QString &file_name); + QString fileName() const; + bool load(QDesignerWidgetBox::LoadMode loadMode); + bool loadContents(const QString &contents); + bool save(); + QIcon iconForWidget(QString iconName) const; + +signals: + void pressed(const QString name, const QString dom_xml, const QPoint &global_mouse_pos); + +public slots: + void filter(const QString &); + +protected: + void contextMenuEvent(QContextMenuEvent *e); + void resizeEvent(QResizeEvent *e); + +private slots: + void slotSave(); + void slotScratchPadItemDeleted(); + void slotLastScratchPadItemDeleted(); + + void handleMousePress(QTreeWidgetItem *item); + void deleteScratchpad(); + void slotListMode(); + void slotIconMode(); + +private: + WidgetBoxCategoryListView *addCategoryView(QTreeWidgetItem *parent, bool iconMode); + WidgetBoxCategoryListView *categoryViewAt(int idx) const; + void adjustSubListSize(QTreeWidgetItem *cat_item); + + static bool readCategories(const QString &fileName, const QString &xml, CategoryList *cats, QString *errorMessage); + static bool readWidget(Widget *w, const QString &xml, QXmlStreamReader &r); + + CategoryList loadCustomCategoryList() const; + void writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const; + + int indexOfCategory(const QString &name) const; + int indexOfScratchpad() const; + int ensureScratchpad(); + void addCustomCategories(bool replace); + + void saveExpandedState() const; + void restoreExpandedState(); + void updateViewMode(); + + QDesignerFormEditorInterface *m_core; + QString m_file_name; + typedef QHash<QString, QIcon> IconCache; + mutable IconCache m_pluginIcons; + bool m_iconMode; + QTimer *m_scratchPadDeleteTimer; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXTREEWIDGET_H |