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"