File indexing completed on 2024-05-12 04:35:09
0001 /**************************************************************************** 0002 ** 0003 ** Copyright (C) 2016 The Qt Company Ltd. 0004 ** Contact: https://www.qt.io/licensing/ 0005 ** 0006 ** This file is part of the tools applications of the Qt Toolkit. 0007 ** 0008 ** $QT_BEGIN_LICENSE:LGPL$ 0009 ** Commercial License Usage 0010 ** Licensees holding valid commercial Qt licenses may use this file in 0011 ** accordance with the commercial license agreement provided with the 0012 ** Software or, alternatively, in accordance with the terms contained in 0013 ** a written agreement between you and The Qt Company. For licensing terms 0014 ** and conditions see https://www.qt.io/terms-conditions. For further 0015 ** information use the contact form at https://www.qt.io/contact-us. 0016 ** 0017 ** GNU Lesser General Public License Usage 0018 ** Alternatively, this file may be used under the terms of the GNU Lesser 0019 ** General Public License version 3 as published by the Free Software 0020 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 0021 ** packaging of this file. Please review the following information to 0022 ** ensure the GNU Lesser General Public License version 3 requirements 0023 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 0024 ** 0025 ** GNU General Public License Usage 0026 ** Alternatively, this file may be used under the terms of the GNU 0027 ** General Public License version 2.0 or (at your option) the GNU General 0028 ** Public license version 3 or any later version approved by the KDE Free 0029 ** Qt Foundation. The licenses are as published by the Free Software 0030 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 0031 ** included in the packaging of this file. Please review the following 0032 ** information to ensure the GNU General Public License requirements will 0033 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 0034 ** https://www.gnu.org/licenses/gpl-3.0.html. 0035 ** 0036 ** $QT_END_LICENSE$ 0037 ** 0038 ****************************************************************************/ 0039 0040 #include "qtgroupboxpropertybrowser.h" 0041 #include <QtCore/QSet> 0042 #include <QtWidgets/QGridLayout> 0043 #include <QtWidgets/QLabel> 0044 #include <QtWidgets/QGroupBox> 0045 #include <QtCore/QTimer> 0046 #include <QtCore/QMap> 0047 0048 QT_BEGIN_NAMESPACE 0049 0050 class QtGroupBoxPropertyBrowserPrivate 0051 { 0052 QtGroupBoxPropertyBrowser *q_ptr; 0053 Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser) 0054 public: 0055 0056 void init(QWidget *parent); 0057 0058 void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); 0059 void propertyRemoved(QtBrowserItem *index); 0060 void propertyChanged(QtBrowserItem *index); 0061 QWidget *createEditor(QtProperty *property, QWidget *parent) const 0062 { return q_ptr->createEditor(property, parent); } 0063 0064 void slotEditorDestroyed(); 0065 void slotUpdate(); 0066 0067 struct WidgetItem 0068 { 0069 QWidget *widget{nullptr}; // can be null 0070 QLabel *label{nullptr}; 0071 QLabel *widgetLabel{nullptr}; 0072 QGroupBox *groupBox{nullptr}; 0073 QGridLayout *layout{nullptr}; 0074 QFrame *line{nullptr}; 0075 WidgetItem *parent{nullptr}; 0076 QList<WidgetItem *> children; 0077 }; 0078 private: 0079 void updateLater(); 0080 void updateItem(WidgetItem *item); 0081 void insertRow(QGridLayout *layout, int row) const; 0082 void removeRow(QGridLayout *layout, int row) const; 0083 0084 bool hasHeader(WidgetItem *item) const; 0085 0086 QMap<QtBrowserItem *, WidgetItem *> m_indexToItem; 0087 QMap<WidgetItem *, QtBrowserItem *> m_itemToIndex; 0088 QMap<QWidget *, WidgetItem *> m_widgetToItem; 0089 QGridLayout *m_mainLayout; 0090 QList<WidgetItem *> m_children; 0091 QList<WidgetItem *> m_recreateQueue; 0092 }; 0093 0094 void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent) 0095 { 0096 m_mainLayout = new QGridLayout(); 0097 parent->setLayout(m_mainLayout); 0098 QLayoutItem *item = new QSpacerItem(0, 0, 0099 QSizePolicy::Fixed, QSizePolicy::Expanding); 0100 m_mainLayout->addItem(item, 0, 0); 0101 } 0102 0103 void QtGroupBoxPropertyBrowserPrivate::slotEditorDestroyed() 0104 { 0105 QWidget *editor = qobject_cast<QWidget *>(q_ptr->sender()); 0106 if (!editor) 0107 return; 0108 if (!m_widgetToItem.contains(editor)) 0109 return; 0110 m_widgetToItem[editor]->widget = 0; 0111 m_widgetToItem.remove(editor); 0112 } 0113 0114 void QtGroupBoxPropertyBrowserPrivate::slotUpdate() 0115 { 0116 for (WidgetItem *item : qAsConst(m_recreateQueue)) { 0117 WidgetItem *par = item->parent; 0118 QWidget *w = 0; 0119 QGridLayout *l = 0; 0120 int oldRow = -1; 0121 if (!par) { 0122 w = q_ptr; 0123 l = m_mainLayout; 0124 oldRow = m_children.indexOf(item); 0125 } else { 0126 w = par->groupBox; 0127 l = par->layout; 0128 oldRow = par->children.indexOf(item); 0129 if (hasHeader(par)) 0130 oldRow += 2; 0131 } 0132 0133 if (item->widget) { 0134 item->widget->setParent(w); 0135 } else if (item->widgetLabel) { 0136 item->widgetLabel->setParent(w); 0137 } else { 0138 item->widgetLabel = new QLabel(w); 0139 } 0140 int span = 1; 0141 if (item->widget) 0142 l->addWidget(item->widget, oldRow, 1, 1, 1); 0143 else if (item->widgetLabel) 0144 l->addWidget(item->widgetLabel, oldRow, 1, 1, 1); 0145 else 0146 span = 2; 0147 item->label = new QLabel(w); 0148 item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0149 l->addWidget(item->label, oldRow, 0, 1, span); 0150 0151 updateItem(item); 0152 } 0153 m_recreateQueue.clear(); 0154 } 0155 0156 void QtGroupBoxPropertyBrowserPrivate::updateLater() 0157 { 0158 QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); 0159 } 0160 0161 void QtGroupBoxPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) 0162 { 0163 WidgetItem *afterItem = m_indexToItem.value(afterIndex); 0164 WidgetItem *parentItem = m_indexToItem.value(index->parent()); 0165 0166 WidgetItem *newItem = new WidgetItem(); 0167 newItem->parent = parentItem; 0168 0169 QGridLayout *layout = 0; 0170 QWidget *parentWidget = 0; 0171 int row = -1; 0172 if (!afterItem) { 0173 row = 0; 0174 if (parentItem) 0175 parentItem->children.insert(0, newItem); 0176 else 0177 m_children.insert(0, newItem); 0178 } else { 0179 if (parentItem) { 0180 row = parentItem->children.indexOf(afterItem) + 1; 0181 parentItem->children.insert(row, newItem); 0182 } else { 0183 row = m_children.indexOf(afterItem) + 1; 0184 m_children.insert(row, newItem); 0185 } 0186 } 0187 if (parentItem && hasHeader(parentItem)) 0188 row += 2; 0189 0190 if (!parentItem) { 0191 layout = m_mainLayout; 0192 parentWidget = q_ptr;; 0193 } else { 0194 if (!parentItem->groupBox) { 0195 m_recreateQueue.removeAll(parentItem); 0196 WidgetItem *par = parentItem->parent; 0197 QWidget *w = 0; 0198 QGridLayout *l = 0; 0199 int oldRow = -1; 0200 if (!par) { 0201 w = q_ptr; 0202 l = m_mainLayout; 0203 oldRow = m_children.indexOf(parentItem); 0204 } else { 0205 w = par->groupBox; 0206 l = par->layout; 0207 oldRow = par->children.indexOf(parentItem); 0208 if (hasHeader(par)) 0209 oldRow += 2; 0210 } 0211 parentItem->groupBox = new QGroupBox(w); 0212 parentItem->layout = new QGridLayout(); 0213 parentItem->groupBox->setLayout(parentItem->layout); 0214 if (parentItem->label) { 0215 l->removeWidget(parentItem->label); 0216 delete parentItem->label; 0217 parentItem->label = 0; 0218 } 0219 if (parentItem->widget) { 0220 l->removeWidget(parentItem->widget); 0221 parentItem->widget->setParent(parentItem->groupBox); 0222 parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2); 0223 parentItem->line = new QFrame(parentItem->groupBox); 0224 } else if (parentItem->widgetLabel) { 0225 l->removeWidget(parentItem->widgetLabel); 0226 delete parentItem->widgetLabel; 0227 parentItem->widgetLabel = 0; 0228 } 0229 if (parentItem->line) { 0230 parentItem->line->setFrameShape(QFrame::HLine); 0231 parentItem->line->setFrameShadow(QFrame::Sunken); 0232 parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2); 0233 } 0234 l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2); 0235 updateItem(parentItem); 0236 } 0237 layout = parentItem->layout; 0238 parentWidget = parentItem->groupBox; 0239 } 0240 0241 newItem->label = new QLabel(parentWidget); 0242 newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0243 newItem->widget = createEditor(index->property(), parentWidget); 0244 if (!newItem->widget) { 0245 newItem->widgetLabel = new QLabel(parentWidget); 0246 } else { 0247 QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); 0248 m_widgetToItem[newItem->widget] = newItem; 0249 } 0250 0251 insertRow(layout, row); 0252 int span = 1; 0253 if (newItem->widget) 0254 layout->addWidget(newItem->widget, row, 1); 0255 else if (newItem->widgetLabel) 0256 layout->addWidget(newItem->widgetLabel, row, 1); 0257 else 0258 span = 2; 0259 layout->addWidget(newItem->label, row, 0, 1, span); 0260 0261 m_itemToIndex[newItem] = index; 0262 m_indexToItem[index] = newItem; 0263 0264 updateItem(newItem); 0265 } 0266 0267 void QtGroupBoxPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) 0268 { 0269 WidgetItem *item = m_indexToItem.value(index); 0270 0271 m_indexToItem.remove(index); 0272 m_itemToIndex.remove(item); 0273 0274 WidgetItem *parentItem = item->parent; 0275 0276 int row = -1; 0277 0278 if (parentItem) { 0279 row = parentItem->children.indexOf(item); 0280 parentItem->children.removeAt(row); 0281 if (hasHeader(parentItem)) 0282 row += 2; 0283 } else { 0284 row = m_children.indexOf(item); 0285 m_children.removeAt(row); 0286 } 0287 0288 if (item->widget) 0289 delete item->widget; 0290 if (item->label) 0291 delete item->label; 0292 if (item->widgetLabel) 0293 delete item->widgetLabel; 0294 if (item->groupBox) 0295 delete item->groupBox; 0296 0297 if (!parentItem) { 0298 removeRow(m_mainLayout, row); 0299 } else if (parentItem->children.count() != 0) { 0300 removeRow(parentItem->layout, row); 0301 } else { 0302 WidgetItem *par = parentItem->parent; 0303 QGridLayout *l = 0; 0304 int oldRow = -1; 0305 if (!par) { 0306 l = m_mainLayout; 0307 oldRow = m_children.indexOf(parentItem); 0308 } else { 0309 l = par->layout; 0310 oldRow = par->children.indexOf(parentItem); 0311 if (hasHeader(par)) 0312 oldRow += 2; 0313 } 0314 0315 if (parentItem->widget) { 0316 parentItem->widget->hide(); 0317 parentItem->widget->setParent(0); 0318 } else if (parentItem->widgetLabel) { 0319 parentItem->widgetLabel->hide(); 0320 parentItem->widgetLabel->setParent(0); 0321 } else { 0322 //parentItem->widgetLabel = new QLabel(w); 0323 } 0324 l->removeWidget(parentItem->groupBox); 0325 delete parentItem->groupBox; 0326 parentItem->groupBox = 0; 0327 parentItem->line = 0; 0328 parentItem->layout = 0; 0329 if (!m_recreateQueue.contains(parentItem)) 0330 m_recreateQueue.append(parentItem); 0331 updateLater(); 0332 } 0333 m_recreateQueue.removeAll(item); 0334 0335 delete item; 0336 } 0337 0338 void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const 0339 { 0340 QMap<QLayoutItem *, QRect> itemToPos; 0341 int idx = 0; 0342 while (idx < layout->count()) { 0343 int r, c, rs, cs; 0344 layout->getItemPosition(idx, &r, &c, &rs, &cs); 0345 if (r >= row) { 0346 itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); 0347 } else { 0348 idx++; 0349 } 0350 } 0351 0352 const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); 0353 for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { 0354 const QRect r = it.value(); 0355 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); 0356 } 0357 } 0358 0359 void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const 0360 { 0361 QMap<QLayoutItem *, QRect> itemToPos; 0362 int idx = 0; 0363 while (idx < layout->count()) { 0364 int r, c, rs, cs; 0365 layout->getItemPosition(idx, &r, &c, &rs, &cs); 0366 if (r > row) { 0367 itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); 0368 } else { 0369 idx++; 0370 } 0371 } 0372 0373 const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd(); 0374 for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { 0375 const QRect r = it.value(); 0376 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); 0377 } 0378 } 0379 0380 bool QtGroupBoxPropertyBrowserPrivate::hasHeader(WidgetItem *item) const 0381 { 0382 if (item->widget) 0383 return true; 0384 return false; 0385 } 0386 0387 void QtGroupBoxPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) 0388 { 0389 WidgetItem *item = m_indexToItem.value(index); 0390 0391 updateItem(item); 0392 } 0393 0394 void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item) 0395 { 0396 QtProperty *property = m_itemToIndex[item]->property(); 0397 if (item->groupBox) { 0398 QFont font = item->groupBox->font(); 0399 font.setUnderline(property->isModified()); 0400 item->groupBox->setFont(font); 0401 item->groupBox->setTitle(property->propertyName()); 0402 item->groupBox->setToolTip(property->descriptionToolTip()); 0403 item->groupBox->setStatusTip(property->statusTip()); 0404 item->groupBox->setWhatsThis(property->whatsThis()); 0405 item->groupBox->setEnabled(property->isEnabled()); 0406 } 0407 if (item->label) { 0408 QFont font = item->label->font(); 0409 font.setUnderline(property->isModified()); 0410 item->label->setFont(font); 0411 item->label->setText(property->propertyName()); 0412 item->label->setToolTip(property->descriptionToolTip()); 0413 item->label->setStatusTip(property->statusTip()); 0414 item->label->setWhatsThis(property->whatsThis()); 0415 item->label->setEnabled(property->isEnabled()); 0416 } 0417 if (item->widgetLabel) { 0418 QFont font = item->widgetLabel->font(); 0419 font.setUnderline(false); 0420 item->widgetLabel->setFont(font); 0421 item->widgetLabel->setText(property->valueText()); 0422 item->widgetLabel->setEnabled(property->isEnabled()); 0423 } 0424 if (item->widget) { 0425 QFont font = item->widget->font(); 0426 font.setUnderline(false); 0427 item->widget->setFont(font); 0428 item->widget->setEnabled(property->isEnabled()); 0429 const QString valueToolTip = property->valueToolTip(); 0430 item->widget->setToolTip(valueToolTip.isEmpty() ? property->valueText() : valueToolTip); 0431 } 0432 //item->setIcon(1, property->valueIcon()); 0433 } 0434 0435 0436 0437 /*! 0438 \class QtGroupBoxPropertyBrowser 0439 \internal 0440 \inmodule QtDesigner 0441 \since 4.4 0442 0443 \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox 0444 based property browser. 0445 0446 A property browser is a widget that enables the user to edit a 0447 given set of properties. Each property is represented by a label 0448 specifying the property's name, and an editing widget (e.g. a line 0449 edit or a combobox) holding its value. A property can have zero or 0450 more subproperties. 0451 0452 QtGroupBoxPropertyBrowser provides group boxes for all nested 0453 properties, i.e. subproperties are enclosed by a group box with 0454 the parent property's name as its title. For example: 0455 0456 \image qtgroupboxpropertybrowser.png 0457 0458 Use the QtAbstractPropertyBrowser API to add, insert and remove 0459 properties from an instance of the QtGroupBoxPropertyBrowser 0460 class. The properties themselves are created and managed by 0461 implementations of the QtAbstractPropertyManager class. 0462 0463 \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser 0464 */ 0465 0466 /*! 0467 Creates a property browser with the given \a parent. 0468 */ 0469 QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent) 0470 : QtAbstractPropertyBrowser(parent), d_ptr(new QtGroupBoxPropertyBrowserPrivate) 0471 { 0472 d_ptr->q_ptr = this; 0473 0474 d_ptr->init(this); 0475 } 0476 0477 /*! 0478 Destroys this property browser. 0479 0480 Note that the properties that were inserted into this browser are 0481 \e not destroyed since they may still be used in other 0482 browsers. The properties are owned by the manager that created 0483 them. 0484 0485 \sa QtProperty, QtAbstractPropertyManager 0486 */ 0487 QtGroupBoxPropertyBrowser::~QtGroupBoxPropertyBrowser() 0488 { 0489 const QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); 0490 for (QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) 0491 delete it.key(); 0492 } 0493 0494 /*! 0495 \reimp 0496 */ 0497 void QtGroupBoxPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) 0498 { 0499 d_ptr->propertyInserted(item, afterItem); 0500 } 0501 0502 /*! 0503 \reimp 0504 */ 0505 void QtGroupBoxPropertyBrowser::itemRemoved(QtBrowserItem *item) 0506 { 0507 d_ptr->propertyRemoved(item); 0508 } 0509 0510 /*! 0511 \reimp 0512 */ 0513 void QtGroupBoxPropertyBrowser::itemChanged(QtBrowserItem *item) 0514 { 0515 d_ptr->propertyChanged(item); 0516 } 0517 0518 QT_END_NAMESPACE 0519 0520 #include "moc_qtgroupboxpropertybrowser.cpp"