1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "propertyeditor.h"
43 
44 #include "qttreepropertybrowser.h"
45 #include "qtbuttonpropertybrowser.h"
46 #include "qtvariantproperty.h"
47 #include "designerpropertymanager.h"
48 #include "qdesigner_propertysheet_p.h"
49 #include "formwindowbase_p.h"
50 #include "filterwidget_p.h" // For FilterWidget
51 
52 #include "newdynamicpropertydialog.h"
53 #include "dynamicpropertysheet.h"
54 #include "shared_enums_p.h"
55 
56 // sdk
57 #include <QtDesigner/QDesignerFormEditorInterface>
58 #include <QtDesigner/QDesignerFormWindowManagerInterface>
59 #include <QtDesigner/QExtensionManager>
60 #include <QtDesigner/QDesignerPropertySheetExtension>
61 #include <QtDesigner/QDesignerWidgetDataBaseInterface>
62 #include <QtDesigner/private/abstractsettings_p.h>
63 // shared
64 #include <qdesigner_utils_p.h>
65 #include <qdesigner_propertycommand_p.h>
66 #include <metadatabase_p.h>
67 #include <iconloader_p.h>
68 #ifdef Q_OS_WIN
69 #  include <widgetfactory_p.h>
70 #endif
71 #include <QtGui/QAction>
72 #include <QtGui/QLineEdit>
73 #include <QtGui/QMenu>
74 #include <QtGui/QApplication>
75 #include <QtGui/QVBoxLayout>
76 #include <QtGui/QScrollArea>
77 #include <QtGui/QStackedWidget>
78 #include <QtGui/QToolBar>
79 #include <QtGui/QToolButton>
80 #include <QtGui/QActionGroup>
81 #include <QtGui/QLabel>
82 #include <QtGui/QPainter>
83 
84 #include <QtCore/QDebug>
85 #include <QtCore/QTextStream>
86 
87 static const char *SettingsGroupC = "PropertyEditor";
88 #if QT_VERSION >= 0x040500
89 static const char *ViewKeyC = "View";
90 #endif
91 static const char *ColorKeyC = "Colored";
92 static const char *SortedKeyC = "Sorted";
93 static const char *ExpansionKeyC = "ExpandedItems";
94 static const char *SplitterPositionKeyC = "SplitterPosition";
95 
96 enum SettingsView { TreeView, ButtonView };
97 
98 QT_BEGIN_NAMESPACE
99 
100 // ---------------------------------------------------------------------------------
101 
102 namespace qdesigner_internal {
103 
104 // ----------- ElidingLabel
105 // QLabel does not support text eliding so we need a helper class
106 
107 class ElidingLabel : public QWidget
108 {
109 public:
ElidingLabel(const QString & text=QString (),QWidget * parent=0)110     ElidingLabel(const QString &text = QString(), QWidget *parent = 0)
111         : QWidget(parent),
112         m_text(text),
113         m_mode(Qt::ElideRight) {
114         setContentsMargins(3, 2, 3, 2);
115     }
116     QSize sizeHint() const;
117     void paintEvent(QPaintEvent *e);
setText(const QString & text)118     void setText(const QString &text) {
119         m_text = text;
120         updateGeometry();
121     }
setElidemode(Qt::TextElideMode mode)122     void setElidemode(Qt::TextElideMode mode) {
123         m_mode = mode;
124         updateGeometry();
125     }
126 private:
127     QString m_text;
128     Qt::TextElideMode m_mode;
129 };
130 
sizeHint() const131 QSize ElidingLabel::sizeHint() const
132 {
133     QSize size = fontMetrics().boundingRect(m_text).size();
134     size += QSize(contentsMargins().left() + contentsMargins().right(),
135                   contentsMargins().top() + contentsMargins().bottom());
136     return size;
137 }
138 
paintEvent(QPaintEvent *)139 void ElidingLabel::paintEvent(QPaintEvent *) {
140     QPainter painter(this);
141     painter.setPen(QColor(0, 0, 0, 60));
142     painter.setBrush(QColor(255, 255, 255, 40));
143     painter.drawRect(rect().adjusted(0, 0, -1, -1));
144     painter.setPen(palette().windowText().color());
145     painter.drawText(contentsRect(), Qt::AlignLeft,
146                      fontMetrics().elidedText(m_text, Qt::ElideRight, width(), 0));
147 }
148 
149 
150 // ----------- PropertyEditor::Strings
151 
Strings()152 PropertyEditor::Strings::Strings() :
153     m_fontProperty(QLatin1String("font")),
154     m_qLayoutWidget(QLatin1String("QLayoutWidget")),
155     m_designerPrefix(QLatin1String("QDesigner")),
156     m_layout(QLatin1String("Layout")),
157     m_validationModeAttribute(QLatin1String("validationMode")),
158     m_fontAttribute(QLatin1String("font")),
159     m_superPaletteAttribute(QLatin1String("superPalette")),
160     m_enumNamesAttribute(QLatin1String("enumNames")),
161     m_resettableAttribute(QLatin1String("resettable")),
162     m_flagsAttribute(QLatin1String("flags"))
163 {
164     m_alignmentProperties.insert(QLatin1String("alignment"));
165     m_alignmentProperties.insert(QLatin1String("layoutLabelAlignment")); // QFormLayout
166     m_alignmentProperties.insert(QLatin1String("layoutFormAlignment"));
167 }
168 
169 // ----------- PropertyEditor
170 
metaDataBaseItem() const171 QDesignerMetaDataBaseItemInterface* PropertyEditor::metaDataBaseItem() const
172 {
173     QObject *o = object();
174     if (!o)
175         return 0;
176     QDesignerMetaDataBaseInterface *db = core()->metaDataBase();
177     if (!db)
178         return 0;
179     return db->item(o);
180 }
181 
setupStringProperty(QtVariantProperty * property,bool isMainContainer)182 void PropertyEditor::setupStringProperty(QtVariantProperty *property, bool isMainContainer)
183 {
184     const StringPropertyParameters params = textPropertyValidationMode(core(), m_object, property->propertyName(), isMainContainer);
185     // Does a meta DB entry exist - add comment
186     const bool hasComment = params.second;
187     property->setAttribute(m_strings.m_validationModeAttribute, params.first);
188     // assuming comment cannot appear or disappear for the same property in different object instance
189     if (!hasComment)
190         qDeleteAll(property->subProperties());
191 }
192 
setupPaletteProperty(QtVariantProperty * property)193 void PropertyEditor::setupPaletteProperty(QtVariantProperty *property)
194 {
195     QPalette value = qvariant_cast<QPalette>(property->value());
196     QPalette superPalette = QPalette();
197     QWidget *currentWidget = qobject_cast<QWidget *>(m_object);
198     if (currentWidget) {
199         if (currentWidget->isWindow())
200             superPalette = QApplication::palette(currentWidget);
201         else {
202             if (currentWidget->parentWidget())
203                 superPalette = currentWidget->parentWidget()->palette();
204         }
205     }
206     m_updatingBrowser = true;
207     property->setAttribute(m_strings.m_superPaletteAttribute, superPalette);
208     m_updatingBrowser = false;
209 }
210 
createDropDownButton(QAction * defaultAction,QWidget * parent=0)211 static inline QToolButton *createDropDownButton(QAction *defaultAction, QWidget *parent = 0)
212 {
213     QToolButton *rc = new QToolButton(parent);
214     rc->setDefaultAction(defaultAction);
215     rc->setPopupMode(QToolButton::InstantPopup);
216     return rc;
217 }
218 
PropertyEditor(QDesignerFormEditorInterface * core,QWidget * parent,Qt::WindowFlags flags)219 PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags)  :
220     QDesignerPropertyEditor(parent, flags),
221     m_core(core),
222     m_propertySheet(0),
223     m_currentBrowser(0),
224     m_treeBrowser(0),
225     m_propertyManager(new DesignerPropertyManager(m_core, this)),
226     m_dynamicGroup(0),
227     m_updatingBrowser(false),
228     m_stackedWidget(new QStackedWidget),
229     m_filterWidget(new FilterWidget(0, FilterWidget::LayoutAlignNone)),
230     m_buttonIndex(-1),
231     m_treeIndex(-1),
232     m_addDynamicAction(new QAction(createIconSet(QLatin1String("plus.png")), tr("Add Dynamic Property..."), this)),
233     m_removeDynamicAction(new QAction(createIconSet(QLatin1String("minus.png")), tr("Remove Dynamic Property"), this)),
234     m_sortingAction(new QAction(createIconSet(QLatin1String("sort.png")), tr("Sorting"), this)),
235     m_coloringAction(new QAction(createIconSet(QLatin1String("color.png")), tr("Color Groups"), this)),
236     m_treeAction(new QAction(tr("Tree View"), this)),
237     m_buttonAction(new QAction(tr("Drop Down Button View"), this)),
238     m_classLabel(new ElidingLabel),
239     m_sorting(false),
240     m_coloring(false),
241     m_brightness(false)
242 {
243     QVector<QColor> colors;
244     colors.reserve(6);
245     colors.push_back(QColor(255, 230, 191));
246     colors.push_back(QColor(255, 255, 191));
247     colors.push_back(QColor(191, 255, 191));
248     colors.push_back(QColor(199, 255, 255));
249     colors.push_back(QColor(234, 191, 255));
250     colors.push_back(QColor(255, 191, 239));
251     m_colors.reserve(colors.count());
252     const int darknessFactor = 250;
253     for (int i = 0; i < colors.count(); i++) {
254         QColor c = colors.at(i);
255         m_colors.push_back(qMakePair(c, c.darker(darknessFactor)));
256     }
257     QColor dynamicColor(191, 207, 255);
258     QColor layoutColor(255, 191, 191);
259     m_dynamicColor = qMakePair(dynamicColor, dynamicColor.darker(darknessFactor));
260     m_layoutColor = qMakePair(layoutColor, layoutColor.darker(darknessFactor));
261 
262     updateForegroundBrightness();
263 
264     QActionGroup *actionGroup = new QActionGroup(this);
265 
266     m_treeAction->setCheckable(true);
267     m_treeAction->setIcon(createIconSet(QLatin1String("widgets/listview.png")));
268     m_buttonAction->setCheckable(true);
269     m_buttonAction->setIcon(createIconSet(QLatin1String("dropdownbutton.png")));
270 
271     actionGroup->addAction(m_treeAction);
272     actionGroup->addAction(m_buttonAction);
273     connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewTriggered(QAction*)));
274 
275     // Add actions
276     QActionGroup *addDynamicActionGroup = new QActionGroup(this);
277     connect(addDynamicActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotAddDynamicProperty(QAction*)));
278 
279     QMenu *addDynamicActionMenu = new QMenu(this);
280     m_addDynamicAction->setMenu(addDynamicActionMenu);
281     m_addDynamicAction->setEnabled(false);
282     QAction *addDynamicAction = addDynamicActionGroup->addAction(tr("String..."));
283     addDynamicAction->setData(static_cast<int>(QVariant::String));
284     addDynamicActionMenu->addAction(addDynamicAction);
285     addDynamicAction = addDynamicActionGroup->addAction(tr("Bool..."));
286     addDynamicAction->setData(static_cast<int>(QVariant::Bool));
287     addDynamicActionMenu->addAction(addDynamicAction);
288     addDynamicActionMenu->addSeparator();
289     addDynamicAction = addDynamicActionGroup->addAction(tr("Other..."));
290     addDynamicAction->setData(static_cast<int>(QVariant::Invalid));
291     addDynamicActionMenu->addAction(addDynamicAction);
292     // remove
293     m_removeDynamicAction->setEnabled(false);
294     connect(m_removeDynamicAction, SIGNAL(triggered()), this, SLOT(slotRemoveDynamicProperty()));
295     // Configure
296     QAction *configureAction = new QAction(tr("Configure Property Editor"), this);
297     configureAction->setIcon(createIconSet(QLatin1String("configure.png")));
298     QMenu *configureMenu = new QMenu(this);
299     configureAction->setMenu(configureMenu);
300 
301     m_sortingAction->setCheckable(true);
302     connect(m_sortingAction, SIGNAL(toggled(bool)), this, SLOT(slotSorting(bool)));
303 
304     m_coloringAction->setCheckable(true);
305     connect(m_coloringAction, SIGNAL(toggled(bool)), this, SLOT(slotColoring(bool)));
306 
307     configureMenu->addAction(m_sortingAction);
308     configureMenu->addAction(m_coloringAction);
309 #if QT_VERSION >= 0x04FF00
310     configureMenu->addSeparator();
311     configureMenu->addAction(m_treeAction);
312     configureMenu->addAction(m_buttonAction);
313 #endif
314     // Assemble toolbar
315     QToolBar *toolBar = new QToolBar;
316     toolBar->addWidget(m_filterWidget);
317     toolBar->addWidget(createDropDownButton(m_addDynamicAction));
318     toolBar->addAction(m_removeDynamicAction);
319     toolBar->addWidget(createDropDownButton(configureAction));
320     // Views
321     QScrollArea *buttonScroll = new QScrollArea(m_stackedWidget);
322     m_buttonBrowser = new QtButtonPropertyBrowser(buttonScroll);
323     buttonScroll->setWidgetResizable(true);
324     buttonScroll->setWidget(m_buttonBrowser);
325     m_buttonIndex = m_stackedWidget->addWidget(buttonScroll);
326     connect(m_buttonBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*)));
327 
328     m_treeBrowser = new QtTreePropertyBrowser(m_stackedWidget);
329     m_treeBrowser->setRootIsDecorated(false);
330     m_treeBrowser->setPropertiesWithoutValueMarked(true);
331     m_treeBrowser->setResizeMode(QtTreePropertyBrowser::Interactive);
332     m_treeIndex = m_stackedWidget->addWidget(m_treeBrowser);
333     connect(m_treeBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*)));
334     connect(m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(setFilter(QString)));
335 
336     QVBoxLayout *layout = new QVBoxLayout(this);
337     layout->addWidget(toolBar);
338     layout->addWidget(m_classLabel);
339     layout->addSpacerItem(new QSpacerItem(0,1));
340     layout->addWidget(m_stackedWidget);
341     layout->setMargin(0);
342     layout->setSpacing(0);
343 
344     m_treeFactory = new DesignerEditorFactory(m_core, this);
345     m_treeFactory->setSpacing(0);
346     m_groupFactory = new DesignerEditorFactory(m_core, this);
347     QtVariantPropertyManager *variantManager = m_propertyManager;
348     m_buttonBrowser->setFactoryForManager(variantManager, m_groupFactory);
349     m_treeBrowser->setFactoryForManager(variantManager, m_treeFactory);
350 
351     m_stackedWidget->setCurrentIndex(m_treeIndex);
352     m_currentBrowser = m_treeBrowser;
353     m_treeAction->setChecked(true);
354 
355     connect(m_groupFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*)));
356     connect(m_treeFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*)));
357     connect(variantManager, SIGNAL(valueChanged(QtProperty*,QVariant,bool)), this, SLOT(slotValueChanged(QtProperty*,QVariant,bool)));
358 
359     // retrieve initial settings
360     QDesignerSettingsInterface *settings = m_core->settingsManager();
361     settings->beginGroup(QLatin1String(SettingsGroupC));
362 #if QT_VERSION >= 0x040500
363     const SettingsView view = settings->value(QLatin1String(ViewKeyC), TreeView).toInt() == TreeView ? TreeView :  ButtonView;
364 #endif
365     // Coloring not available unless treeview and not sorted
366     m_sorting = settings->value(QLatin1String(SortedKeyC), false).toBool();
367     m_coloring = settings->value(QLatin1String(ColorKeyC), true).toBool();
368     const QVariantMap expansionState = settings->value(QLatin1String(ExpansionKeyC), QVariantMap()).toMap();
369     const int splitterPosition = settings->value(QLatin1String(SplitterPositionKeyC), 150).toInt();
370     settings->endGroup();
371     // Apply settings
372     m_sortingAction->setChecked(m_sorting);
373     m_coloringAction->setChecked(m_coloring);
374     m_treeBrowser->setSplitterPosition(splitterPosition);
375 #if QT_VERSION >= 0x040500
376     switch (view) {
377     case TreeView:
378         m_currentBrowser = m_treeBrowser;
379         m_stackedWidget->setCurrentIndex(m_treeIndex);
380         m_treeAction->setChecked(true);
381         break;
382     case ButtonView:
383         m_currentBrowser = m_buttonBrowser;
384         m_stackedWidget->setCurrentIndex(m_buttonIndex);
385         m_buttonAction->setChecked(true);
386         break;
387     }
388 #endif
389     // Restore expansionState from QVariant map
390     if (!expansionState.empty()) {
391         const QVariantMap::const_iterator cend = expansionState.constEnd();
392         for (QVariantMap::const_iterator it = expansionState.constBegin(); it != cend; ++it)
393             m_expansionState.insert(it.key(), it.value().toBool());
394     }
395     updateActionsState();
396 }
397 
~PropertyEditor()398 PropertyEditor::~PropertyEditor()
399 {
400     storeExpansionState();
401     saveSettings();
402 }
403 
saveSettings() const404 void PropertyEditor::saveSettings() const
405 {
406     QDesignerSettingsInterface *settings = m_core->settingsManager();
407     settings->beginGroup(QLatin1String(SettingsGroupC));
408 #if QT_VERSION >= 0x040500
409     settings->setValue(QLatin1String(ViewKeyC), QVariant(m_treeAction->isChecked() ? TreeView : ButtonView));
410 #endif
411     settings->setValue(QLatin1String(ColorKeyC), QVariant(m_coloring));
412     settings->setValue(QLatin1String(SortedKeyC), QVariant(m_sorting));
413     // Save last expansionState as QVariant map
414     QVariantMap expansionState;
415     if (!m_expansionState.empty()) {
416         const QMap<QString, bool>::const_iterator cend = m_expansionState.constEnd();
417         for (QMap<QString, bool>::const_iterator it = m_expansionState.constBegin(); it != cend; ++it)
418             expansionState.insert(it.key(), QVariant(it.value()));
419     }
420     settings->setValue(QLatin1String(ExpansionKeyC), expansionState);
421     settings->setValue(QLatin1String(SplitterPositionKeyC), m_treeBrowser->splitterPosition());
422     settings->endGroup();
423 }
424 
setExpanded(QtBrowserItem * item,bool expanded)425 void PropertyEditor::setExpanded(QtBrowserItem *item, bool expanded)
426 {
427     if (m_buttonBrowser == m_currentBrowser)
428         m_buttonBrowser->setExpanded(item, expanded);
429     else if (m_treeBrowser == m_currentBrowser)
430         m_treeBrowser->setExpanded(item, expanded);
431 }
432 
isExpanded(QtBrowserItem * item) const433 bool PropertyEditor::isExpanded(QtBrowserItem *item) const
434 {
435     if (m_buttonBrowser == m_currentBrowser)
436         return m_buttonBrowser->isExpanded(item);
437     else if (m_treeBrowser == m_currentBrowser)
438         return m_treeBrowser->isExpanded(item);
439     return false;
440 }
441 
setItemVisible(QtBrowserItem * item,bool visible)442 void PropertyEditor::setItemVisible(QtBrowserItem *item, bool visible)
443 {
444     if (m_currentBrowser == m_treeBrowser) {
445         m_treeBrowser->setItemVisible(item, visible);
446     } else {
447         qWarning("** WARNING %s is not implemented for this browser.", Q_FUNC_INFO);
448     }
449 }
450 
isItemVisible(QtBrowserItem * item) const451 bool PropertyEditor::isItemVisible(QtBrowserItem *item) const
452 {
453     return m_currentBrowser == m_treeBrowser ? m_treeBrowser->isItemVisible(item) : true;
454 }
455 
456 /* Default handling of items not found in the map:
457  * - Top-level items (classes) are assumed to be expanded
458  * - Anything below (properties) is assumed to be collapsed
459  * That is, the map is required, the state cannot be stored in a set */
460 
storePropertiesExpansionState(const QList<QtBrowserItem * > & items)461 void PropertyEditor::storePropertiesExpansionState(const QList<QtBrowserItem *> &items)
462 {
463     const QChar bar = QLatin1Char('|');
464     QListIterator<QtBrowserItem *> itProperty(items);
465     while (itProperty.hasNext()) {
466         QtBrowserItem *propertyItem = itProperty.next();
467         if (!propertyItem->children().empty()) {
468             QtProperty *property = propertyItem->property();
469             const QString propertyName = property->propertyName();
470             const QMap<QtProperty *, QString>::const_iterator itGroup = m_propertyToGroup.constFind(property);
471             if (itGroup != m_propertyToGroup.constEnd()) {
472                 QString key = itGroup.value();
473                 key += bar;
474                 key += propertyName;
475                 m_expansionState[key] = isExpanded(propertyItem);
476             }
477         }
478     }
479 }
480 
storeExpansionState()481 void PropertyEditor::storeExpansionState()
482 {
483     const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems();
484     if (m_sorting) {
485         storePropertiesExpansionState(items);
486     } else {
487         QListIterator<QtBrowserItem *> itGroup(items);
488         while (itGroup.hasNext()) {
489             QtBrowserItem *item = itGroup.next();
490             const QString groupName = item->property()->propertyName();
491             QList<QtBrowserItem *> propertyItems = item->children();
492             if (!propertyItems.empty())
493                 m_expansionState[groupName] = isExpanded(item);
494 
495             // properties stuff here
496             storePropertiesExpansionState(propertyItems);
497         }
498     }
499 }
500 
collapseAll()501 void PropertyEditor::collapseAll()
502 {
503     QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems();
504     QListIterator<QtBrowserItem *> itGroup(items);
505     while (itGroup.hasNext())
506         setExpanded(itGroup.next(), false);
507 }
508 
applyPropertiesExpansionState(const QList<QtBrowserItem * > & items)509 void PropertyEditor::applyPropertiesExpansionState(const QList<QtBrowserItem *> &items)
510 {
511     const QChar bar = QLatin1Char('|');
512     QListIterator<QtBrowserItem *> itProperty(items);
513     while (itProperty.hasNext()) {
514         const QMap<QString, bool>::const_iterator excend = m_expansionState.constEnd();
515         QtBrowserItem *propertyItem = itProperty.next();
516         QtProperty *property = propertyItem->property();
517         const QString propertyName = property->propertyName();
518         const QMap<QtProperty *, QString>::const_iterator itGroup = m_propertyToGroup.constFind(property);
519         if (itGroup != m_propertyToGroup.constEnd()) {
520             QString key = itGroup.value();
521             key += bar;
522             key += propertyName;
523             const QMap<QString, bool>::const_iterator pit = m_expansionState.constFind(key);
524             if (pit != excend)
525                 setExpanded(propertyItem, pit.value());
526             else
527                 setExpanded(propertyItem, false);
528         }
529     }
530 }
531 
applyExpansionState()532 void PropertyEditor::applyExpansionState()
533 {
534     const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems();
535     if (m_sorting) {
536         applyPropertiesExpansionState(items);
537     } else {
538         QListIterator<QtBrowserItem *> itTopLevel(items);
539         const QMap<QString, bool>::const_iterator excend = m_expansionState.constEnd();
540         while (itTopLevel.hasNext()) {
541             QtBrowserItem *item = itTopLevel.next();
542             const QString groupName = item->property()->propertyName();
543             const QMap<QString, bool>::const_iterator git = m_expansionState.constFind(groupName);
544             if (git != excend)
545                 setExpanded(item, git.value());
546             else
547                 setExpanded(item, true);
548             // properties stuff here
549             applyPropertiesExpansionState(item->children());
550         }
551     }
552 }
553 
applyPropertiesFilter(const QList<QtBrowserItem * > & items)554 int PropertyEditor::applyPropertiesFilter(const QList<QtBrowserItem *> &items)
555 {
556     int showCount = 0;
557     const bool matchAll = m_filterPattern.isEmpty();
558     QListIterator<QtBrowserItem *> itProperty(items);
559     while (itProperty.hasNext()) {
560         QtBrowserItem *propertyItem = itProperty.next();
561         QtProperty *property = propertyItem->property();
562         const QString propertyName = property->propertyName();
563         const bool showProperty = matchAll || propertyName.contains(m_filterPattern, Qt::CaseInsensitive);
564         setItemVisible(propertyItem, showProperty);
565         if (showProperty)
566             showCount++;
567     }
568     return showCount;
569 }
570 
applyFilter()571 void PropertyEditor::applyFilter()
572 {
573     const QList<QtBrowserItem *> items = m_currentBrowser->topLevelItems();
574     if (m_sorting) {
575         applyPropertiesFilter(items);
576     } else {
577         QListIterator<QtBrowserItem *> itTopLevel(items);
578         while (itTopLevel.hasNext()) {
579             QtBrowserItem *item = itTopLevel.next();
580             setItemVisible(item, applyPropertiesFilter(item->children()));
581         }
582     }
583 }
584 
clearView()585 void PropertyEditor::clearView()
586 {
587     m_currentBrowser->clear();
588 }
589 
event(QEvent * event)590 bool PropertyEditor::event(QEvent *event)
591 {
592     if (event->type() == QEvent::PaletteChange)
593         updateForegroundBrightness();
594 
595     return QDesignerPropertyEditor::event(event);
596 }
597 
updateForegroundBrightness()598 void PropertyEditor::updateForegroundBrightness()
599 {
600     QColor c = palette().color(QPalette::Text);
601     bool newBrightness = qRound(0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF());
602 
603     if (m_brightness == newBrightness)
604         return;
605 
606     m_brightness = newBrightness;
607 
608     updateColors();
609 }
610 
propertyColor(QtProperty * property) const611 QColor PropertyEditor::propertyColor(QtProperty *property) const
612 {
613     if (!m_coloring)
614         return QColor();
615 
616     QtProperty *groupProperty = property;
617 
618     QMap<QtProperty *, QString>::ConstIterator itProp = m_propertyToGroup.constFind(property);
619     if (itProp != m_propertyToGroup.constEnd())
620         groupProperty = m_nameToGroup.value(itProp.value());
621 
622     const int groupIdx = m_groups.indexOf(groupProperty);
623     QPair<QColor, QColor> pair;
624     if (groupIdx != -1) {
625         if (groupProperty == m_dynamicGroup)
626             pair = m_dynamicColor;
627         else if (isLayoutGroup(groupProperty))
628             pair = m_layoutColor;
629         else
630             pair = m_colors[groupIdx % m_colors.count()];
631     }
632     if (!m_brightness)
633         return pair.first;
634     return pair.second;
635 }
636 
fillView()637 void PropertyEditor::fillView()
638 {
639     if (m_sorting) {
640         QMapIterator<QString, QtVariantProperty *> itProperty(m_nameToProperty);
641         while (itProperty.hasNext()) {
642             QtVariantProperty *property = itProperty.next().value();
643             m_currentBrowser->addProperty(property);
644         }
645     } else {
646         QListIterator<QtProperty *> itGroup(m_groups);
647         while (itGroup.hasNext()) {
648             QtProperty *group = itGroup.next();
649             QtBrowserItem *item = m_currentBrowser->addProperty(group);
650             if (m_currentBrowser == m_treeBrowser)
651                 m_treeBrowser->setBackgroundColor(item, propertyColor(group));
652             group->setModified(m_currentBrowser == m_treeBrowser);
653         }
654     }
655 }
656 
isLayoutGroup(QtProperty * group) const657 bool PropertyEditor::isLayoutGroup(QtProperty *group) const
658 {
659    return group->propertyName() == m_strings.m_layout;
660 }
661 
updateActionsState()662 void PropertyEditor::updateActionsState()
663 {
664     m_coloringAction->setEnabled(m_treeAction->isChecked() && !m_sortingAction->isChecked());
665 }
666 
slotViewTriggered(QAction * action)667 void PropertyEditor::slotViewTriggered(QAction *action)
668 {
669     storeExpansionState();
670     collapseAll();
671     {
672         UpdateBlocker ub(this);
673         clearView();
674         int idx = 0;
675         if (action == m_treeAction) {
676             m_currentBrowser = m_treeBrowser;
677             idx = m_treeIndex;
678         } else if (action == m_buttonAction) {
679             m_currentBrowser = m_buttonBrowser;
680             idx = m_buttonIndex;
681         }
682         fillView();
683         m_stackedWidget->setCurrentIndex(idx);
684         applyExpansionState();
685         applyFilter();
686     }
687     updateActionsState();
688 }
689 
slotSorting(bool sort)690 void PropertyEditor::slotSorting(bool sort)
691 {
692     if (sort == m_sorting)
693         return;
694 
695     storeExpansionState();
696     m_sorting = sort;
697     collapseAll();
698     {
699         UpdateBlocker ub(this);
700         clearView();
701         m_treeBrowser->setRootIsDecorated(sort);
702         fillView();
703         applyExpansionState();
704         applyFilter();
705     }
706     updateActionsState();
707 }
708 
updateColors()709 void PropertyEditor::updateColors()
710 {
711     if (m_treeBrowser && m_currentBrowser == m_treeBrowser) {
712         QList<QtBrowserItem *> items = m_treeBrowser->topLevelItems();
713         QListIterator<QtBrowserItem *> itItem(items);
714         while (itItem.hasNext()) {
715             QtBrowserItem *item = itItem.next();
716             m_treeBrowser->setBackgroundColor(item, propertyColor(item->property()));
717         }
718     }
719 }
720 
slotColoring(bool coloring)721 void PropertyEditor::slotColoring(bool coloring)
722 {
723     if (coloring == m_coloring)
724         return;
725 
726     m_coloring = coloring;
727 
728     updateColors();
729 }
730 
slotAddDynamicProperty(QAction * action)731 void PropertyEditor::slotAddDynamicProperty(QAction *action)
732 {
733     if (!m_propertySheet)
734         return;
735 
736     const QDesignerDynamicPropertySheetExtension *dynamicSheet =
737             qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object);
738 
739     if (!dynamicSheet)
740         return;
741 
742     QString newName;
743     QVariant newValue;
744     { // Make sure the dialog is closed before the signal is emitted.
745         const QVariant::Type type = static_cast<QVariant::Type>(action->data().toInt());
746         NewDynamicPropertyDialog dlg(core()->dialogGui(), m_currentBrowser);
747         if (type != QVariant::Invalid)
748             dlg.setPropertyType(type);
749 
750         QStringList reservedNames;
751         const int propertyCount = m_propertySheet->count();
752         for (int i = 0; i < propertyCount; i++) {
753             if (!dynamicSheet->isDynamicProperty(i) || m_propertySheet->isVisible(i))
754                 reservedNames.append(m_propertySheet->propertyName(i));
755         }
756         dlg.setReservedNames(reservedNames);
757         if (dlg.exec() == QDialog::Rejected)
758             return;
759         newName = dlg.propertyName();
760         newValue = dlg.propertyValue();
761     }
762     m_recentlyAddedDynamicProperty = newName;
763     emit addDynamicProperty(newName, newValue);
764 }
765 
core() const766 QDesignerFormEditorInterface *PropertyEditor::core() const
767 {
768     return m_core;
769 }
770 
isReadOnly() const771 bool PropertyEditor::isReadOnly() const
772 {
773     return false;
774 }
775 
setReadOnly(bool)776 void PropertyEditor::setReadOnly(bool /*readOnly*/)
777 {
778     qDebug() << "PropertyEditor::setReadOnly() request";
779 }
780 
setPropertyValue(const QString & name,const QVariant & value,bool changed)781 void PropertyEditor::setPropertyValue(const QString &name, const QVariant &value, bool changed)
782 {
783     const QMap<QString, QtVariantProperty*>::const_iterator it = m_nameToProperty.constFind(name);
784     if (it == m_nameToProperty.constEnd())
785         return;
786     QtVariantProperty *property = it.value();
787     updateBrowserValue(property, value);
788     property->setModified(changed);
789 }
790 
791 /* Quick update that assumes the actual count of properties has not changed
792  * N/A when for example executing a layout command and margin properties appear. */
updatePropertySheet()793 void PropertyEditor::updatePropertySheet()
794 {
795     if (!m_propertySheet)
796         return;
797 
798     updateToolBarLabel();
799 
800     const int propertyCount = m_propertySheet->count();
801     const  QMap<QString, QtVariantProperty*>::const_iterator npcend = m_nameToProperty.constEnd();
802     for (int i = 0; i < propertyCount; ++i) {
803         const QString propertyName = m_propertySheet->propertyName(i);
804         QMap<QString, QtVariantProperty*>::const_iterator it = m_nameToProperty.constFind(propertyName);
805         if (it != npcend)
806             updateBrowserValue(it.value(), m_propertySheet->property(i));
807     }
808 }
809 
layoutOfQLayoutWidget(QObject * o)810 static inline QLayout *layoutOfQLayoutWidget(QObject *o)
811 {
812     if (o->isWidgetType() && !qstrcmp(o->metaObject()->className(), "QLayoutWidget"))
813         return static_cast<QWidget*>(o)->layout();
814     return 0;
815 }
816 
updateToolBarLabel()817 void PropertyEditor::updateToolBarLabel()
818 {
819     QString objectName;
820     QString className;
821     if (m_object) {
822         if (QLayout *l = layoutOfQLayoutWidget(m_object))
823             objectName = l->objectName();
824         else
825             objectName = m_object->objectName();
826         className = realClassName(m_object);
827     }
828 
829     m_classLabel->setVisible(!objectName.isEmpty() || !className.isEmpty());
830     m_classLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
831 
832     QString classLabelText;
833     if (!objectName.isEmpty())
834         classLabelText += objectName + QLatin1String(" : ");
835     classLabelText += className;
836 
837     m_classLabel->setText(classLabelText);
838     m_classLabel->setToolTip(tr("Object: %1\nClass: %2").arg(objectName).arg(className));
839 }
840 
updateBrowserValue(QtVariantProperty * property,const QVariant & value)841 void PropertyEditor::updateBrowserValue(QtVariantProperty *property, const QVariant &value)
842 {
843     QVariant v = value;
844     const int type = property->propertyType();
845     if (type == QtVariantPropertyManager::enumTypeId()) {
846         const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(v);
847         v = e.metaEnum.keys().indexOf(e.metaEnum.valueToKey(e.value));
848     } else if (type == DesignerPropertyManager::designerFlagTypeId()) {
849         const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v);
850         v = QVariant(f.value);
851     } else if (type == DesignerPropertyManager::designerAlignmentTypeId()) {
852         const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v);
853         v = QVariant(f.value);
854     }
855     QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension)));
856     int index = -1;
857     if (sheet)
858         index = sheet->indexOf(property->propertyName());
859     if (sheet && m_propertyToGroup.contains(property)) { // don't do it for comments since property sheet doesn't keep them
860         property->setEnabled(sheet->isEnabled(index));
861     }
862 
863     // Rich text string property with comment: Store/Update the font the rich text editor dialog starts out with
864     if (type == QVariant::String && !property->subProperties().empty()) {
865         const int fontIndex = m_propertySheet->indexOf(m_strings.m_fontProperty);
866         if (fontIndex != -1)
867             property->setAttribute(m_strings.m_fontAttribute, m_propertySheet->property(fontIndex));
868     }
869 
870     m_updatingBrowser = true;
871     property->setValue(v);
872     if (sheet && sheet->isResourceProperty(index))
873         property->setAttribute(QLatin1String("defaultResource"), sheet->defaultResourceProperty(index));
874     m_updatingBrowser = false;
875 }
876 
toBrowserType(const QVariant & value,const QString & propertyName) const877 int PropertyEditor::toBrowserType(const QVariant &value, const QString &propertyName) const
878 {
879     if (value.canConvert<PropertySheetFlagValue>()) {
880         if (m_strings.m_alignmentProperties.contains(propertyName))
881             return DesignerPropertyManager::designerAlignmentTypeId();
882         return DesignerPropertyManager::designerFlagTypeId();
883     }
884     if (value.canConvert<PropertySheetEnumValue>())
885         return DesignerPropertyManager::enumTypeId();
886 
887     return value.userType();
888 }
889 
realClassName(QObject * object) const890 QString PropertyEditor::realClassName(QObject *object) const
891 {
892     if (!object)
893         return QString();
894 
895     QString className = QLatin1String(object->metaObject()->className());
896     const QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
897     if (QDesignerWidgetDataBaseItemInterface *widgetItem = db->item(db->indexOfObject(object, true))) {
898         className = widgetItem->name();
899 
900         if (object->isWidgetType() && className == m_strings.m_qLayoutWidget
901                 && static_cast<QWidget*>(object)->layout()) {
902             className = QLatin1String(static_cast<QWidget*>(object)->layout()->metaObject()->className());
903         }
904     }
905 
906     if (className.startsWith(m_strings.m_designerPrefix))
907         className.remove(1, m_strings.m_designerPrefix.size() - 1);
908 
909     return className;
910 }
911 
msgUnsupportedType(const QString & propertyName,unsigned type)912 static QString msgUnsupportedType(const QString &propertyName, unsigned type)
913 {
914     QString rc;
915     QTextStream str(&rc);
916     str << "The property \"" << propertyName << "\" of type " << type;
917     if (type == QVariant::Invalid) {
918         str << " (invalid) ";
919     } else {
920         if (type < QVariant::UserType) {
921             if (const char *typeName = QVariant::typeToName(static_cast<QVariant::Type>(type)))
922                 str << " (" << typeName << ") ";
923         } else {
924             str << " (user type) ";
925         }
926     }
927     str << " is not supported yet!";
928     return rc;
929 }
930 
setObject(QObject * object)931 void PropertyEditor::setObject(QObject *object)
932 {
933     QDesignerFormWindowInterface *oldFormWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
934     // In the first setObject() call following the addition of a dynamic property, focus and edit it.
935     const bool editNewDynamicProperty = object != 0 && m_object == object && !m_recentlyAddedDynamicProperty.isEmpty();
936     m_object = object;
937     m_propertyManager->setObject(object);
938     QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
939     FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow);
940     m_treeFactory->setFormWindowBase(fwb);
941     m_groupFactory->setFormWindowBase(fwb);
942 
943     storeExpansionState();
944 
945     UpdateBlocker ub(this);
946 
947     updateToolBarLabel();
948 
949     QMap<QString, QtVariantProperty *> toRemove = m_nameToProperty;
950 
951     const QDesignerDynamicPropertySheetExtension *dynamicSheet =
952             qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object);
953     const QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension)));
954 
955     // Optimizization: Instead of rebuilding the complete list every time, compile a list of properties to remove,
956     // remove them, traverse the sheet, in case property exists just set a value, otherwise - create it.
957     QExtensionManager *m = m_core->extensionManager();
958 
959     m_propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)));
960     if (m_propertySheet) {
961         const int propertyCount = m_propertySheet->count();
962         for (int i = 0; i < propertyCount; ++i) {
963             if (!m_propertySheet->isVisible(i))
964                 continue;
965 
966             const QString propertyName = m_propertySheet->propertyName(i);
967             if (m_propertySheet->indexOf(propertyName) != i)
968                 continue;
969             const QString groupName = m_propertySheet->propertyGroup(i);
970             const QMap<QString, QtVariantProperty *>::const_iterator rit = toRemove.constFind(propertyName);
971             if (rit != toRemove.constEnd()) {
972                 QtVariantProperty *property = rit.value();
973                 if (m_propertyToGroup.value(property) == groupName && toBrowserType(m_propertySheet->property(i), propertyName) == property->propertyType())
974                     toRemove.remove(propertyName);
975             }
976         }
977     }
978 
979     QMapIterator<QString, QtVariantProperty *> itRemove(toRemove);
980     while (itRemove.hasNext()) {
981         itRemove.next();
982 
983         QtVariantProperty *property = itRemove.value();
984         m_nameToProperty.remove(itRemove.key());
985         m_propertyToGroup.remove(property);
986         delete property;
987     }
988 
989     if (oldFormWindow != formWindow)
990         reloadResourceProperties();
991 
992     bool isMainContainer = false;
993     if (QWidget *widget = qobject_cast<QWidget*>(object)) {
994         if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) {
995             isMainContainer = (fw->mainContainer() == widget);
996         }
997     }
998     m_groups.clear();
999 
1000     if (m_propertySheet) {
1001         QtProperty *lastProperty = 0;
1002         QtProperty *lastGroup = 0;
1003         const int propertyCount = m_propertySheet->count();
1004         for (int i = 0; i < propertyCount; ++i) {
1005             if (!m_propertySheet->isVisible(i))
1006                 continue;
1007 
1008             const QString propertyName = m_propertySheet->propertyName(i);
1009             if (m_propertySheet->indexOf(propertyName) != i)
1010                 continue;
1011             const QVariant value = m_propertySheet->property(i);
1012 
1013             const int type = toBrowserType(value, propertyName);
1014 
1015             QtVariantProperty *property = m_nameToProperty.value(propertyName, 0);
1016             bool newProperty = property == 0;
1017             if (newProperty) {
1018                 property = m_propertyManager->addProperty(type, propertyName);
1019                 if (property) {
1020                     newProperty = true;
1021                     if (type == DesignerPropertyManager::enumTypeId()) {
1022                         const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(value);
1023                         QStringList names;
1024                         QStringListIterator it(e.metaEnum.keys());
1025                         while (it.hasNext())
1026                             names.append(it.next());
1027                         m_updatingBrowser = true;
1028                         property->setAttribute(m_strings.m_enumNamesAttribute, names);
1029                         m_updatingBrowser = false;
1030                     } else if (type == DesignerPropertyManager::designerFlagTypeId()) {
1031                         const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(value);
1032                         QList<QPair<QString, uint> > flags;
1033                         QStringListIterator it(f.metaFlags.keys());
1034                         while (it.hasNext()) {
1035                             const QString name = it.next();
1036                             const uint val = f.metaFlags.keyToValue(name);
1037                             flags.append(qMakePair(name, val));
1038                         }
1039                         m_updatingBrowser = true;
1040                         QVariant v;
1041                         v.setValue(flags);
1042                         property->setAttribute(m_strings.m_flagsAttribute, v);
1043                         m_updatingBrowser = false;
1044                     }
1045                 }
1046             }
1047 
1048             if (property != 0) {
1049                 const bool dynamicProperty = (dynamicSheet && dynamicSheet->isDynamicProperty(i))
1050                             || (sheet && sheet->isDefaultDynamicProperty(i));
1051                 switch (type) {
1052                 case QVariant::Palette:
1053                     setupPaletteProperty(property);
1054                     break;
1055                 case QVariant::KeySequence:
1056                     //addCommentProperty(property, propertyName);
1057                     break;
1058                 default:
1059                     break;
1060                 }
1061                 if (type == QVariant::String || type == qMetaTypeId<PropertySheetStringValue>())
1062                     setupStringProperty(property, isMainContainer);
1063                 property->setAttribute(m_strings.m_resettableAttribute, m_propertySheet->hasReset(i));
1064 
1065                 const QString groupName = m_propertySheet->propertyGroup(i);
1066                 QtVariantProperty *groupProperty = 0;
1067 
1068                 if (newProperty) {
1069                     QMap<QString, QtVariantProperty*>::const_iterator itPrev = m_nameToProperty.insert(propertyName, property);
1070                     m_propertyToGroup[property] = groupName;
1071                     if (m_sorting) {
1072                         QtProperty *previous = 0;
1073                         if (itPrev != m_nameToProperty.constBegin())
1074                             previous = (--itPrev).value();
1075                         m_currentBrowser->insertProperty(property, previous);
1076                     }
1077                 }
1078                 const QMap<QString, QtVariantProperty*>::const_iterator gnit = m_nameToGroup.constFind(groupName);
1079                 if (gnit != m_nameToGroup.constEnd()) {
1080                     groupProperty = gnit.value();
1081                 } else {
1082                     groupProperty = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), groupName);
1083                     QtBrowserItem *item = 0;
1084                     if (!m_sorting)
1085                          item = m_currentBrowser->insertProperty(groupProperty, lastGroup);
1086                     m_nameToGroup[groupName] = groupProperty;
1087                     m_groups.append(groupProperty);
1088                     if (dynamicProperty)
1089                         m_dynamicGroup = groupProperty;
1090                     if (m_currentBrowser == m_treeBrowser && item) {
1091                         m_treeBrowser->setBackgroundColor(item, propertyColor(groupProperty));
1092                         groupProperty->setModified(true);
1093                     }
1094                 }
1095                 /*  Group changed or new group. Append to last subproperty of
1096                  * that group. Note that there are cases in which a derived
1097                  * property sheet appends fake properties for the class
1098                  * which will appear after the layout group properties
1099                  * (QWizardPage). To make them appear at the end of the
1100                  * actual class group, goto last element. */
1101                 if (lastGroup != groupProperty) {
1102                     lastGroup = groupProperty;
1103                     lastProperty = 0;  // Append at end
1104                     const QList<QtProperty*> subProperties = lastGroup->subProperties();
1105                     if (!subProperties.empty())
1106                         lastProperty = subProperties.back();
1107                     lastGroup = groupProperty;
1108                 }
1109                 if (!m_groups.contains(groupProperty))
1110                     m_groups.append(groupProperty);
1111                 if (newProperty)
1112                     groupProperty->insertSubProperty(property, lastProperty);
1113 
1114                 lastProperty = property;
1115 
1116                 updateBrowserValue(property, value);
1117 
1118                 property->setModified(m_propertySheet->isChanged(i));
1119                 if (propertyName == QLatin1String("geometry") && type == QVariant::Rect) {
1120                     QList<QtProperty *> subProperties = property->subProperties();
1121                     foreach (QtProperty *subProperty, subProperties) {
1122                         const QString subPropertyName = subProperty->propertyName();
1123                         if (subPropertyName == QLatin1String("X") || subPropertyName == QLatin1String("Y"))
1124                             subProperty->setEnabled(!isMainContainer);
1125                     }
1126                 }
1127             } else {
1128                 qWarning("%s", qPrintable(msgUnsupportedType(propertyName, type)));
1129             }
1130         }
1131     }
1132     QMap<QString, QtVariantProperty *> groups = m_nameToGroup;
1133     QMapIterator<QString, QtVariantProperty *> itGroup(groups);
1134     while (itGroup.hasNext()) {
1135         QtVariantProperty *groupProperty = itGroup.next().value();
1136         if (groupProperty->subProperties().empty()) {
1137             if (groupProperty == m_dynamicGroup)
1138                 m_dynamicGroup = 0;
1139             delete groupProperty;
1140             m_nameToGroup.remove(itGroup.key());
1141         }
1142     }
1143     const bool addEnabled = dynamicSheet ? dynamicSheet->dynamicPropertiesAllowed() : false;
1144     m_addDynamicAction->setEnabled(addEnabled);
1145     m_removeDynamicAction->setEnabled(false);
1146     applyExpansionState();
1147     applyFilter();
1148     // In the first setObject() call following the addition of a dynamic property, focus and edit it.
1149     if (editNewDynamicProperty) {
1150         // Have QApplication process the events related to completely closing the modal 'add' dialog,
1151         // otherwise, we cannot focus the property editor in docked mode.
1152         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1153         editProperty(m_recentlyAddedDynamicProperty);
1154     }
1155     m_recentlyAddedDynamicProperty.clear();
1156     m_filterWidget->setEnabled(object);
1157 }
1158 
reloadResourceProperties()1159 void PropertyEditor::reloadResourceProperties()
1160 {
1161     m_updatingBrowser = true;
1162     m_propertyManager->reloadResourceProperties();
1163     m_updatingBrowser = false;
1164 }
1165 
nonFakePropertyBrowserItem(QtBrowserItem * item) const1166 QtBrowserItem *PropertyEditor::nonFakePropertyBrowserItem(QtBrowserItem *item) const
1167 {
1168     // Top-level properties are QObject/QWidget groups, etc. Find first item property below
1169     // which should be nonfake
1170     const QList<QtBrowserItem *> topLevelItems = m_currentBrowser->topLevelItems();
1171     do {
1172         if (topLevelItems.contains(item->parent()))
1173             return item;
1174         item = item->parent();
1175     } while (item);
1176     return 0;
1177 }
1178 
currentPropertyName() const1179 QString PropertyEditor::currentPropertyName() const
1180 {
1181     if (QtBrowserItem *browserItem = m_currentBrowser->currentItem())
1182         if (QtBrowserItem *topLevelItem = nonFakePropertyBrowserItem(browserItem)) {
1183             return topLevelItem->property()->propertyName();
1184         }
1185     return QString();
1186 }
1187 
slotResetProperty(QtProperty * property)1188 void PropertyEditor::slotResetProperty(QtProperty *property)
1189 {
1190     QDesignerFormWindowInterface *form = m_core->formWindowManager()->activeFormWindow();
1191     if (!form)
1192         return;
1193 
1194     if (m_propertyManager->resetFontSubProperty(property))
1195         return;
1196 
1197     if (m_propertyManager->resetIconSubProperty(property))
1198         return;
1199 
1200     if (!m_propertyToGroup.contains(property))
1201         return;
1202 
1203     emit resetProperty(property->propertyName());
1204 }
1205 
slotValueChanged(QtProperty * property,const QVariant & value,bool enableSubPropertyHandling)1206 void PropertyEditor::slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling)
1207 {
1208     if (m_updatingBrowser)
1209         return;
1210 
1211     if (!m_propertySheet)
1212         return;
1213 
1214     QtVariantProperty *varProp = m_propertyManager->variantProperty(property);
1215 
1216     if (!varProp)
1217         return;
1218 
1219     if (!m_propertyToGroup.contains(property))
1220         return;
1221 
1222     if (varProp->propertyType() == QtVariantPropertyManager::enumTypeId()) {
1223         PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(m_propertySheet->property(m_propertySheet->indexOf(property->propertyName())));
1224         const int val = value.toInt();
1225         const QString valName = varProp->attributeValue(m_strings.m_enumNamesAttribute).toStringList().at(val);
1226         bool ok = false;
1227         e.value = e.metaEnum.parseEnum(valName, &ok);
1228         Q_ASSERT(ok);
1229         QVariant v;
1230         v.setValue(e);
1231         emitPropertyValueChanged(property->propertyName(), v, true);
1232         return;
1233     }
1234 
1235     emitPropertyValueChanged(property->propertyName(), value, enableSubPropertyHandling);
1236 }
1237 
isDynamicProperty(const QtBrowserItem * item) const1238 bool PropertyEditor::isDynamicProperty(const QtBrowserItem* item) const
1239 {
1240     if (!item)
1241         return false;
1242 
1243     const QDesignerDynamicPropertySheetExtension *dynamicSheet =
1244             qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object);
1245 
1246     if (!dynamicSheet)
1247         return false;
1248 
1249     if (m_propertyToGroup.contains(item->property())
1250                 && dynamicSheet->isDynamicProperty(m_propertySheet->indexOf(item->property()->propertyName())))
1251         return true;
1252     return false;
1253 }
1254 
editProperty(const QString & name)1255 void PropertyEditor::editProperty(const QString &name)
1256 {
1257     // find the browser item belonging to the property, make it current and edit it
1258     QtBrowserItem *browserItem = 0;
1259     if (QtVariantProperty *property = m_nameToProperty.value(name, 0)) {
1260         const QList<QtBrowserItem *> items = m_currentBrowser->items(property);
1261         if (items.size() == 1)
1262             browserItem = items.front();
1263     }
1264     if (browserItem == 0)
1265         return;
1266     m_currentBrowser->setFocus(Qt::OtherFocusReason);
1267     if (m_currentBrowser == m_treeBrowser) { // edit is currently only supported in tree view
1268         m_treeBrowser->editItem(browserItem);
1269     } else {
1270         m_currentBrowser->setCurrentItem(browserItem);
1271     }
1272 }
1273 
slotCurrentItemChanged(QtBrowserItem * item)1274 void PropertyEditor::slotCurrentItemChanged(QtBrowserItem *item)
1275 {
1276     m_removeDynamicAction->setEnabled(isDynamicProperty(item));
1277 
1278 }
1279 
slotRemoveDynamicProperty()1280 void PropertyEditor::slotRemoveDynamicProperty()
1281 {
1282     if (QtBrowserItem* item = m_currentBrowser->currentItem())
1283         if (isDynamicProperty(item))
1284             emit removeDynamicProperty(item->property()->propertyName());
1285 }
1286 
setFilter(const QString & pattern)1287 void PropertyEditor::setFilter(const QString &pattern)
1288 {
1289     m_filterPattern = pattern;
1290     applyFilter();
1291 }
1292 }
1293 
1294 QT_END_NAMESPACE
1295