/tools/designer/src/components/widgetbox/widgetboxtreewidget.cpp
C++ | 1001 lines | 766 code | 127 blank | 108 comment | 161 complexity | a24f7e699f9ebe07b60c7c5c5e03f261 MD5 | raw file
- /****************************************************************************
- **
- ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the Qt Designer of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:LGPL$
- ** GNU Lesser General Public License Usage
- ** This file may be used under the terms of the GNU Lesser General Public
- ** License version 2.1 as published by the Free Software Foundation and
- ** appearing in the file LICENSE.LGPL included in the packaging of this
- ** file. Please review the following information to ensure the GNU Lesser
- ** General Public License version 2.1 requirements will be met:
- ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- **
- ** In addition, as a special exception, Nokia gives you certain additional
- ** rights. These rights are described in the Nokia Qt LGPL Exception
- ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
- **
- ** GNU General Public License Usage
- ** Alternatively, this file may be used under the terms of the GNU General
- ** Public License version 3.0 as published by the Free Software Foundation
- ** and appearing in the file LICENSE.GPL included in the packaging of this
- ** file. Please review the following information to ensure the GNU General
- ** Public License version 3.0 requirements will be met:
- ** http://www.gnu.org/copyleft/gpl.html.
- **
- ** Other Usage
- ** Alternatively, this file may be used in accordance with the terms and
- ** conditions contained in a signed written agreement between you and Nokia.
- **
- **
- **
- **
- **
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
- #include "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);
- if (embedItem == 0)
- return;
- 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