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