VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSelector.cpp@ 103977

Last change on this file since 103977 was 103169, checked in by vboxsync, 10 months ago

FE/Qt: bugref:10513: Removing unused types of settings selector and a bit of other unused stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.2 KB
Line 
1/* $Id: UISettingsSelector.cpp 103169 2024-02-01 17:51:58Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISettingsSelector class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QAbstractItemModel>
30#include <QAccessibleWidget>
31#include <QAction>
32#include <QActionGroup>
33#include <QItemDelegate>
34#include <QLayout>
35#include <QPainter>
36#include <QSortFilterProxyModel>
37#include <QTabWidget>
38#include <QToolButton>
39
40/* GUI includes: */
41#include "QITabWidget.h"
42#include "QITreeView.h"
43#include "UICommon.h"
44#include "UIDesktopWidgetWatchdog.h"
45#include "UIIconPool.h"
46#include "UIImageTools.h"
47#include "UISettingsPage.h"
48#include "UISettingsSelector.h"
49#include "QIToolBar.h"
50
51
52/** QAccessibleWidget extension used as an accessibility interface for UISettingsSelectorToolBar buttons. */
53class UIAccessibilityInterfaceForUISettingsSelectorToolBarButton : public QAccessibleWidget
54{
55public:
56
57 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
58 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
59 {
60 /* Creating toolbar button accessibility interface: */
61 if ( pObject
62 && strClassname == QLatin1String("QToolButton")
63 && pObject->property("Belongs to") == "UISettingsSelectorToolBar")
64 return new UIAccessibilityInterfaceForUISettingsSelectorToolBarButton(qobject_cast<QWidget*>(pObject));
65
66 /* Null by default: */
67 return 0;
68 }
69
70 /** Constructs an accessibility interface passing @a pWidget to the base-class. */
71 UIAccessibilityInterfaceForUISettingsSelectorToolBarButton(QWidget *pWidget)
72 : QAccessibleWidget(pWidget, QAccessible::Button)
73 {}
74
75 /** Returns the role. */
76 virtual QAccessible::Role role() const RT_OVERRIDE
77 {
78 /* Make sure button still alive: */
79 AssertPtrReturn(button(), QAccessible::NoRole);
80
81 /* Return role for checkable button: */
82 if (button()->isCheckable())
83 return QAccessible::RadioButton;
84
85 /* Return default role: */
86 return QAccessible::Button;
87 }
88
89 /** Returns the state. */
90 virtual QAccessible::State state() const RT_OVERRIDE
91 {
92 /* Prepare the button state: */
93 QAccessible::State state;
94
95 /* Make sure button still alive: */
96 AssertPtrReturn(button(), state);
97
98 /* Compose the button state: */
99 state.checkable = button()->isCheckable();
100 state.checked = button()->isChecked();
101
102 /* Return the button state: */
103 return state;
104 }
105
106private:
107
108 /** Returns corresponding toolbar button. */
109 QToolButton *button() const { return qobject_cast<QToolButton*>(widget()); }
110};
111
112
113/** QITreeViewItem subclass used as selector tree-view item. */
114class UISelectorTreeViewItem : public QITreeViewItem
115{
116 Q_OBJECT;
117
118public:
119
120 /** Constructs selector item passing @a pParent to the base-class.
121 * This is constructor for root-item only. */
122 UISelectorTreeViewItem(QITreeView *pParent);
123 /** Constructs selector item passing @a pParentItem to the base-class.
124 * This is constructor for rest of items we need.
125 * @param iID Brings the item ID.
126 * @param icon Brings the item icon.
127 * @param strLink Brings the item link. */
128 UISelectorTreeViewItem(UISelectorTreeViewItem *pParentItem,
129 int iID,
130 const QIcon &icon,
131 const QString &strLink);
132
133 /** Returns item ID. */
134 int id() const { return m_iID; }
135 /** Returns item icon. */
136 QIcon icon() const { return m_icon; }
137 /** Returns item link. */
138 QString link() const { return m_strLink; }
139
140 /** Returns item text. */
141 virtual QString text() const RT_OVERRIDE { return m_strText; }
142 /** Defines item @a strText. */
143 virtual void setText(const QString &strText) { m_strText = strText; }
144
145 /** Returns whether item is hidden. */
146 virtual bool isHidden() const { return m_fHidden; }
147 /** Defines item is @a fHidden. */
148 virtual void setHidden(bool fHidden) { m_fHidden = fHidden; }
149
150 /** Returns the number of children. */
151 virtual int childCount() const RT_OVERRIDE { return m_children.size(); }
152 /** Returns the child item with @a iIndex. */
153 virtual UISelectorTreeViewItem *childItem(int iIndex) const RT_OVERRIDE { return m_children.at(iIndex); }
154
155 /** Adds @a pChild to this item. */
156 void addChild(UISelectorTreeViewItem *pChild) { m_children << pChild; }
157 /** Assigns @a children for this item. */
158 void setChildren(const QList<UISelectorTreeViewItem*> &children) { m_children = children; }
159 /** Returns position for the passed @a pChild. */
160 int posOfChild(UISelectorTreeViewItem *pChild) const { return m_children.indexOf(pChild); }
161
162 /** Searches for the child with @a iID specified. */
163 UISelectorTreeViewItem *childItemById(int iID) const;
164 /** Searches for the child with @a strLink specified. */
165 UISelectorTreeViewItem *childItemByLink(const QString &strLink) const;
166
167private:
168
169 /** Holds the item ID. */
170 int m_iID;
171 /** Holds the item icon. */
172 QIcon m_icon;
173 /** Holds the item link. */
174 QString m_strLink;
175 /** Holds the item text. */
176 QString m_strText;
177 /** Holds whether item is hidden. */
178 bool m_fHidden;
179
180 /** Holds the list of children. */
181 QList<UISelectorTreeViewItem*> m_children;
182};
183
184
185/** QItemDelegate subclass used as selector tree-view item delegate. */
186class UISelectorDelegate : public QItemDelegate
187{
188 Q_OBJECT;
189
190public:
191
192 /** Constructs selector item delegate passing @a pParent to the base-class. */
193 UISelectorDelegate(QObject *pParent);
194
195private:
196
197 /** Paints @a index item with specified @a option using specified @a pPainter. */
198 void paint(QPainter *pPainter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
199};
200
201
202/** QAbstractItemModel subclass used as selector model. */
203class UISelectorModel : public QAbstractItemModel
204{
205 Q_OBJECT;
206
207public:
208
209 /** Data roles. */
210 enum DataRole
211 {
212 R_Margin = Qt::UserRole + 1,
213 R_Spacing,
214 R_IconSize,
215
216 R_ItemId,
217 R_ItemPixmap,
218 R_ItemPixmapRect,
219 R_ItemName,
220 R_ItemNamePoint,
221 R_ItemHidden,
222 };
223
224 /** Constructs selector model passing @a pParent to the base-class. */
225 UISelectorModel(QITreeView *pParent);
226 /** Destructs selector model. */
227 virtual ~UISelectorModel() RT_OVERRIDE;
228
229 /** Returns row count for the passed @a parentIndex. */
230 virtual int rowCount(const QModelIndex &parentIndex = QModelIndex()) const RT_OVERRIDE;
231 /** Returns column count for the passed @a parentIndex. */
232 virtual int columnCount(const QModelIndex &parentIndex = QModelIndex()) const RT_OVERRIDE;
233
234 /** Returns parent item of @a specifiedIndex item. */
235 virtual QModelIndex parent(const QModelIndex &specifiedIndex) const RT_OVERRIDE;
236 /** Returns item specified by @a iRow, @a iColum and @a parentIndex. */
237 virtual QModelIndex index(int iRow, int iColumn, const QModelIndex &parentIndex = QModelIndex()) const RT_OVERRIDE;
238 /** Returns root item. */
239 QModelIndex root() const;
240
241 /** Returns model data for @a specifiedIndex and @a iRole. */
242 virtual QVariant data(const QModelIndex &specifiedIndex, int iRole) const RT_OVERRIDE;
243 /** Defines model data for @a specifiedIndex and @a iRole as @a value. */
244 virtual bool setData(const QModelIndex &specifiedIndex, const QVariant &value, int iRole) RT_OVERRIDE;
245
246 /** Adds item with certain @a strId. */
247 QModelIndex addItem(int iID, const QIcon &icon, const QString &strLink);
248 /** Deletes item with certain @a iID. */
249 void delItem(int iID);
250
251 /** Returns item with certain @a iID. */
252 QModelIndex findItem(int iID);
253 /** Returns item with certain @a strLink. */
254 QModelIndex findItem(const QString &strLink);
255
256private:
257
258 /** Returns model flags for @a specifiedIndex. */
259 virtual Qt::ItemFlags flags(const QModelIndex &specifiedIndex) const RT_OVERRIDE;
260
261 /** Returns a pointer to item containing within @a specifiedIndex. */
262 static UISelectorTreeViewItem *indexToItem(const QModelIndex &specifiedIndex);
263
264 /** Holds the parent tree-view reference. */
265 QITreeView *m_pParentTree;
266
267 /** Holds the root item instance. */
268 UISelectorTreeViewItem *m_pRootItem;
269};
270
271
272/** QITreeView extension used as selector tree-view. */
273class UISelectorTreeView : public QITreeView
274{
275 Q_OBJECT;
276
277public:
278
279 /** Constructs selector tree-view passing @a pParent to the base-class. */
280 UISelectorTreeView(QWidget *pParent);
281
282 /** Calculates widget minimum size-hint. */
283 virtual QSize minimumSizeHint() const RT_OVERRIDE;
284 /** Calculates widget size-hint. */
285 virtual QSize sizeHint() const RT_OVERRIDE;
286
287private:
288
289 /** Prepares all. */
290 void prepare();
291};
292
293
294/** Tree-widget column sections. */
295enum TreeWidgetSection
296{
297 TreeWidgetSection_Category = 0,
298 TreeWidgetSection_Id,
299 TreeWidgetSection_Link,
300 TreeWidgetSection_Max
301};
302
303
304/** Simple container of all the selector item data. */
305class UISelectorItem
306{
307public:
308
309 /** Constructs selector item.
310 * @param icon Brings the item icon.
311 * @param iID Brings the item ID.
312 * @param strLink Brings the item link.
313 * @param pPage Brings the item page reference.
314 * @param iParentID Brings the item parent ID. */
315 UISelectorItem(const QIcon &icon, int iID, const QString &strLink, UISettingsPage *pPage, int iParentID)
316 : m_icon(icon)
317 , m_iID(iID)
318 , m_strLink(strLink)
319 , m_pPage(pPage)
320 , m_iParentID(iParentID)
321 {}
322
323 /** Destructs selector item. */
324 virtual ~UISelectorItem() {}
325
326 /** Returns the item icon. */
327 QIcon icon() const { return m_icon; }
328 /** Returns the item text. */
329 QString text() const { return m_strText; }
330 /** Defines the item @a strText. */
331 void setText(const QString &strText) { m_strText = strText; }
332 /** Returns the item ID. */
333 int id() const { return m_iID; }
334 /** Returns the item link. */
335 QString link() const { return m_strLink; }
336 /** Returns the item page reference. */
337 UISettingsPage *page() const { return m_pPage; }
338 /** Returns the item parent ID. */
339 int parentID() const { return m_iParentID; }
340
341protected:
342
343 /** Holds the item icon. */
344 QIcon m_icon;
345 /** Holds the item text. */
346 QString m_strText;
347 /** Holds the item ID. */
348 int m_iID;
349 /** Holds the item link. */
350 QString m_strLink;
351 /** Holds the item page reference. */
352 UISettingsPage *m_pPage;
353 /** Holds the item parent ID. */
354 int m_iParentID;
355};
356
357
358/** UISelectorItem subclass used as tab-widget selector item. */
359class UISelectorActionItem : public UISelectorItem
360{
361public:
362
363 /** Constructs selector item.
364 * @param icon Brings the item icon.
365 * @param iID Brings the item ID.
366 * @param strLink Brings the item link.
367 * @param pPage Brings the item page reference.
368 * @param iParentID Brings the item parent ID.
369 * @param pParent Brings the item parent. */
370 UISelectorActionItem(const QIcon &icon, int iID, const QString &strLink, UISettingsPage *pPage, int iParentID, QObject *pParent)
371 : UISelectorItem(icon, iID, strLink, pPage, iParentID)
372 , m_pAction(new QAction(icon, QString(), pParent))
373 , m_pTabWidget(0)
374 {
375 m_pAction->setCheckable(true);
376 }
377
378 /** Returns the action instance. */
379 QAction *action() const { return m_pAction; }
380
381 /** Defines the @a pTabWidget instance. */
382 void setTabWidget(QTabWidget *pTabWidget) { m_pTabWidget = pTabWidget; }
383 /** Returns the tab-widget instance. */
384 QTabWidget *tabWidget() const { return m_pTabWidget; }
385
386protected:
387
388 /** Holds the action instance. */
389 QAction *m_pAction;
390 /** Holds the tab-widget instance. */
391 QTabWidget *m_pTabWidget;
392};
393
394
395/*********************************************************************************************************************************
396* Class UISelectorTreeViewItem implementation. *
397*********************************************************************************************************************************/
398
399UISelectorTreeViewItem::UISelectorTreeViewItem(QITreeView *pParent)
400 : QITreeViewItem(pParent)
401 , m_fHidden(false)
402{
403}
404
405UISelectorTreeViewItem::UISelectorTreeViewItem(UISelectorTreeViewItem *pParentItem,
406 int iID,
407 const QIcon &icon,
408 const QString &strLink)
409 : QITreeViewItem(pParentItem)
410 , m_iID(iID)
411 , m_icon(icon)
412 , m_strLink(strLink)
413 , m_fHidden(false)
414{
415 if (pParentItem)
416 pParentItem->addChild(this);
417}
418
419UISelectorTreeViewItem *UISelectorTreeViewItem::childItemById(int iID) const
420{
421 for (int i = 0; i < childCount(); ++i)
422 if (UISelectorTreeViewItem *pItem = childItem(i))
423 if (pItem->id() == iID)
424 return pItem;
425 return 0;
426}
427
428UISelectorTreeViewItem *UISelectorTreeViewItem::childItemByLink(const QString &strLink) const
429{
430 for (int i = 0; i < childCount(); ++i)
431 if (UISelectorTreeViewItem *pItem = childItem(i))
432 if (pItem->link() == strLink)
433 return pItem;
434 return 0;
435}
436
437
438/*********************************************************************************************************************************
439* Class UISelectorDelegate implementation. *
440*********************************************************************************************************************************/
441
442UISelectorDelegate::UISelectorDelegate(QObject *pParent)
443 : QItemDelegate(pParent)
444{
445}
446
447void UISelectorDelegate::paint(QPainter *pPainter, const QStyleOptionViewItem &option, const QModelIndex &proxyIndex) const
448{
449 /* Sanity checks: */
450 AssertPtrReturnVoid(pPainter);
451 AssertReturnVoid(proxyIndex.isValid());
452
453 /* Acquire model: */
454 const QSortFilterProxyModel *pProxyModel = qobject_cast<const QSortFilterProxyModel*>(proxyIndex.model());
455 AssertPtrReturnVoid(pProxyModel);
456 const UISelectorModel *pModel = qobject_cast<const UISelectorModel*>(pProxyModel->sourceModel());
457 AssertPtrReturnVoid(pModel);
458
459 /* Acquire model index: */
460 const QModelIndex index = pProxyModel->mapToSource(proxyIndex);
461 AssertReturnVoid(index.isValid());
462
463 /* Acquire item properties: */
464 const QPalette palette = QGuiApplication::palette();
465 const QRect itemRectangle = option.rect;
466 const QStyle::State enmState = option.state;
467 const bool fChosen = enmState & QStyle::State_Selected;
468
469 /* Draw background: */
470 QColor backColor;
471 if (fChosen)
472 {
473 /* Prepare painter path: */
474 QPainterPath painterPath;
475 painterPath.lineTo(itemRectangle.width() - itemRectangle.height(), 0);
476 painterPath.lineTo(itemRectangle.width(), itemRectangle.height());
477 painterPath.lineTo(0, itemRectangle.height());
478 painterPath.closeSubpath();
479 painterPath.translate(itemRectangle.topLeft());
480
481 /* Prepare painting gradient: */
482 backColor = palette.color(QPalette::Active, QPalette::Highlight);
483 const QColor bcTone1 = backColor.lighter(100);
484 const QColor bcTone2 = backColor.lighter(120);
485 QLinearGradient grad(itemRectangle.topLeft(), itemRectangle.bottomRight());
486 grad.setColorAt(0, bcTone1);
487 grad.setColorAt(1, bcTone2);
488
489 /* Paint fancy shape: */
490 pPainter->save();
491 pPainter->setClipPath(painterPath);
492 pPainter->setRenderHint(QPainter::Antialiasing);
493 pPainter->fillPath(painterPath, grad);
494 pPainter->strokePath(painterPath, uiCommon().isInDarkMode() ? backColor.lighter(120) : backColor.darker(110));
495 pPainter->restore();
496 }
497 else
498 {
499 /* Just init painting color: */
500 backColor = palette.color(QPalette::Active, QPalette::Window);
501 }
502
503 /* Draw icon: */
504 const QRect itemPixmapRect = pModel->data(index, UISelectorModel::R_ItemPixmapRect).toRect();
505 const QPixmap itemPixmap = pModel->data(index, UISelectorModel::R_ItemPixmap).value<QPixmap>();
506 pPainter->save();
507 pPainter->translate(itemRectangle.topLeft());
508 pPainter->drawPixmap(itemPixmapRect, itemPixmap);
509 pPainter->restore();
510
511 /* Draw name: */
512 const QColor foreground = suitableForegroundColor(palette, backColor);
513 const QFont font = pModel->data(index, Qt::FontRole).value<QFont>();
514 const QPoint namePoint = pModel->data(index, UISelectorModel::R_ItemNamePoint).toPoint();
515 const QString strName = pModel->data(index, UISelectorModel::R_ItemName).toString();
516 pPainter->save();
517 pPainter->translate(itemRectangle.topLeft());
518 pPainter->setPen(foreground);
519 pPainter->setFont(font);
520 pPainter->drawText(namePoint, strName);
521 pPainter->restore();
522}
523
524
525/*********************************************************************************************************************************
526* Class UISelectorModel implementation. *
527*********************************************************************************************************************************/
528
529UISelectorModel::UISelectorModel(QITreeView *pParentTree)
530 : QAbstractItemModel(pParentTree)
531 , m_pParentTree(pParentTree)
532 , m_pRootItem(new UISelectorTreeViewItem(pParentTree))
533{
534 AssertPtr(m_pParentTree);
535}
536
537UISelectorModel::~UISelectorModel()
538{
539 delete m_pRootItem;
540}
541
542int UISelectorModel::rowCount(const QModelIndex &parentIndex) const
543{
544 UISelectorTreeViewItem *pParentItem = indexToItem(parentIndex);
545 return pParentItem ? pParentItem->childCount() : 1 /* root item */;
546}
547
548int UISelectorModel::columnCount(const QModelIndex & /* parentIndex */) const
549{
550 return 1;
551}
552
553QModelIndex UISelectorModel::parent(const QModelIndex &specifiedIndex) const
554{
555 if (!specifiedIndex.isValid())
556 return QModelIndex();
557
558 UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex);
559 UISelectorTreeViewItem *pParentOfItem =
560 pItem ? qobject_cast<UISelectorTreeViewItem*>(pItem->parentItem()) : 0;
561 UISelectorTreeViewItem *pParentOfParent =
562 pParentOfItem ? qobject_cast<UISelectorTreeViewItem*>(pParentOfItem->parentItem()) : 0;
563 const int iParentPosition = pParentOfParent ? pParentOfParent->posOfChild(pParentOfItem) : 0;
564
565 return pParentOfItem ? createIndex(iParentPosition, 0, pParentOfItem) : QModelIndex();
566}
567
568QModelIndex UISelectorModel::index(int iRow, int iColumn, const QModelIndex &parentIndex) const
569{
570 if (!hasIndex(iRow, iColumn, parentIndex))
571 return QModelIndex();
572
573 UISelectorTreeViewItem *pItem = !parentIndex.isValid()
574 ? m_pRootItem
575 : indexToItem(parentIndex)->childItem(iRow);
576
577 return pItem ? createIndex(iRow, iColumn, pItem) : QModelIndex();
578}
579
580QModelIndex UISelectorModel::root() const
581{
582 return index(0, 0);
583}
584
585QVariant UISelectorModel::data(const QModelIndex &specifiedIndex, int iRole) const
586{
587 if (!specifiedIndex.isValid())
588 return QVariant();
589
590 switch (iRole)
591 {
592 /* Basic Attributes: */
593 case Qt::FontRole:
594 {
595 QFont font = m_pParentTree->font();
596 font.setBold(true);
597 return font;
598 }
599 case Qt::SizeHintRole:
600 {
601 const QFontMetrics fm(data(specifiedIndex, Qt::FontRole).value<QFont>());
602 const int iMargin = data(specifiedIndex, R_Margin).toInt();
603 const int iSpacing = data(specifiedIndex, R_Spacing).toInt();
604 const int iIconSize = data(specifiedIndex, R_IconSize).toInt();
605 const QString strName = data(specifiedIndex, R_ItemName).toString();
606 const int iMinimumContentWidth = iIconSize /* icon width */
607 + iSpacing
608 + fm.horizontalAdvance(strName) /* name width */;
609 const int iMinimumContentHeight = qMax(fm.height() /* font height */,
610 iIconSize /* icon height */);
611 const int iMinimumWidth = iMinimumContentWidth + iMargin * 2;
612 const int iMinimumHeight = iMinimumContentHeight + iMargin * 2;
613 return QSize(iMinimumWidth, iMinimumHeight);
614 }
615
616 /* Advanced Attributes: */
617 case R_Margin:
618 {
619 return QApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin) / 1.5;
620 }
621 case R_Spacing:
622 {
623 return qMax(QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing), 5) * 2;
624 }
625 case R_IconSize:
626 {
627 return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) * 1.5;
628 }
629 case R_ItemId:
630 {
631 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
632 return pItem->id();
633 return 0;
634 }
635 case R_ItemPixmap:
636 {
637 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
638 {
639 const QIcon icon = pItem->icon();
640 const int iIconSize = data(specifiedIndex, R_IconSize).toInt();
641 const qreal fDpr = m_pParentTree->window() && m_pParentTree->window()->windowHandle()
642 ? m_pParentTree->window()->windowHandle()->devicePixelRatio() : 1;
643 return icon.pixmap(QSize(iIconSize, iIconSize), fDpr);
644 }
645 return QPixmap();
646 }
647 case R_ItemPixmapRect:
648 {
649 const int iMargin = data(specifiedIndex, R_Margin).toInt();
650 const int iWidth = data(specifiedIndex, R_IconSize).toInt();
651 return QRect(iMargin, iMargin, iWidth, iWidth);
652 }
653 case R_ItemName:
654 {
655 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
656 return pItem->text();
657 return QString();
658 }
659 case R_ItemNamePoint:
660 {
661 const int iMargin = data(specifiedIndex, R_Margin).toInt();
662 const int iSpacing = data(specifiedIndex, R_Spacing).toInt();
663 const int iIconSize = data(specifiedIndex, R_IconSize).toInt();
664 const QFontMetrics fm(data(specifiedIndex, Qt::FontRole).value<QFont>());
665 const QSize sizeHint = data(specifiedIndex, Qt::SizeHintRole).toSize();
666 return QPoint(iMargin + iIconSize + iSpacing,
667 sizeHint.height() / 2 + fm.ascent() / 2 - 1 /* base line */);
668 }
669 case R_ItemHidden:
670 {
671 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
672 return pItem->isHidden() ? "hide" : "show";
673 return QString();
674 }
675
676 default:
677 break;
678 }
679
680 return QVariant();
681}
682
683bool UISelectorModel::setData(const QModelIndex &specifiedIndex, const QVariant &aValue, int iRole)
684{
685 if (!specifiedIndex.isValid())
686 return QAbstractItemModel::setData(specifiedIndex, aValue, iRole);
687
688 switch (iRole)
689 {
690 /* Advanced Attributes: */
691 case R_ItemName:
692 {
693 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
694 {
695 pItem->setText(aValue.toString());
696 emit dataChanged(specifiedIndex, specifiedIndex);
697 return true;
698 }
699 return false;
700 }
701 case R_ItemHidden:
702 {
703 if (UISelectorTreeViewItem *pItem = indexToItem(specifiedIndex))
704 {
705 pItem->setHidden(aValue.toBool());
706 emit dataChanged(specifiedIndex, specifiedIndex);
707 return true;
708 }
709 return false;
710 }
711
712 default:
713 break;
714 }
715
716 return false;
717}
718
719QModelIndex UISelectorModel::addItem(int iID, const QIcon &icon, const QString &strLink)
720{
721 beginInsertRows(root(), m_pRootItem->childCount(), m_pRootItem->childCount());
722 new UISelectorTreeViewItem(m_pRootItem, iID, icon, strLink);
723 endInsertRows();
724 return index(m_pRootItem->childCount() - 1, 0, root());
725}
726
727void UISelectorModel::delItem(int iID)
728{
729 if (UISelectorTreeViewItem *pItem = m_pRootItem->childItemById(iID))
730 {
731 const int iItemPosition = m_pRootItem->posOfChild(pItem);
732 beginRemoveRows(root(), iItemPosition, iItemPosition);
733 delete pItem;
734 endRemoveRows();
735 }
736}
737
738QModelIndex UISelectorModel::findItem(int iID)
739{
740 UISelectorTreeViewItem *pItem = m_pRootItem->childItemById(iID);
741 if (!pItem)
742 return QModelIndex();
743
744 const int iItemPosition = m_pRootItem->posOfChild(pItem);
745 return pItem ? createIndex(iItemPosition, 0, pItem) : QModelIndex();
746}
747
748QModelIndex UISelectorModel::findItem(const QString &strLink)
749{
750 UISelectorTreeViewItem *pItem = m_pRootItem->childItemByLink(strLink);
751 if (!pItem)
752 return QModelIndex();
753
754 const int iItemPosition = m_pRootItem->posOfChild(pItem);
755 return pItem ? createIndex(iItemPosition, 0, pItem) : QModelIndex();
756}
757
758Qt::ItemFlags UISelectorModel::flags(const QModelIndex &specifiedIndex) const
759{
760 return !specifiedIndex.isValid() ? QAbstractItemModel::flags(specifiedIndex)
761 : Qt::ItemIsEnabled | Qt::ItemIsSelectable;
762}
763
764/* static */
765UISelectorTreeViewItem *UISelectorModel::indexToItem(const QModelIndex &specifiedIndex)
766{
767 if (!specifiedIndex.isValid())
768 return 0;
769 return static_cast<UISelectorTreeViewItem*>(specifiedIndex.internalPointer());
770}
771
772
773/*********************************************************************************************************************************
774* Class UISelectorTreeView implementation. *
775*********************************************************************************************************************************/
776
777UISelectorTreeView::UISelectorTreeView(QWidget *pParent)
778 : QITreeView(pParent)
779{
780 prepare();
781}
782
783QSize UISelectorTreeView::minimumSizeHint() const
784{
785 /* Sanity check: */
786 QSortFilterProxyModel *pProxyModel = qobject_cast<QSortFilterProxyModel*>(model());
787 AssertPtrReturn(pProxyModel, QITreeView::minimumSizeHint());
788 UISelectorModel *pModel = qobject_cast<UISelectorModel*>(pProxyModel->sourceModel());
789 AssertPtrReturn(pModel, QITreeView::minimumSizeHint());
790
791 /* Calculate largest column width: */
792 int iMaximumColumnWidth = 0;
793 int iCumulativeColumnHeight = 0;
794 for (int i = 0; i < pModel->rowCount(pModel->root()); ++i)
795 {
796 const QModelIndex iteratedIndex = pModel->index(i, 0, pModel->root());
797 const QSize sizeHint = pModel->data(iteratedIndex, Qt::SizeHintRole).toSize();
798 const int iHeightHint = sizeHint.height();
799 iMaximumColumnWidth = qMax(iMaximumColumnWidth, sizeHint.width() + iHeightHint /* to get the fancy shape */);
800 iCumulativeColumnHeight += iHeightHint;
801 }
802
803 /* Return selector size-hint: */
804 return QSize(iMaximumColumnWidth, iCumulativeColumnHeight);
805}
806
807QSize UISelectorTreeView::sizeHint() const
808{
809 // WORKAROUND:
810 // By default QTreeView uses own size-hint
811 // which we don't like and want to ignore:
812 return minimumSizeHint();
813}
814
815void UISelectorTreeView::prepare()
816{
817 /* Configure tree-view: */
818 setSortingEnabled(true);
819 sortByColumn(0, Qt::AscendingOrder);
820 setFrameShape(QFrame::NoFrame);
821 viewport()->setAutoFillBackground(false);
822 setContextMenuPolicy(Qt::PreventContextMenu);
823 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
824 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
825 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
826
827 /* Prepare selector delegate: */
828 UISelectorDelegate *pDelegate = new UISelectorDelegate(this);
829 if (pDelegate)
830 setItemDelegate(pDelegate);
831}
832
833
834/*********************************************************************************************************************************
835* Class UISettingsSelector implementation. *
836*********************************************************************************************************************************/
837
838UISettingsSelector::UISettingsSelector(QWidget *pParent /* = 0 */)
839 : QObject(pParent)
840{
841}
842
843UISettingsSelector::~UISettingsSelector()
844{
845 qDeleteAll(m_list);
846 m_list.clear();
847}
848
849void UISettingsSelector::setItemText(int iID, const QString &strText)
850{
851 if (UISelectorItem *pTtem = findItem(iID))
852 pTtem->setText(strText);
853}
854
855QString UISettingsSelector::itemTextByPage(UISettingsPage *pPage) const
856{
857 QString strText;
858 if (UISelectorItem *pItem = findItemByPage(pPage))
859 strText = pItem->text();
860 return strText;
861}
862
863QWidget *UISettingsSelector::idToPage(int iID) const
864{
865 UISettingsPage *pPage = 0;
866 if (UISelectorItem *pItem = findItem(iID))
867 pPage = pItem->page();
868 return pPage;
869}
870
871QList<UISettingsPage*> UISettingsSelector::settingPages() const
872{
873 QList<UISettingsPage*> list;
874 foreach (UISelectorItem *pItem, m_list)
875 if (pItem->page())
876 list << pItem->page();
877 return list;
878}
879
880UISelectorItem *UISettingsSelector::findItem(int iID) const
881{
882 UISelectorItem *pResult = 0;
883 foreach (UISelectorItem *pItem, m_list)
884 if (pItem->id() == iID)
885 {
886 pResult = pItem;
887 break;
888 }
889 return pResult;
890}
891
892UISelectorItem *UISettingsSelector::findItemByLink(const QString &strLink) const
893{
894 UISelectorItem *pResult = 0;
895 foreach (UISelectorItem *pItem, m_list)
896 if (pItem->link() == strLink)
897 {
898 pResult = pItem;
899 break;
900 }
901 return pResult;
902}
903
904UISelectorItem *UISettingsSelector::findItemByPage(UISettingsPage *pPage) const
905{
906 UISelectorItem *pResult = 0;
907 foreach (UISelectorItem *pItem, m_list)
908 if (pItem->page() == pPage)
909 {
910 pResult = pItem;
911 break;
912 }
913 return pResult;
914}
915
916
917/*********************************************************************************************************************************
918* Class UISettingsSelectorTreeView implementation. *
919*********************************************************************************************************************************/
920
921UISettingsSelectorTreeView::UISettingsSelectorTreeView(QWidget *pParent /* = 0 */)
922 : UISettingsSelector(pParent)
923 , m_pTreeView(0)
924 , m_pModel(0)
925 , m_pModelProxy(0)
926{
927 prepare();
928}
929
930UISettingsSelectorTreeView::~UISettingsSelectorTreeView()
931{
932 cleanup();
933}
934
935QWidget *UISettingsSelectorTreeView::widget() const
936{
937 return m_pTreeView;
938}
939
940QWidget *UISettingsSelectorTreeView::addItem(const QString & /* strBigIcon */,
941 const QString &strMediumIcon ,
942 const QString & /* strSmallIcon */,
943 int iID,
944 const QString &strLink,
945 UISettingsPage *pPage /* = 0 */,
946 int iParentID /* = -1 */)
947{
948 QWidget *pResult = 0;
949 if (pPage)
950 {
951 /* Adjust page a bit: */
952 pPage->setContentsMargins(0, 0, 0, 0);
953 if (pPage->layout())
954 pPage->layout()->setContentsMargins(0, 0, 0, 0);
955 pResult = pPage;
956
957 /* Add selector-item object: */
958 const QIcon icon = UIIconPool::iconSet(strMediumIcon);
959 UISelectorItem *pItem = new UISelectorItem(icon, iID, strLink, pPage, iParentID);
960 if (pItem)
961 m_list.append(pItem);
962
963 /* Add model-item: */
964 m_pModel->addItem(iID, pItem->icon(), strLink);
965 }
966 return pResult;
967}
968
969void UISettingsSelectorTreeView::setItemVisible(int iID, bool fVisible)
970{
971 /* Look for the tree-view item to assign the text: */
972 QModelIndex specifiedIndex = m_pModel->findItem(iID);
973 if (specifiedIndex.isValid())
974 m_pModel->setData(specifiedIndex, !fVisible, UISelectorModel::R_ItemHidden);
975}
976
977void UISettingsSelectorTreeView::setItemText(int iID, const QString &strText)
978{
979 /* Call to base-class: */
980 UISettingsSelector::setItemText(iID, strText);
981
982 /* Look for the tree-view item to assign the text: */
983 QModelIndex specifiedIndex = m_pModel->findItem(iID);
984 if (specifiedIndex.isValid())
985 m_pModel->setData(specifiedIndex, strText, UISelectorModel::R_ItemName);
986}
987
988QString UISettingsSelectorTreeView::itemText(int iID) const
989{
990 QString strResult;
991 if (UISelectorItem *pItem = findItem(iID))
992 strResult = pItem->text();
993 return strResult;
994}
995
996int UISettingsSelectorTreeView::currentId() const
997{
998 int iID = -1;
999 const QModelIndex proxyIndex = m_pTreeView->currentIndex();
1000 const QModelIndex index = m_pModelProxy->mapToSource(proxyIndex);
1001 if (index.isValid())
1002 iID = m_pModel->data(index, UISelectorModel::R_ItemId).toString().toInt();
1003 return iID;
1004}
1005
1006int UISettingsSelectorTreeView::linkToId(const QString &strLink) const
1007{
1008 int iID = -1;
1009 const QModelIndex index = m_pModel->findItem(strLink);
1010 if (index.isValid())
1011 iID = m_pModel->data(index, UISelectorModel::R_ItemId).toString().toInt();
1012 return iID;
1013}
1014
1015void UISettingsSelectorTreeView::selectById(int iID, bool fSilently)
1016{
1017 const QModelIndex index = m_pModel->findItem(iID);
1018 const QModelIndex proxyIndex = m_pModelProxy->mapFromSource(index);
1019 if (proxyIndex.isValid())
1020 {
1021 if (fSilently)
1022 m_pTreeView->blockSignals(true);
1023 m_pTreeView->setCurrentIndex(proxyIndex);
1024 if (fSilently)
1025 m_pTreeView->blockSignals(false);
1026 }
1027}
1028
1029void UISettingsSelectorTreeView::sltHandleCurrentChanged(const QModelIndex &proxyIndex,
1030 const QModelIndex & /* previousIndex */)
1031{
1032 const QModelIndex index = m_pModelProxy->mapToSource(proxyIndex);
1033 if (index.isValid())
1034 {
1035 const int iID = m_pModel->data(index, UISelectorModel::R_ItemId).toString().toInt();
1036 Assert(iID >= 0);
1037 emit sigCategoryChanged(iID);
1038 }
1039}
1040
1041void UISettingsSelectorTreeView::prepare()
1042{
1043 /* Prepare the tree-widget: */
1044 m_pTreeView = new UISelectorTreeView(qobject_cast<QWidget*>(parent()));
1045 if (m_pTreeView)
1046 {
1047 /* Prepare the model: */
1048 m_pModel = new UISelectorModel(m_pTreeView);
1049 if (m_pModel)
1050 {
1051 /* Create proxy-model: */
1052 m_pModelProxy = new QSortFilterProxyModel(m_pTreeView);
1053 if (m_pModelProxy)
1054 {
1055 /* Configure proxy-model: */
1056 m_pModelProxy->setSortRole(UISelectorModel::R_ItemId);
1057 m_pModelProxy->setFilterRole(UISelectorModel::R_ItemHidden);
1058 m_pModelProxy->setFilterFixedString("show");
1059 m_pModelProxy->setSourceModel(m_pModel);
1060 m_pTreeView->setModel(m_pModelProxy);
1061 }
1062 const QModelIndex proxyIndex = m_pModelProxy->mapFromSource(m_pModel->root());
1063 m_pTreeView->setRootIndex(proxyIndex);
1064 }
1065
1066 /* Setup connections: */
1067 connect(m_pTreeView, &QITreeView::currentItemChanged,
1068 this, &UISettingsSelectorTreeView::sltHandleCurrentChanged);
1069 }
1070}
1071
1072void UISettingsSelectorTreeView::cleanup()
1073{
1074 /* Cleanup the model: */
1075 delete m_pModel;
1076 m_pModel = 0;
1077 /* Cleanup the tree-view: */
1078 delete m_pTreeView;
1079 m_pTreeView = 0;
1080}
1081
1082
1083#include "UISettingsSelector.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette