0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the Qt Designer of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
#include "widgetboxtreewidget.h"
|
|
43 |
#include "widgetboxcategorylistview.h"
|
|
44 |
|
|
45 |
// shared
|
|
46 |
#include <iconloader_p.h>
|
|
47 |
#include <sheet_delegate_p.h>
|
|
48 |
#include <QtDesigner/private/abstractsettings_p.h>
|
|
49 |
#include <ui4_p.h>
|
|
50 |
#include <qdesigner_utils_p.h>
|
|
51 |
#include <pluginmanager_p.h>
|
|
52 |
|
|
53 |
// sdk
|
|
54 |
#include <QtDesigner/QDesignerFormEditorInterface>
|
|
55 |
#include <QtDesigner/QDesignerDnDItemInterface>
|
|
56 |
#include <QtDesigner/QDesignerCustomWidgetInterface>
|
|
57 |
#include <QtDesigner/private/abstractsettings_p.h>
|
|
58 |
|
|
59 |
#include <QtGui/QHeaderView>
|
|
60 |
#include <QtGui/QApplication>
|
|
61 |
#include <QtGui/QTreeWidgetItem>
|
|
62 |
#include <QtGui/QContextMenuEvent>
|
|
63 |
#include <QtGui/QAction>
|
|
64 |
#include <QtGui/QActionGroup>
|
|
65 |
#include <QtGui/QMenu>
|
|
66 |
|
|
67 |
#include <QtCore/QFile>
|
|
68 |
#include <QtCore/QTimer>
|
|
69 |
#include <QtCore/QDebug>
|
|
70 |
|
|
71 |
static const char *widgetBoxRootElementC = "widgetbox";
|
|
72 |
static const char *widgetElementC = "widget";
|
|
73 |
static const char *uiElementC = "ui";
|
|
74 |
static const char *categoryElementC = "category";
|
|
75 |
static const char *categoryEntryElementC = "categoryentry";
|
|
76 |
static const char *nameAttributeC = "name";
|
|
77 |
static const char *typeAttributeC = "type";
|
|
78 |
static const char *iconAttributeC = "icon";
|
|
79 |
static const char *defaultTypeValueC = "default";
|
|
80 |
static const char *customValueC = "custom";
|
|
81 |
static const char *iconPrefixC = "__qt_icon__";
|
|
82 |
static const char *scratchPadValueC = "scratchpad";
|
|
83 |
static const char *qtLogoC = "qtlogo.png";
|
|
84 |
static const char *invisibleNameC = "[invisible]";
|
|
85 |
|
|
86 |
enum TopLevelRole { NORMAL_ITEM, SCRATCHPAD_ITEM, CUSTOM_ITEM };
|
|
87 |
|
|
88 |
QT_BEGIN_NAMESPACE
|
|
89 |
|
|
90 |
static void setTopLevelRole(TopLevelRole tlr, QTreeWidgetItem *item)
|
|
91 |
{
|
|
92 |
item->setData(0, Qt::UserRole, QVariant(tlr));
|
|
93 |
}
|
|
94 |
|
|
95 |
static TopLevelRole topLevelRole(const QTreeWidgetItem *item)
|
|
96 |
{
|
|
97 |
return static_cast<TopLevelRole>(item->data(0, Qt::UserRole).toInt());
|
|
98 |
}
|
|
99 |
|
|
100 |
namespace qdesigner_internal {
|
|
101 |
|
|
102 |
WidgetBoxTreeWidget::WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent) :
|
|
103 |
QTreeWidget(parent),
|
|
104 |
m_core(core),
|
|
105 |
m_iconMode(false),
|
|
106 |
m_scratchPadDeleteTimer(0)
|
|
107 |
{
|
|
108 |
setFocusPolicy(Qt::NoFocus);
|
|
109 |
setIndentation(0);
|
|
110 |
setRootIsDecorated(false);
|
|
111 |
setColumnCount(1);
|
|
112 |
header()->hide();
|
|
113 |
header()->setResizeMode(QHeaderView::Stretch);
|
|
114 |
setTextElideMode(Qt::ElideMiddle);
|
|
115 |
setVerticalScrollMode(ScrollPerPixel);
|
|
116 |
|
|
117 |
setItemDelegate(new SheetDelegate(this, this));
|
|
118 |
|
|
119 |
connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)),
|
|
120 |
this, SLOT(handleMousePress(QTreeWidgetItem*)));
|
|
121 |
}
|
|
122 |
|
|
123 |
QIcon WidgetBoxTreeWidget::iconForWidget(QString iconName) const
|
|
124 |
{
|
|
125 |
if (iconName.isEmpty())
|
|
126 |
iconName = QLatin1String(qtLogoC);
|
|
127 |
|
|
128 |
if (iconName.startsWith(QLatin1String(iconPrefixC))) {
|
|
129 |
const IconCache::const_iterator it = m_pluginIcons.constFind(iconName);
|
|
130 |
if (it != m_pluginIcons.constEnd())
|
|
131 |
return it.value();
|
|
132 |
}
|
|
133 |
return createIconSet(iconName);
|
|
134 |
}
|
|
135 |
|
|
136 |
WidgetBoxCategoryListView *WidgetBoxTreeWidget::categoryViewAt(int idx) const
|
|
137 |
{
|
|
138 |
WidgetBoxCategoryListView *rc = 0;
|
|
139 |
if (QTreeWidgetItem *cat_item = topLevelItem(idx))
|
|
140 |
if (QTreeWidgetItem *embedItem = cat_item->child(0))
|
|
141 |
rc = qobject_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0));
|
|
142 |
Q_ASSERT(rc);
|
|
143 |
return rc;
|
|
144 |
}
|
|
145 |
|
|
146 |
void WidgetBoxTreeWidget::saveExpandedState() const
|
|
147 |
{
|
|
148 |
QStringList closedCategories;
|
|
149 |
if (const int numCategories = categoryCount()) {
|
|
150 |
for (int i = 0; i < numCategories; ++i) {
|
|
151 |
const QTreeWidgetItem *cat_item = topLevelItem(i);
|
|
152 |
if (!isItemExpanded(cat_item))
|
|
153 |
closedCategories.append(cat_item->text(0));
|
|
154 |
}
|
|
155 |
}
|
|
156 |
QDesignerSettingsInterface *settings = m_core->settingsManager();
|
|
157 |
settings->beginGroup(QLatin1String(widgetBoxRootElementC));
|
|
158 |
settings->setValue(QLatin1String("Closed categories"), closedCategories);
|
|
159 |
settings->setValue(QLatin1String("View mode"), m_iconMode);
|
|
160 |
settings->endGroup();
|
|
161 |
}
|
|
162 |
|
|
163 |
void WidgetBoxTreeWidget::restoreExpandedState()
|
|
164 |
{
|
|
165 |
typedef QSet<QString> StringSet;
|
|
166 |
QDesignerSettingsInterface *settings = m_core->settingsManager();
|
|
167 |
m_iconMode = settings->value(QLatin1String("WidgetBox/View mode")).toBool();
|
|
168 |
updateViewMode();
|
|
169 |
const StringSet closedCategories = settings->value(QLatin1String("WidgetBox/Closed categories"), QStringList()).toStringList().toSet();
|
|
170 |
expandAll();
|
|
171 |
if (closedCategories.empty())
|
|
172 |
return;
|
|
173 |
|
|
174 |
if (const int numCategories = categoryCount()) {
|
|
175 |
for (int i = 0; i < numCategories; ++i) {
|
|
176 |
QTreeWidgetItem *item = topLevelItem(i);
|
|
177 |
if (closedCategories.contains(item->text(0)))
|
|
178 |
item->setExpanded(false);
|
|
179 |
}
|
|
180 |
}
|
|
181 |
}
|
|
182 |
|
|
183 |
WidgetBoxTreeWidget::~WidgetBoxTreeWidget()
|
|
184 |
{
|
|
185 |
saveExpandedState();
|
|
186 |
}
|
|
187 |
|
|
188 |
void WidgetBoxTreeWidget::setFileName(const QString &file_name)
|
|
189 |
{
|
|
190 |
m_file_name = file_name;
|
|
191 |
}
|
|
192 |
|
|
193 |
QString WidgetBoxTreeWidget::fileName() const
|
|
194 |
{
|
|
195 |
return m_file_name;
|
|
196 |
}
|
|
197 |
|
|
198 |
bool WidgetBoxTreeWidget::save()
|
|
199 |
{
|
|
200 |
if (fileName().isEmpty())
|
|
201 |
return false;
|
|
202 |
|
|
203 |
QFile file(fileName());
|
|
204 |
if (!file.open(QIODevice::WriteOnly))
|
|
205 |
return false;
|
|
206 |
|
|
207 |
CategoryList cat_list;
|
|
208 |
const int count = categoryCount();
|
|
209 |
for (int i = 0; i < count; ++i)
|
|
210 |
cat_list.append(category(i));
|
|
211 |
|
|
212 |
QXmlStreamWriter writer(&file);
|
|
213 |
writer.setAutoFormatting(true);
|
|
214 |
writer.setAutoFormattingIndent(1);
|
|
215 |
writer.writeStartDocument();
|
|
216 |
writeCategories(writer, cat_list);
|
|
217 |
writer.writeEndDocument();
|
|
218 |
|
|
219 |
return true;
|
|
220 |
}
|
|
221 |
|
|
222 |
void WidgetBoxTreeWidget::slotSave()
|
|
223 |
{
|
|
224 |
save();
|
|
225 |
}
|
|
226 |
|
|
227 |
void WidgetBoxTreeWidget::handleMousePress(QTreeWidgetItem *item)
|
|
228 |
{
|
|
229 |
if (item == 0)
|
|
230 |
return;
|
|
231 |
|
|
232 |
if (QApplication::mouseButtons() != Qt::LeftButton)
|
|
233 |
return;
|
|
234 |
|
|
235 |
if (item->parent() == 0) {
|
|
236 |
setItemExpanded(item, !isItemExpanded(item));
|
|
237 |
return;
|
|
238 |
}
|
|
239 |
}
|
|
240 |
|
|
241 |
int WidgetBoxTreeWidget::ensureScratchpad()
|
|
242 |
{
|
|
243 |
const int existingIndex = indexOfScratchpad();
|
|
244 |
if (existingIndex != -1)
|
|
245 |
return existingIndex;
|
|
246 |
|
|
247 |
QTreeWidgetItem *scratch_item = new QTreeWidgetItem(this);
|
|
248 |
scratch_item->setText(0, tr("Scratchpad"));
|
|
249 |
setTopLevelRole(SCRATCHPAD_ITEM, scratch_item);
|
|
250 |
addCategoryView(scratch_item, false); // Scratchpad in list mode.
|
|
251 |
return categoryCount() - 1;
|
|
252 |
}
|
|
253 |
|
|
254 |
WidgetBoxCategoryListView *WidgetBoxTreeWidget::addCategoryView(QTreeWidgetItem *parent, bool iconMode)
|
|
255 |
{
|
|
256 |
QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent);
|
|
257 |
embed_item->setFlags(Qt::ItemIsEnabled);
|
|
258 |
WidgetBoxCategoryListView *categoryView = new WidgetBoxCategoryListView(m_core, this);
|
|
259 |
categoryView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode);
|
|
260 |
connect(categoryView, SIGNAL(scratchPadChanged()), this, SLOT(slotSave()));
|
|
261 |
connect(categoryView, SIGNAL(pressed(QString,QString,QPoint)), this, SIGNAL(pressed(QString,QString,QPoint)));
|
|
262 |
connect(categoryView, SIGNAL(itemRemoved()), this, SLOT(slotScratchPadItemDeleted()));
|
|
263 |
connect(categoryView, SIGNAL(lastItemRemoved()), this, SLOT(slotLastScratchPadItemDeleted()));
|
|
264 |
setItemWidget(embed_item, 0, categoryView);
|
|
265 |
return categoryView;
|
|
266 |
}
|
|
267 |
|
|
268 |
int WidgetBoxTreeWidget::indexOfScratchpad() const
|
|
269 |
{
|
|
270 |
if (const int numTopLevels = topLevelItemCount()) {
|
|
271 |
for (int i = numTopLevels - 1; i >= 0; --i) {
|
|
272 |
if (topLevelRole(topLevelItem(i)) == SCRATCHPAD_ITEM)
|
|
273 |
return i;
|
|
274 |
}
|
|
275 |
}
|
|
276 |
return -1;
|
|
277 |
}
|
|
278 |
|
|
279 |
int WidgetBoxTreeWidget::indexOfCategory(const QString &name) const
|
|
280 |
{
|
|
281 |
const int topLevelCount = topLevelItemCount();
|
|
282 |
for (int i = 0; i < topLevelCount; ++i) {
|
|
283 |
if (topLevelItem(i)->text(0) == name)
|
|
284 |
return i;
|
|
285 |
}
|
|
286 |
return -1;
|
|
287 |
}
|
|
288 |
|
|
289 |
bool WidgetBoxTreeWidget::load(QDesignerWidgetBox::LoadMode loadMode)
|
|
290 |
{
|
|
291 |
switch (loadMode) {
|
|
292 |
case QDesignerWidgetBox::LoadReplace:
|
|
293 |
clear();
|
|
294 |
break;
|
|
295 |
case QDesignerWidgetBox::LoadCustomWidgetsOnly:
|
|
296 |
addCustomCategories(true);
|
|
297 |
updateGeometries();
|
|
298 |
return true;
|
|
299 |
default:
|
|
300 |
break;
|
|
301 |
}
|
|
302 |
|
|
303 |
const QString name = fileName();
|
|
304 |
|
|
305 |
QFile f(name);
|
|
306 |
if (!f.open(QIODevice::ReadOnly)) // Might not exist at first startup
|
|
307 |
return false;
|
|
308 |
|
|
309 |
const QString contents = QString::fromUtf8(f.readAll());
|
|
310 |
return loadContents(contents);
|
|
311 |
}
|
|
312 |
|
|
313 |
bool WidgetBoxTreeWidget::loadContents(const QString &contents)
|
|
314 |
{
|
|
315 |
QString errorMessage;
|
|
316 |
CategoryList cat_list;
|
|
317 |
if (!readCategories(m_file_name, contents, &cat_list, &errorMessage)) {
|
|
318 |
qdesigner_internal::designerWarning(errorMessage);
|
|
319 |
return false;
|
|
320 |
}
|
|
321 |
|
|
322 |
foreach(const Category &cat, cat_list)
|
|
323 |
addCategory(cat);
|
|
324 |
|
|
325 |
addCustomCategories(false);
|
|
326 |
// Restore which items are expanded
|
|
327 |
restoreExpandedState();
|
|
328 |
return true;
|
|
329 |
}
|
|
330 |
|
|
331 |
void WidgetBoxTreeWidget::addCustomCategories(bool replace)
|
|
332 |
{
|
|
333 |
if (replace) {
|
|
334 |
// clear out all existing custom widgets
|
|
335 |
if (const int numTopLevels = topLevelItemCount()) {
|
|
336 |
for (int t = 0; t < numTopLevels ; ++t)
|
|
337 |
categoryViewAt(t)->removeCustomWidgets();
|
|
338 |
}
|
|
339 |
}
|
|
340 |
// re-add
|
|
341 |
const CategoryList customList = loadCustomCategoryList();
|
|
342 |
const CategoryList::const_iterator cend = customList.constEnd();
|
|
343 |
for (CategoryList::const_iterator it = customList.constBegin(); it != cend; ++it)
|
|
344 |
addCategory(*it);
|
|
345 |
}
|
|
346 |
|
|
347 |
static inline QString msgXmlError(const QString &fileName, const QXmlStreamReader &r)
|
|
348 |
{
|
|
349 |
return QDesignerWidgetBox::tr("An error has been encountered at line %1 of %2: %3")
|
|
350 |
.arg(r.lineNumber()).arg(fileName, r.errorString());
|
|
351 |
}
|
|
352 |
|
|
353 |
bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString &contents,
|
|
354 |
CategoryList *cats, QString *errorMessage)
|
|
355 |
{
|
|
356 |
// Read widget box XML:
|
|
357 |
//
|
|
358 |
//<widgetbox version="4.5">
|
|
359 |
// <category name="Layouts">
|
|
360 |
// <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default">
|
|
361 |
// <widget class="QListWidget" ...>
|
|
362 |
// ...
|
|
363 |
|
|
364 |
QXmlStreamReader reader(contents);
|
|
365 |
|
|
366 |
|
|
367 |
// Entries of category with name="invisible" should be ignored
|
|
368 |
bool ignoreEntries = false;
|
|
369 |
|
|
370 |
while (!reader.atEnd()) {
|
|
371 |
switch (reader.readNext()) {
|
|
372 |
case QXmlStreamReader::StartElement: {
|
|
373 |
const QStringRef tag = reader.name();
|
|
374 |
if (tag == QLatin1String(widgetBoxRootElementC)) {
|
|
375 |
//<widgetbox version="4.5">
|
|
376 |
continue;
|
|
377 |
}
|
|
378 |
if (tag == QLatin1String(categoryElementC)) {
|
|
379 |
// <category name="Layouts">
|
|
380 |
const QXmlStreamAttributes attributes = reader.attributes();
|
|
381 |
const QString categoryName = attributes.value(QLatin1String(nameAttributeC)).toString();
|
|
382 |
if (categoryName == QLatin1String(invisibleNameC)) {
|
|
383 |
ignoreEntries = true;
|
|
384 |
} else {
|
|
385 |
Category category(categoryName);
|
|
386 |
if (attributes.value(QLatin1String(typeAttributeC)) == QLatin1String(scratchPadValueC))
|
|
387 |
category.setType(Category::Scratchpad);
|
|
388 |
cats->push_back(category);
|
|
389 |
}
|
|
390 |
continue;
|
|
391 |
}
|
|
392 |
if (tag == QLatin1String(categoryEntryElementC)) {
|
|
393 |
// <categoryentry name="Vertical Layout" icon="win/editvlayout.png" type="default">
|
|
394 |
if (!ignoreEntries) {
|
|
395 |
QXmlStreamAttributes attr = reader.attributes();
|
|
396 |
const QString widgetName = attr.value(QLatin1String(nameAttributeC)).toString();
|
|
397 |
const QString widgetIcon = attr.value(QLatin1String(iconAttributeC)).toString();
|
|
398 |
const WidgetBoxTreeWidget::Widget::Type widgetType =
|
|
399 |
attr.value(QLatin1String(typeAttributeC)).toString()
|
|
400 |
== QLatin1String(customValueC) ?
|
|
401 |
WidgetBoxTreeWidget::Widget::Custom :
|
|
402 |
WidgetBoxTreeWidget::Widget::Default;
|
|
403 |
|
|
404 |
Widget w;
|
|
405 |
w.setName(widgetName);
|
|
406 |
w.setIconName(widgetIcon);
|
|
407 |
w.setType(widgetType);
|
|
408 |
if (!readWidget(&w, contents, reader))
|
|
409 |
continue;
|
|
410 |
|
|
411 |
cats->back().addWidget(w);
|
|
412 |
} // ignoreEntries
|
|
413 |
continue;
|
|
414 |
}
|
|
415 |
break;
|
|
416 |
}
|
|
417 |
case QXmlStreamReader::EndElement: {
|
|
418 |
const QStringRef tag = reader.name();
|
|
419 |
if (tag == QLatin1String(widgetBoxRootElementC)) {
|
|
420 |
continue;
|
|
421 |
}
|
|
422 |
if (tag == QLatin1String(categoryElementC)) {
|
|
423 |
ignoreEntries = false;
|
|
424 |
continue;
|
|
425 |
}
|
|
426 |
if (tag == QLatin1String(categoryEntryElementC)) {
|
|
427 |
continue;
|
|
428 |
}
|
|
429 |
break;
|
|
430 |
}
|
|
431 |
default: break;
|
|
432 |
}
|
|
433 |
}
|
|
434 |
|
|
435 |
if (reader.hasError()) {
|
|
436 |
*errorMessage = msgXmlError(fileName, reader);
|
|
437 |
return false;
|
|
438 |
}
|
|
439 |
|
|
440 |
return true;
|
|
441 |
}
|
|
442 |
|
|
443 |
/*!
|
|
444 |
* Read out a widget within a category. This can either be
|
|
445 |
* enclosed in a <ui> element or a (legacy) <widget> element which may
|
|
446 |
* contain nested <widget> elements.
|
|
447 |
*
|
|
448 |
* Examples:
|
|
449 |
*
|
|
450 |
* <ui language="c++">
|
|
451 |
* <widget class="MultiPageWidget" name="multipagewidget"> ... </widget>
|
|
452 |
* <customwidgets>...</customwidgets>
|
|
453 |
* <ui>
|
|
454 |
*
|
|
455 |
* or
|
|
456 |
*
|
|
457 |
* <widget>
|
|
458 |
* <widget> ... </widget>
|
|
459 |
* ...
|
|
460 |
* <widget>
|
|
461 |
*
|
|
462 |
* Returns true on success, false if end was reached or an error has been encountered
|
|
463 |
* in which case the reader has its error flag set. If successful, the current item
|
|
464 |
* of the reader will be the closing element (</ui> or </widget>)
|
|
465 |
*/
|
|
466 |
bool WidgetBoxTreeWidget::readWidget(Widget *w, const QString &xml, QXmlStreamReader &r)
|
|
467 |
{
|
|
468 |
qint64 startTagPosition =0, endTagPosition = 0;
|
|
469 |
|
|
470 |
int nesting = 0;
|
|
471 |
bool endEncountered = false;
|
|
472 |
bool parsedWidgetTag = false;
|
|
473 |
QString outmostElement;
|
|
474 |
while (!endEncountered) {
|
|
475 |
const qint64 currentPosition = r.characterOffset();
|
|
476 |
switch(r.readNext()) {
|
|
477 |
case QXmlStreamReader::StartElement:
|
|
478 |
if (nesting++ == 0) {
|
|
479 |
// First element must be <ui> or (legacy) <widget>
|
|
480 |
const QStringRef name = r.name();
|
|
481 |
if (name == QLatin1String(uiElementC)) {
|
|
482 |
startTagPosition = currentPosition;
|
|
483 |
} else {
|
|
484 |
if (name == QLatin1String(widgetElementC)) {
|
|
485 |
startTagPosition = currentPosition;
|
|
486 |
parsedWidgetTag = true;
|
|
487 |
} else {
|
|
488 |
r.raiseError(QDesignerWidgetBox::tr("Unexpected element <%1> encountered when parsing for <widget> or <ui>").arg(name.toString()));
|
|
489 |
return false;
|
|
490 |
}
|
|
491 |
}
|
|
492 |
} else {
|
|
493 |
// We are within <ui> looking for the first <widget> tag
|
|
494 |
if (!parsedWidgetTag && r.name() == QLatin1String(widgetElementC)) {
|
|
495 |
parsedWidgetTag = true;
|
|
496 |
}
|
|
497 |
}
|
|
498 |
break;
|
|
499 |
case QXmlStreamReader::EndElement:
|
|
500 |
// Reached end of widget?
|
|
501 |
if (--nesting == 0) {
|
|
502 |
endTagPosition = r.characterOffset();
|
|
503 |
endEncountered = true;
|
|
504 |
}
|
|
505 |
break;
|
|
506 |
case QXmlStreamReader::EndDocument:
|
|
507 |
r.raiseError(QDesignerWidgetBox::tr("Unexpected end of file encountered when parsing widgets."));
|
|
508 |
return false;
|
|
509 |
case QXmlStreamReader::Invalid:
|
|
510 |
return false;
|
|
511 |
default:
|
|
512 |
break;
|
|
513 |
}
|
|
514 |
}
|
|
515 |
if (!parsedWidgetTag) {
|
|
516 |
r.raiseError(QDesignerWidgetBox::tr("A widget element could not be found."));
|
|
517 |
return false;
|
|
518 |
}
|
|
519 |
// Oddity: Startposition is 1 off
|
|
520 |
QString widgetXml = xml.mid(startTagPosition, endTagPosition - startTagPosition);
|
|
521 |
const QChar lessThan = QLatin1Char('<');
|
|
522 |
if (!widgetXml.startsWith(lessThan))
|
|
523 |
widgetXml.prepend(lessThan);
|
|
524 |
w->setDomXml(widgetXml);
|
|
525 |
return true;
|
|
526 |
}
|
|
527 |
|
|
528 |
void WidgetBoxTreeWidget::writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const
|
|
529 |
{
|
|
530 |
const QString widgetbox = QLatin1String(widgetBoxRootElementC);
|
|
531 |
const QString name = QLatin1String(nameAttributeC);
|
|
532 |
const QString type = QLatin1String(typeAttributeC);
|
|
533 |
const QString icon = QLatin1String(iconAttributeC);
|
|
534 |
const QString defaultType = QLatin1String(defaultTypeValueC);
|
|
535 |
const QString category = QLatin1String(categoryElementC);
|
|
536 |
const QString categoryEntry = QLatin1String(categoryEntryElementC);
|
|
537 |
const QString iconPrefix = QLatin1String(iconPrefixC);
|
|
538 |
const QString widgetTag = QLatin1String(widgetElementC);
|
|
539 |
|
|
540 |
//
|
|
541 |
// <widgetbox>
|
|
542 |
// <category name="Layouts">
|
|
543 |
// <categoryEntry name="Vertical Layout" type="default" icon="win/editvlayout.png">
|
|
544 |
// <ui>
|
|
545 |
// ...
|
|
546 |
// </ui>
|
|
547 |
// </categoryEntry>
|
|
548 |
// ...
|
|
549 |
// </category>
|
|
550 |
// ...
|
|
551 |
// </widgetbox>
|
|
552 |
//
|
|
553 |
|
|
554 |
writer.writeStartElement(widgetbox);
|
|
555 |
|
|
556 |
foreach (const Category &cat, cat_list) {
|
|
557 |
writer.writeStartElement(category);
|
|
558 |
writer.writeAttribute(name, cat.name());
|
|
559 |
if (cat.type() == Category::Scratchpad)
|
|
560 |
writer.writeAttribute(type, QLatin1String(scratchPadValueC));
|
|
561 |
|
|
562 |
const int widgetCount = cat.widgetCount();
|
|
563 |
for (int i = 0; i < widgetCount; ++i) {
|
|
564 |
const Widget wgt = cat.widget(i);
|
|
565 |
if (wgt.type() == Widget::Custom)
|
|
566 |
continue;
|
|
567 |
|
|
568 |
writer.writeStartElement(categoryEntry);
|
|
569 |
writer.writeAttribute(name, wgt.name());
|
|
570 |
if (!wgt.iconName().startsWith(iconPrefix))
|
|
571 |
writer.writeAttribute(icon, wgt.iconName());
|
|
572 |
writer.writeAttribute(type, defaultType);
|
|
573 |
|
|
574 |
const DomUI *domUI = QDesignerWidgetBox::xmlToUi(wgt.name(), WidgetBoxCategoryListView::widgetDomXml(wgt), false);
|
|
575 |
if (domUI) {
|
|
576 |
domUI->write(writer);
|
|
577 |
delete domUI;
|
|
578 |
}
|
|
579 |
|
|
580 |
writer.writeEndElement(); // categoryEntry
|
|
581 |
}
|
|
582 |
writer.writeEndElement(); // categoryEntry
|
|
583 |
}
|
|
584 |
|
|
585 |
writer.writeEndElement(); // widgetBox
|
|
586 |
}
|
|
587 |
|
|
588 |
static int findCategory(const QString &name, const WidgetBoxTreeWidget::CategoryList &list)
|
|
589 |
{
|
|
590 |
int idx = 0;
|
|
591 |
foreach (const WidgetBoxTreeWidget::Category &cat, list) {
|
|
592 |
if (cat.name() == name)
|
|
593 |
return idx;
|
|
594 |
++idx;
|
|
595 |
}
|
|
596 |
return -1;
|
|
597 |
}
|
|
598 |
|
|
599 |
static inline bool isValidIcon(const QIcon &icon)
|
|
600 |
{
|
|
601 |
if (!icon.isNull()) {
|
|
602 |
const QList<QSize> availableSizes = icon.availableSizes();
|
|
603 |
if (!availableSizes.empty())
|
|
604 |
return !availableSizes.front().isEmpty();
|
|
605 |
}
|
|
606 |
return false;
|
|
607 |
}
|
|
608 |
|
|
609 |
WidgetBoxTreeWidget::CategoryList WidgetBoxTreeWidget::loadCustomCategoryList() const
|
|
610 |
{
|
|
611 |
CategoryList result;
|
|
612 |
|
|
613 |
const QDesignerPluginManager *pm = m_core->pluginManager();
|
|
614 |
const QDesignerPluginManager::CustomWidgetList customWidgets = pm->registeredCustomWidgets();
|
|
615 |
if (customWidgets.empty())
|
|
616 |
return result;
|
|
617 |
|
|
618 |
static const QString customCatName = tr("Custom Widgets");
|
|
619 |
|
|
620 |
const QString invisible = QLatin1String(invisibleNameC);
|
|
621 |
const QString iconPrefix = QLatin1String(iconPrefixC);
|
|
622 |
|
|
623 |
foreach(QDesignerCustomWidgetInterface *c, customWidgets) {
|
|
624 |
const QString dom_xml = c->domXml();
|
|
625 |
if (dom_xml.isEmpty())
|
|
626 |
continue;
|
|
627 |
|
|
628 |
const QString pluginName = c->name();
|
|
629 |
const QDesignerCustomWidgetData data = pm->customWidgetData(c);
|
|
630 |
QString displayName = data.xmlDisplayName();
|
|
631 |
if (displayName.isEmpty())
|
|
632 |
displayName = pluginName;
|
|
633 |
|
|
634 |
QString cat_name = c->group();
|
|
635 |
if (cat_name.isEmpty())
|
|
636 |
cat_name = customCatName;
|
|
637 |
else if (cat_name == invisible)
|
|
638 |
continue;
|
|
639 |
|
|
640 |
int idx = findCategory(cat_name, result);
|
|
641 |
if (idx == -1) {
|
|
642 |
result.append(Category(cat_name));
|
|
643 |
idx = result.size() - 1;
|
|
644 |
}
|
|
645 |
Category &cat = result[idx];
|
|
646 |
|
|
647 |
const QIcon icon = c->icon();
|
|
648 |
|
|
649 |
QString icon_name;
|
|
650 |
if (isValidIcon(icon)) {
|
|
651 |
icon_name = iconPrefix;
|
|
652 |
icon_name += pluginName;
|
|
653 |
m_pluginIcons.insert(icon_name, icon);
|
|
654 |
} else {
|
|
655 |
icon_name = QLatin1String(qtLogoC);
|
|
656 |
}
|
|
657 |
|
|
658 |
cat.addWidget(Widget(displayName, dom_xml, icon_name, Widget::Custom));
|
|
659 |
}
|
|
660 |
|
|
661 |
return result;
|
|
662 |
}
|
|
663 |
|
|
664 |
void WidgetBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item)
|
|
665 |
{
|
|
666 |
QTreeWidgetItem *embedItem = cat_item->child(0);
|
|
667 |
if (embedItem == 0)
|
|
668 |
return;
|
|
669 |
|
|
670 |
WidgetBoxCategoryListView *list_widget = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0));
|
|
671 |
list_widget->setFixedWidth(header()->width());
|
|
672 |
list_widget->doItemsLayout();
|
|
673 |
const int height = qMax(list_widget->contentsSize().height() ,1);
|
|
674 |
list_widget->setFixedHeight(height);
|
|
675 |
embedItem->setSizeHint(0, QSize(-1, height - 1));
|
|
676 |
}
|
|
677 |
|
|
678 |
int WidgetBoxTreeWidget::categoryCount() const
|
|
679 |
{
|
|
680 |
return topLevelItemCount();
|
|
681 |
}
|
|
682 |
|
|
683 |
WidgetBoxTreeWidget::Category WidgetBoxTreeWidget::category(int cat_idx) const
|
|
684 |
{
|
|
685 |
if (cat_idx >= topLevelItemCount())
|
|
686 |
return Category();
|
|
687 |
|
|
688 |
QTreeWidgetItem *cat_item = topLevelItem(cat_idx);
|
|
689 |
|
|
690 |
QTreeWidgetItem *embedItem = cat_item->child(0);
|
|
691 |
WidgetBoxCategoryListView *categoryView = static_cast<WidgetBoxCategoryListView*>(itemWidget(embedItem, 0));
|
|
692 |
|
|
693 |
Category result = categoryView->category();
|
|
694 |
result.setName(cat_item->text(0));
|
|
695 |
|
|
696 |
switch (topLevelRole(cat_item)) {
|
|
697 |
case SCRATCHPAD_ITEM:
|
|
698 |
result.setType(Category::Scratchpad);
|
|
699 |
break;
|
|
700 |
default:
|
|
701 |
result.setType(Category::Default);
|
|
702 |
break;
|
|
703 |
}
|
|
704 |
return result;
|
|
705 |
}
|
|
706 |
|
|
707 |
void WidgetBoxTreeWidget::addCategory(const Category &cat)
|
|
708 |
{
|
|
709 |
if (cat.widgetCount() == 0)
|
|
710 |
return;
|
|
711 |
|
|
712 |
const bool isScratchPad = cat.type() == Category::Scratchpad;
|
|
713 |
WidgetBoxCategoryListView *categoryView;
|
|
714 |
QTreeWidgetItem *cat_item;
|
|
715 |
|
|
716 |
if (isScratchPad) {
|
|
717 |
const int idx = ensureScratchpad();
|
|
718 |
categoryView = categoryViewAt(idx);
|
|
719 |
cat_item = topLevelItem(idx);
|
|
720 |
} else {
|
|
721 |
const int existingIndex = indexOfCategory(cat.name());
|
|
722 |
if (existingIndex == -1) {
|
|
723 |
cat_item = new QTreeWidgetItem();
|
|
724 |
cat_item->setText(0, cat.name());
|
|
725 |
setTopLevelRole(NORMAL_ITEM, cat_item);
|
|
726 |
// insert before scratchpad
|
|
727 |
const int scratchPadIndex = indexOfScratchpad();
|
|
728 |
if (scratchPadIndex == -1) {
|
|
729 |
addTopLevelItem(cat_item);
|
|
730 |
} else {
|
|
731 |
insertTopLevelItem(scratchPadIndex, cat_item);
|
|
732 |
}
|
|
733 |
setItemExpanded(cat_item, true);
|
|
734 |
categoryView = addCategoryView(cat_item, m_iconMode);
|
|
735 |
} else {
|
|
736 |
categoryView = categoryViewAt(existingIndex);
|
|
737 |
cat_item = topLevelItem(existingIndex);
|
|
738 |
}
|
|
739 |
}
|
|
740 |
// The same categories are read from the file $HOME, avoid duplicates
|
|
741 |
const int widgetCount = cat.widgetCount();
|
|
742 |
for (int i = 0; i < widgetCount; ++i) {
|
|
743 |
const Widget w = cat.widget(i);
|
|
744 |
if (!categoryView->containsWidget(w.name()))
|
|
745 |
categoryView->addWidget(w, iconForWidget(w.iconName()), isScratchPad);
|
|
746 |
}
|
|
747 |
adjustSubListSize(cat_item);
|
|
748 |
}
|
|
749 |
|
|
750 |
void WidgetBoxTreeWidget::removeCategory(int cat_idx)
|
|
751 |
{
|
|
752 |
if (cat_idx >= topLevelItemCount())
|
|
753 |
return;
|
|
754 |
delete takeTopLevelItem(cat_idx);
|
|
755 |
}
|
|
756 |
|
|
757 |
int WidgetBoxTreeWidget::widgetCount(int cat_idx) const
|
|
758 |
{
|
|
759 |
if (cat_idx >= topLevelItemCount())
|
|
760 |
return 0;
|
|
761 |
// SDK functions want unfiltered access
|
|
762 |
return categoryViewAt(cat_idx)->count(WidgetBoxCategoryListView::UnfilteredAccess);
|
|
763 |
}
|
|
764 |
|
|
765 |
WidgetBoxTreeWidget::Widget WidgetBoxTreeWidget::widget(int cat_idx, int wgt_idx) const
|
|
766 |
{
|
|
767 |
if (cat_idx >= topLevelItemCount())
|
|
768 |
return Widget();
|
|
769 |
// SDK functions want unfiltered access
|
|
770 |
WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx);
|
|
771 |
return categoryView->widgetAt(WidgetBoxCategoryListView::UnfilteredAccess, wgt_idx);
|
|
772 |
}
|
|
773 |
|
|
774 |
void WidgetBoxTreeWidget::addWidget(int cat_idx, const Widget &wgt)
|
|
775 |
{
|
|
776 |
if (cat_idx >= topLevelItemCount())
|
|
777 |
return;
|
|
778 |
|
|
779 |
QTreeWidgetItem *cat_item = topLevelItem(cat_idx);
|
|
780 |
WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx);
|
|
781 |
|
|
782 |
const bool scratch = topLevelRole(cat_item) == SCRATCHPAD_ITEM;
|
|
783 |
categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), scratch);
|
|
784 |
adjustSubListSize(cat_item);
|
|
785 |
}
|
|
786 |
|
|
787 |
void WidgetBoxTreeWidget::removeWidget(int cat_idx, int wgt_idx)
|
|
788 |
{
|
|
789 |
if (cat_idx >= topLevelItemCount())
|
|
790 |
return;
|
|
791 |
|
|
792 |
WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx);
|
|
793 |
|
|
794 |
// SDK functions want unfiltered access
|
|
795 |
const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::UnfilteredAccess;
|
|
796 |
if (wgt_idx >= categoryView->count(am))
|
|
797 |
return;
|
|
798 |
|
|
799 |
categoryView->removeRow(am, wgt_idx);
|
|
800 |
}
|
|
801 |
|
|
802 |
void WidgetBoxTreeWidget::slotScratchPadItemDeleted()
|
|
803 |
{
|
|
804 |
const int scratch_idx = indexOfScratchpad();
|
|
805 |
QTreeWidgetItem *scratch_item = topLevelItem(scratch_idx);
|
|
806 |
adjustSubListSize(scratch_item);
|
|
807 |
save();
|
|
808 |
}
|
|
809 |
|
|
810 |
void WidgetBoxTreeWidget::slotLastScratchPadItemDeleted()
|
|
811 |
{
|
|
812 |
// Remove the scratchpad in the next idle loop
|
|
813 |
if (!m_scratchPadDeleteTimer) {
|
|
814 |
m_scratchPadDeleteTimer = new QTimer(this);
|
|
815 |
m_scratchPadDeleteTimer->setSingleShot(true);
|
|
816 |
m_scratchPadDeleteTimer->setInterval(0);
|
|
817 |
connect(m_scratchPadDeleteTimer, SIGNAL(timeout()), this, SLOT(deleteScratchpad()));
|
|
818 |
}
|
|
819 |
if (!m_scratchPadDeleteTimer->isActive())
|
|
820 |
m_scratchPadDeleteTimer->start();
|
|
821 |
}
|
|
822 |
|
|
823 |
void WidgetBoxTreeWidget::deleteScratchpad()
|
|
824 |
{
|
|
825 |
const int idx = indexOfScratchpad();
|
|
826 |
if (idx == -1)
|
|
827 |
return;
|
|
828 |
delete takeTopLevelItem(idx);
|
|
829 |
save();
|
|
830 |
}
|
|
831 |
|
|
832 |
|
|
833 |
void WidgetBoxTreeWidget::slotListMode()
|
|
834 |
{
|
|
835 |
m_iconMode = false;
|
|
836 |
updateViewMode();
|
|
837 |
}
|
|
838 |
|
|
839 |
void WidgetBoxTreeWidget::slotIconMode()
|
|
840 |
{
|
|
841 |
m_iconMode = true;
|
|
842 |
updateViewMode();
|
|
843 |
}
|
|
844 |
|
|
845 |
void WidgetBoxTreeWidget::updateViewMode()
|
|
846 |
{
|
|
847 |
if (const int numTopLevels = topLevelItemCount()) {
|
|
848 |
for (int i = numTopLevels - 1; i >= 0; --i) {
|
|
849 |
QTreeWidgetItem *topLevel = topLevelItem(i);
|
|
850 |
// Scratch pad stays in list mode.
|
|
851 |
const QListView::ViewMode viewMode = m_iconMode && (topLevelRole(topLevel) != SCRATCHPAD_ITEM) ? QListView::IconMode : QListView::ListMode;
|
|
852 |
WidgetBoxCategoryListView *categoryView = categoryViewAt(i);
|
|
853 |
if (viewMode != categoryView->viewMode()) {
|
|
854 |
categoryView->setViewMode(viewMode);
|
|
855 |
adjustSubListSize(topLevelItem(i));
|
|
856 |
}
|
|
857 |
}
|
|
858 |
}
|
|
859 |
|
|
860 |
updateGeometries();
|
|
861 |
}
|
|
862 |
|
|
863 |
void WidgetBoxTreeWidget::resizeEvent(QResizeEvent *e)
|
|
864 |
{
|
|
865 |
QTreeWidget::resizeEvent(e);
|
|
866 |
if (const int numTopLevels = topLevelItemCount()) {
|
|
867 |
for (int i = numTopLevels - 1; i >= 0; --i)
|
|
868 |
adjustSubListSize(topLevelItem(i));
|
|
869 |
}
|
|
870 |
}
|
|
871 |
|
|
872 |
void WidgetBoxTreeWidget::contextMenuEvent(QContextMenuEvent *e)
|
|
873 |
{
|
|
874 |
QTreeWidgetItem *item = itemAt(e->pos());
|
|
875 |
|
|
876 |
const bool scratchpad_menu = item != 0
|
|
877 |
&& item->parent() != 0
|
|
878 |
&& topLevelRole(item->parent()) == SCRATCHPAD_ITEM;
|
|
879 |
|
|
880 |
QMenu menu;
|
|
881 |
menu.addAction(tr("Expand all"), this, SLOT(expandAll()));
|
|
882 |
menu.addAction(tr("Collapse all"), this, SLOT(collapseAll()));
|
|
883 |
menu.addSeparator();
|
|
884 |
|
|
885 |
QAction *listModeAction = menu.addAction(tr("List View"));
|
|
886 |
QAction *iconModeAction = menu.addAction(tr("Icon View"));
|
|
887 |
listModeAction->setCheckable(true);
|
|
888 |
iconModeAction->setCheckable(true);
|
|
889 |
QActionGroup *viewModeGroup = new QActionGroup(&menu);
|
|
890 |
viewModeGroup->addAction(listModeAction);
|
|
891 |
viewModeGroup->addAction(iconModeAction);
|
|
892 |
if (m_iconMode)
|
|
893 |
iconModeAction->setChecked(true);
|
|
894 |
else
|
|
895 |
listModeAction->setChecked(true);
|
|
896 |
connect(listModeAction, SIGNAL(triggered()), SLOT(slotListMode()));
|
|
897 |
connect(iconModeAction, SIGNAL(triggered()), SLOT(slotIconMode()));
|
|
898 |
|
|
899 |
if (scratchpad_menu) {
|
|
900 |
menu.addSeparator();
|
|
901 |
menu.addAction(tr("Remove"), itemWidget(item, 0), SLOT(removeCurrentItem()));
|
|
902 |
if (!m_iconMode)
|
|
903 |
menu.addAction(tr("Edit name"), itemWidget(item, 0), SLOT(editCurrentItem()));
|
|
904 |
}
|
|
905 |
e->accept();
|
|
906 |
menu.exec(mapToGlobal(e->pos()));
|
|
907 |
}
|
|
908 |
|
|
909 |
void WidgetBoxTreeWidget::dropWidgets(const QList<QDesignerDnDItemInterface*> &item_list)
|
|
910 |
{
|
|
911 |
QTreeWidgetItem *scratch_item = 0;
|
|
912 |
WidgetBoxCategoryListView *categoryView = 0;
|
|
913 |
bool added = false;
|
|
914 |
|
|
915 |
foreach (QDesignerDnDItemInterface *item, item_list) {
|
|
916 |
QWidget *w = item->widget();
|
|
917 |
if (w == 0)
|
|
918 |
continue;
|
|
919 |
|
|
920 |
DomUI *dom_ui = item->domUi();
|
|
921 |
if (dom_ui == 0)
|
|
922 |
continue;
|
|
923 |
|
|
924 |
const int scratch_idx = ensureScratchpad();
|
|
925 |
scratch_item = topLevelItem(scratch_idx);
|
|
926 |
categoryView = categoryViewAt(scratch_idx);
|
|
927 |
|
|
928 |
// Temporarily remove the fake toplevel in-between
|
|
929 |
DomWidget *fakeTopLevel = dom_ui->takeElementWidget();
|
|
930 |
DomWidget *firstWidget = 0;
|
|
931 |
if (fakeTopLevel && !fakeTopLevel->elementWidget().isEmpty()) {
|
|
932 |
firstWidget = fakeTopLevel->elementWidget().first();
|
|
933 |
dom_ui->setElementWidget(firstWidget);
|
|
934 |
} else {
|
|
935 |
dom_ui->setElementWidget(fakeTopLevel);
|
|
936 |
continue;
|
|
937 |
}
|
|
938 |
|
|
939 |
// Serialize to XML
|
|
940 |
QString xml;
|
|
941 |
{
|
|
942 |
QXmlStreamWriter writer(&xml);
|
|
943 |
writer.setAutoFormatting(true);
|
|
944 |
writer.setAutoFormattingIndent(1);
|
|
945 |
writer.writeStartDocument();
|
|
946 |
dom_ui->write(writer);
|
|
947 |
writer.writeEndDocument();
|
|
948 |
}
|
|
949 |
|
|
950 |
// Insert fake toplevel again
|
|
951 |
dom_ui->takeElementWidget();
|
|
952 |
dom_ui->setElementWidget(fakeTopLevel);
|
|
953 |
|
|
954 |
const Widget wgt = Widget(w->objectName(), xml);
|
|
955 |
categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), true);
|
|
956 |
setItemExpanded(scratch_item, true);
|
|
957 |
added = true;
|
|
958 |
}
|
|
959 |
|
|
960 |
if (added) {
|
|
961 |
save();
|
|
962 |
QApplication::setActiveWindow(this);
|
|
963 |
// Is the new item visible in filtered mode?
|
|
964 |
const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::FilteredAccess;
|
|
965 |
if (const int count = categoryView->count(am))
|
|
966 |
categoryView->setCurrentItem(am, count - 1);
|
|
967 |
categoryView->adjustSize(); // XXX
|
|
968 |
adjustSubListSize(scratch_item);
|
|
969 |
}
|
|
970 |
}
|
|
971 |
|
|
972 |
void WidgetBoxTreeWidget::filter(const QString &f)
|
|
973 |
{
|
|
974 |
const bool empty = f.isEmpty();
|
|
975 |
const QRegExp re = empty ? QRegExp() : QRegExp(f, Qt::CaseInsensitive, QRegExp::FixedString);
|
|
976 |
const int numTopLevels = topLevelItemCount();
|
|
977 |
bool changed = false;
|
|
978 |
for (int i = 0; i < numTopLevels; i++) {
|
|
979 |
QTreeWidgetItem *tl = topLevelItem(i);
|
|
980 |
WidgetBoxCategoryListView *categoryView = categoryViewAt(i);
|
|
981 |
// Anything changed? -> Enable the category
|
|
982 |
const int oldCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess);
|
|
983 |
categoryView->filter(re);
|
|
984 |
const int newCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess);
|
|
985 |
if (oldCount != newCount) {
|
|
986 |
changed = true;
|
|
987 |
const bool categoryEnabled = newCount > 0 || empty;
|
|
988 |
if (categoryEnabled) {
|
|
989 |
categoryView->adjustSize();
|
|
990 |
adjustSubListSize(tl);
|
|
991 |
}
|
|
992 |
setRowHidden (i, QModelIndex(), !categoryEnabled);
|
|
993 |
}
|
|
994 |
}
|
|
995 |
if (changed)
|
|
996 |
updateGeometries();
|
|
997 |
}
|
|
998 |
|
|
999 |
} // namespace qdesigner_internal
|
|
1000 |
|
|
1001 |
QT_END_NAMESPACE
|