qtgroupboxpropertybrowser.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2016 The Qt Company Ltd.
  4. ** Contact: https://www.qt.io/licensing/
  5. **
  6. ** This file is part of the tools applications 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 https://www.qt.io/terms-conditions. For further
  15. ** information use the contact form at https://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 3 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL3 included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 3 requirements
  23. ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
  24. **
  25. ** GNU General Public License Usage
  26. ** Alternatively, this file may be used under the terms of the GNU
  27. ** General Public License version 2.0 or (at your option) the GNU General
  28. ** Public license version 3 or any later version approved by the KDE Free
  29. ** Qt Foundation. The licenses are as published by the Free Software
  30. ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
  31. ** included in the packaging of this file. Please review the following
  32. ** information to ensure the GNU General Public License requirements will
  33. ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
  34. ** https://www.gnu.org/licenses/gpl-3.0.html.
  35. **
  36. ** $QT_END_LICENSE$
  37. **
  38. ****************************************************************************/
  39. #include "qtgroupboxpropertybrowser.h"
  40. #include <QtCore/QSet>
  41. #include <QtWidgets/QGridLayout>
  42. #include <QtWidgets/QLabel>
  43. #include <QtWidgets/QGroupBox>
  44. #include <QtCore/QTimer>
  45. #include <QtCore/QMap>
  46. QT_BEGIN_NAMESPACE
  47. class QtGroupBoxPropertyBrowserPrivate
  48. {
  49. QtGroupBoxPropertyBrowser *q_ptr;
  50. Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser)
  51. public:
  52. void init(QWidget *parent);
  53. void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
  54. void propertyRemoved(QtBrowserItem *index);
  55. void propertyChanged(QtBrowserItem *index);
  56. QWidget *createEditor(QtProperty *property, QWidget *parent) const
  57. { return q_ptr->createEditor(property, parent); }
  58. void slotEditorDestroyed();
  59. void slotUpdate();
  60. struct WidgetItem
  61. {
  62. QWidget *widget{nullptr}; // can be null
  63. QLabel *label{nullptr};
  64. QLabel *widgetLabel{nullptr};
  65. QGroupBox *groupBox{nullptr};
  66. QGridLayout *layout{nullptr};
  67. QFrame *line{nullptr};
  68. WidgetItem *parent{nullptr};
  69. QList<WidgetItem *> children;
  70. };
  71. private:
  72. void updateLater();
  73. void updateItem(WidgetItem *item);
  74. void insertRow(QGridLayout *layout, int row) const;
  75. void removeRow(QGridLayout *layout, int row) const;
  76. bool hasHeader(WidgetItem *item) const;
  77. QMap<QtBrowserItem *, WidgetItem *> m_indexToItem;
  78. QMap<WidgetItem *, QtBrowserItem *> m_itemToIndex;
  79. QMap<QWidget *, WidgetItem *> m_widgetToItem;
  80. QGridLayout *m_mainLayout;
  81. QList<WidgetItem *> m_children;
  82. QList<WidgetItem *> m_recreateQueue;
  83. };
  84. void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent)
  85. {
  86. m_mainLayout = new QGridLayout();
  87. parent->setLayout(m_mainLayout);
  88. QLayoutItem *item = new QSpacerItem(0, 0,
  89. QSizePolicy::Fixed, QSizePolicy::Expanding);
  90. m_mainLayout->addItem(item, 0, 0);
  91. }
  92. void QtGroupBoxPropertyBrowserPrivate::slotEditorDestroyed()
  93. {
  94. QWidget *editor = qobject_cast<QWidget *>(q_ptr->sender());
  95. if (!editor)
  96. return;
  97. if (!m_widgetToItem.contains(editor))
  98. return;
  99. m_widgetToItem[editor]->widget = 0;
  100. m_widgetToItem.remove(editor);
  101. }
  102. void QtGroupBoxPropertyBrowserPrivate::slotUpdate()
  103. {
  104. for (WidgetItem *item : qAsConst(m_recreateQueue)) {
  105. WidgetItem *par = item->parent;
  106. QWidget *w = 0;
  107. QGridLayout *l = 0;
  108. int oldRow = -1;
  109. if (!par) {
  110. w = q_ptr;
  111. l = m_mainLayout;
  112. oldRow = m_children.indexOf(item);
  113. } else {
  114. w = par->groupBox;
  115. l = par->layout;
  116. oldRow = par->children.indexOf(item);
  117. if (hasHeader(par))
  118. oldRow += 2;
  119. }
  120. if (item->widget) {
  121. item->widget->setParent(w);
  122. } else if (item->widgetLabel) {
  123. item->widgetLabel->setParent(w);
  124. } else {
  125. item->widgetLabel = new QLabel(w);
  126. }
  127. int span = 1;
  128. if (item->widget)
  129. l->addWidget(item->widget, oldRow, 1, 1, 1);
  130. else if (item->widgetLabel)
  131. l->addWidget(item->widgetLabel, oldRow, 1, 1, 1);
  132. else
  133. span = 2;
  134. item->label = new QLabel(w);
  135. item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
  136. l->addWidget(item->label, oldRow, 0, 1, span);
  137. updateItem(item);
  138. }
  139. m_recreateQueue.clear();
  140. }
  141. void QtGroupBoxPropertyBrowserPrivate::updateLater()
  142. {
  143. QTimer::singleShot(0, q_ptr, SLOT(slotUpdate()));
  144. }
  145. void QtGroupBoxPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
  146. {
  147. WidgetItem *afterItem = m_indexToItem.value(afterIndex);
  148. WidgetItem *parentItem = m_indexToItem.value(index->parent());
  149. WidgetItem *newItem = new WidgetItem();
  150. newItem->parent = parentItem;
  151. QGridLayout *layout = 0;
  152. QWidget *parentWidget = 0;
  153. int row = -1;
  154. if (!afterItem) {
  155. row = 0;
  156. if (parentItem)
  157. parentItem->children.insert(0, newItem);
  158. else
  159. m_children.insert(0, newItem);
  160. } else {
  161. if (parentItem) {
  162. row = parentItem->children.indexOf(afterItem) + 1;
  163. parentItem->children.insert(row, newItem);
  164. } else {
  165. row = m_children.indexOf(afterItem) + 1;
  166. m_children.insert(row, newItem);
  167. }
  168. }
  169. if (parentItem && hasHeader(parentItem))
  170. row += 2;
  171. if (!parentItem) {
  172. layout = m_mainLayout;
  173. parentWidget = q_ptr;;
  174. } else {
  175. if (!parentItem->groupBox) {
  176. m_recreateQueue.removeAll(parentItem);
  177. WidgetItem *par = parentItem->parent;
  178. QWidget *w = 0;
  179. QGridLayout *l = 0;
  180. int oldRow = -1;
  181. if (!par) {
  182. w = q_ptr;
  183. l = m_mainLayout;
  184. oldRow = m_children.indexOf(parentItem);
  185. } else {
  186. w = par->groupBox;
  187. l = par->layout;
  188. oldRow = par->children.indexOf(parentItem);
  189. if (hasHeader(par))
  190. oldRow += 2;
  191. }
  192. parentItem->groupBox = new QGroupBox(w);
  193. parentItem->layout = new QGridLayout();
  194. parentItem->groupBox->setLayout(parentItem->layout);
  195. if (parentItem->label) {
  196. l->removeWidget(parentItem->label);
  197. delete parentItem->label;
  198. parentItem->label = 0;
  199. }
  200. if (parentItem->widget) {
  201. l->removeWidget(parentItem->widget);
  202. parentItem->widget->setParent(parentItem->groupBox);
  203. parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2);
  204. parentItem->line = new QFrame(parentItem->groupBox);
  205. } else if (parentItem->widgetLabel) {
  206. l->removeWidget(parentItem->widgetLabel);
  207. delete parentItem->widgetLabel;
  208. parentItem->widgetLabel = 0;
  209. }
  210. if (parentItem->line) {
  211. parentItem->line->setFrameShape(QFrame::HLine);
  212. parentItem->line->setFrameShadow(QFrame::Sunken);
  213. parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2);
  214. }
  215. l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2);
  216. updateItem(parentItem);
  217. }
  218. layout = parentItem->layout;
  219. parentWidget = parentItem->groupBox;
  220. }
  221. newItem->label = new QLabel(parentWidget);
  222. newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
  223. newItem->widget = createEditor(index->property(), parentWidget);
  224. if (!newItem->widget) {
  225. newItem->widgetLabel = new QLabel(parentWidget);
  226. } else {
  227. QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed()));
  228. m_widgetToItem[newItem->widget] = newItem;
  229. }
  230. insertRow(layout, row);
  231. int span = 1;
  232. if (newItem->widget)
  233. layout->addWidget(newItem->widget, row, 1);
  234. else if (newItem->widgetLabel)
  235. layout->addWidget(newItem->widgetLabel, row, 1);
  236. else
  237. span = 2;
  238. layout->addWidget(newItem->label, row, 0, 1, span);
  239. m_itemToIndex[newItem] = index;
  240. m_indexToItem[index] = newItem;
  241. updateItem(newItem);
  242. }
  243. void QtGroupBoxPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index)
  244. {
  245. WidgetItem *item = m_indexToItem.value(index);
  246. m_indexToItem.remove(index);
  247. m_itemToIndex.remove(item);
  248. WidgetItem *parentItem = item->parent;
  249. int row = -1;
  250. if (parentItem) {
  251. row = parentItem->children.indexOf(item);
  252. parentItem->children.removeAt(row);
  253. if (hasHeader(parentItem))
  254. row += 2;
  255. } else {
  256. row = m_children.indexOf(item);
  257. m_children.removeAt(row);
  258. }
  259. if (item->widget)
  260. delete item->widget;
  261. if (item->label)
  262. delete item->label;
  263. if (item->widgetLabel)
  264. delete item->widgetLabel;
  265. if (item->groupBox)
  266. delete item->groupBox;
  267. if (!parentItem) {
  268. removeRow(m_mainLayout, row);
  269. } else if (parentItem->children.count() != 0) {
  270. removeRow(parentItem->layout, row);
  271. } else {
  272. WidgetItem *par = parentItem->parent;
  273. QGridLayout *l = 0;
  274. int oldRow = -1;
  275. if (!par) {
  276. l = m_mainLayout;
  277. oldRow = m_children.indexOf(parentItem);
  278. } else {
  279. l = par->layout;
  280. oldRow = par->children.indexOf(parentItem);
  281. if (hasHeader(par))
  282. oldRow += 2;
  283. }
  284. if (parentItem->widget) {
  285. parentItem->widget->hide();
  286. parentItem->widget->setParent(0);
  287. } else if (parentItem->widgetLabel) {
  288. parentItem->widgetLabel->hide();
  289. parentItem->widgetLabel->setParent(0);
  290. } else {
  291. //parentItem->widgetLabel = new QLabel(w);
  292. }
  293. l->removeWidget(parentItem->groupBox);
  294. delete parentItem->groupBox;
  295. parentItem->groupBox = 0;
  296. parentItem->line = 0;
  297. parentItem->layout = 0;
  298. if (!m_recreateQueue.contains(parentItem))
  299. m_recreateQueue.append(parentItem);
  300. updateLater();
  301. }
  302. m_recreateQueue.removeAll(item);
  303. delete item;
  304. }
  305. void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const
  306. {
  307. QMap<QLayoutItem *, QRect> itemToPos;
  308. int idx = 0;
  309. while (idx < layout->count()) {
  310. int r, c, rs, cs;
  311. layout->getItemPosition(idx, &r, &c, &rs, &cs);
  312. if (r >= row) {
  313. itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs);
  314. } else {
  315. idx++;
  316. }
  317. }
  318. const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd();
  319. for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) {
  320. const QRect r = it.value();
  321. layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
  322. }
  323. }
  324. void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const
  325. {
  326. QMap<QLayoutItem *, QRect> itemToPos;
  327. int idx = 0;
  328. while (idx < layout->count()) {
  329. int r, c, rs, cs;
  330. layout->getItemPosition(idx, &r, &c, &rs, &cs);
  331. if (r > row) {
  332. itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs);
  333. } else {
  334. idx++;
  335. }
  336. }
  337. const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd();
  338. for (QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) {
  339. const QRect r = it.value();
  340. layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
  341. }
  342. }
  343. bool QtGroupBoxPropertyBrowserPrivate::hasHeader(WidgetItem *item) const
  344. {
  345. if (item->widget)
  346. return true;
  347. return false;
  348. }
  349. void QtGroupBoxPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
  350. {
  351. WidgetItem *item = m_indexToItem.value(index);
  352. updateItem(item);
  353. }
  354. void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item)
  355. {
  356. QtProperty *property = m_itemToIndex[item]->property();
  357. if (item->groupBox) {
  358. QFont font = item->groupBox->font();
  359. font.setUnderline(property->isModified());
  360. item->groupBox->setFont(font);
  361. item->groupBox->setTitle(property->propertyName());
  362. item->groupBox->setToolTip(property->descriptionToolTip());
  363. item->groupBox->setStatusTip(property->statusTip());
  364. item->groupBox->setWhatsThis(property->whatsThis());
  365. item->groupBox->setEnabled(property->isEnabled());
  366. }
  367. if (item->label) {
  368. QFont font = item->label->font();
  369. font.setUnderline(property->isModified());
  370. item->label->setFont(font);
  371. item->label->setText(property->propertyName());
  372. item->label->setToolTip(property->descriptionToolTip());
  373. item->label->setStatusTip(property->statusTip());
  374. item->label->setWhatsThis(property->whatsThis());
  375. item->label->setEnabled(property->isEnabled());
  376. }
  377. if (item->widgetLabel) {
  378. QFont font = item->widgetLabel->font();
  379. font.setUnderline(false);
  380. item->widgetLabel->setFont(font);
  381. item->widgetLabel->setText(property->valueText());
  382. item->widgetLabel->setEnabled(property->isEnabled());
  383. }
  384. if (item->widget) {
  385. QFont font = item->widget->font();
  386. font.setUnderline(false);
  387. item->widget->setFont(font);
  388. item->widget->setEnabled(property->isEnabled());
  389. const QString valueToolTip = property->valueToolTip();
  390. item->widget->setToolTip(valueToolTip.isEmpty() ? property->valueText() : valueToolTip);
  391. }
  392. //item->setIcon(1, property->valueIcon());
  393. }
  394. /*!
  395. \class QtGroupBoxPropertyBrowser
  396. \internal
  397. \inmodule QtDesigner
  398. \since 4.4
  399. \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox
  400. based property browser.
  401. A property browser is a widget that enables the user to edit a
  402. given set of properties. Each property is represented by a label
  403. specifying the property's name, and an editing widget (e.g. a line
  404. edit or a combobox) holding its value. A property can have zero or
  405. more subproperties.
  406. QtGroupBoxPropertyBrowser provides group boxes for all nested
  407. properties, i.e. subproperties are enclosed by a group box with
  408. the parent property's name as its title. For example:
  409. \image qtgroupboxpropertybrowser.png
  410. Use the QtAbstractPropertyBrowser API to add, insert and remove
  411. properties from an instance of the QtGroupBoxPropertyBrowser
  412. class. The properties themselves are created and managed by
  413. implementations of the QtAbstractPropertyManager class.
  414. \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser
  415. */
  416. /*!
  417. Creates a property browser with the given \a parent.
  418. */
  419. QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent)
  420. : QtAbstractPropertyBrowser(parent), d_ptr(new QtGroupBoxPropertyBrowserPrivate)
  421. {
  422. d_ptr->q_ptr = this;
  423. d_ptr->init(this);
  424. }
  425. /*!
  426. Destroys this property browser.
  427. Note that the properties that were inserted into this browser are
  428. \e not destroyed since they may still be used in other
  429. browsers. The properties are owned by the manager that created
  430. them.
  431. \sa QtProperty, QtAbstractPropertyManager
  432. */
  433. QtGroupBoxPropertyBrowser::~QtGroupBoxPropertyBrowser()
  434. {
  435. const QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator icend = d_ptr->m_itemToIndex.constEnd();
  436. for (QMap<QtGroupBoxPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it)
  437. delete it.key();
  438. }
  439. /*!
  440. \reimp
  441. */
  442. void QtGroupBoxPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
  443. {
  444. d_ptr->propertyInserted(item, afterItem);
  445. }
  446. /*!
  447. \reimp
  448. */
  449. void QtGroupBoxPropertyBrowser::itemRemoved(QtBrowserItem *item)
  450. {
  451. d_ptr->propertyRemoved(item);
  452. }
  453. /*!
  454. \reimp
  455. */
  456. void QtGroupBoxPropertyBrowser::itemChanged(QtBrowserItem *item)
  457. {
  458. d_ptr->propertyChanged(item);
  459. }
  460. QT_END_NAMESPACE
  461. #include "moc_qtgroupboxpropertybrowser.cpp"