VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QITreeView.cpp

Last change on this file was 103987, checked in by vboxsync, 2 months ago

FE/Qt: bugref:10624. Adding RT_FINAL to virtual functions whereever appropriate.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 KB
Line 
1/* $Id: QITreeView.cpp 103987 2024-03-21 12:33:33Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QITreeView class implementation.
4 */
5
6/*
7 * Copyright (C) 2009-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 <QAccessibleWidget>
30#include <QDragLeaveEvent>
31#include <QDragMoveEvent>
32#include <QDropEvent>
33#include <QMouseEvent>
34#include <QPainter>
35#include <QSortFilterProxyModel>
36
37/* GUI includes: */
38#include "QITreeView.h"
39
40/* Other VBox includes: */
41#include "iprt/assert.h"
42
43
44/** QAccessibleObject extension used as an accessibility interface for QITreeViewItem. */
45class QIAccessibilityInterfaceForQITreeViewItem : public QAccessibleObject
46{
47public:
48
49 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
50 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
51 {
52 /* Creating QITreeViewItem accessibility interface: */
53 if (pObject && strClassname == QLatin1String("QITreeViewItem"))
54 return new QIAccessibilityInterfaceForQITreeViewItem(pObject);
55
56 /* Null by default: */
57 return 0;
58 }
59
60 /** Constructs an accessibility interface passing @a pObject to the base-class. */
61 QIAccessibilityInterfaceForQITreeViewItem(QObject *pObject)
62 : QAccessibleObject(pObject)
63 {}
64
65 /** Returns the parent. */
66 virtual QAccessibleInterface *parent() const RT_OVERRIDE RT_FINAL;
67
68 /** Returns the number of children. */
69 virtual int childCount() const RT_OVERRIDE RT_FINAL;
70 /** Returns the child with the passed @a iIndex. */
71 virtual QAccessibleInterface *child(int iIndex) const RT_OVERRIDE RT_FINAL;
72 /** Returns the index of the passed @a pChild. */
73 virtual int indexOfChild(const QAccessibleInterface *pChild) const RT_OVERRIDE RT_FINAL;
74
75 /** Returns the rect. */
76 virtual QRect rect() const RT_OVERRIDE RT_FINAL;
77 /** Returns a text for the passed @a enmTextRole. */
78 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE RT_FINAL;
79
80 /** Returns the role. */
81 virtual QAccessible::Role role() const RT_OVERRIDE RT_FINAL;
82 /** Returns the state. */
83 virtual QAccessible::State state() const RT_OVERRIDE RT_FINAL;
84
85private:
86
87 /** Returns corresponding QITreeViewItem. */
88 QITreeViewItem *item() const { return qobject_cast<QITreeViewItem*>(object()); }
89};
90
91
92/** QAccessibleWidget extension used as an accessibility interface for QITreeView. */
93class QIAccessibilityInterfaceForQITreeView : public QAccessibleWidget
94{
95public:
96
97 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
98 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
99 {
100 /* Creating QITreeView accessibility interface: */
101 if (pObject && strClassname == QLatin1String("QITreeView"))
102 return new QIAccessibilityInterfaceForQITreeView(qobject_cast<QWidget*>(pObject));
103
104 /* Null by default: */
105 return 0;
106 }
107
108 /** Constructs an accessibility interface passing @a pWidget to the base-class. */
109 QIAccessibilityInterfaceForQITreeView(QWidget *pWidget)
110 : QAccessibleWidget(pWidget, QAccessible::List)
111 {}
112
113 /** Returns the number of children. */
114 virtual int childCount() const RT_OVERRIDE RT_FINAL;
115 /** Returns the child with the passed @a iIndex. */
116 virtual QAccessibleInterface *child(int iIndex) const RT_OVERRIDE RT_FINAL;
117 /** Returns the index of the passed @a pChild. */
118 virtual int indexOfChild(const QAccessibleInterface *pChild) const RT_OVERRIDE RT_FINAL;
119
120 /** Returns a text for the passed @a enmTextRole. */
121 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE RT_FINAL;
122
123private:
124
125 /** Returns corresponding QITreeView. */
126 QITreeView *tree() const { return qobject_cast<QITreeView*>(widget()); }
127};
128
129
130/*********************************************************************************************************************************
131* Class QIAccessibilityInterfaceForQITreeViewItem implementation. *
132*********************************************************************************************************************************/
133
134QAccessibleInterface *QIAccessibilityInterfaceForQITreeViewItem::parent() const
135{
136 /* Sanity check: */
137 AssertPtrReturn(item(), 0);
138
139 /* Return the parent: */
140 return item()->parentItem() ?
141 QAccessible::queryAccessibleInterface(item()->parentItem()) :
142 QAccessible::queryAccessibleInterface(item()->parentTree());
143}
144
145int QIAccessibilityInterfaceForQITreeViewItem::childCount() const
146{
147 /* Sanity check: */
148 AssertPtrReturn(item(), 0);
149 AssertPtrReturn(item()->parentTree(), 0);
150 AssertPtrReturn(item()->parentTree()->model(), 0);
151
152 /* Acquire item model-index: */
153 const QModelIndex itemIndex = item()->modelIndex();
154
155 /* Return the number of children: */
156 return item()->parentTree()->model()->rowCount(itemIndex);;
157}
158
159QAccessibleInterface *QIAccessibilityInterfaceForQITreeViewItem::child(int iIndex) const /* override */
160{
161 /* Sanity check: */
162 AssertPtrReturn(item(), 0);
163 AssertPtrReturn(item()->parentTree(), 0);
164 AssertPtrReturn(item()->parentTree()->model(), 0);
165 AssertReturn(iIndex >= 0 && iIndex < childCount(), 0);
166
167 /* Acquire item model-index: */
168 const QModelIndex itemIndex = item()->modelIndex();
169 /* Acquire child model-index: */
170 const QModelIndex childIndex = item()->parentTree()->model()->index(iIndex, 0, itemIndex);
171
172 /* Check whether we have proxy model set or source one otherwise: */
173 const QSortFilterProxyModel *pProxyModel = qobject_cast<const QSortFilterProxyModel*>(item()->parentTree()->model());
174 /* Acquire source child model-index, which can be the same as child model-index: */
175 const QModelIndex sourceChildIndex = pProxyModel ? pProxyModel->mapToSource(childIndex) : childIndex;
176 /* Acquire source child item: */
177 QITreeViewItem *pItem = reinterpret_cast<QITreeViewItem*>(sourceChildIndex.internalPointer());
178 /* Return the child with the passed iIndex: */
179 return QAccessible::queryAccessibleInterface(pItem);
180}
181
182int QIAccessibilityInterfaceForQITreeViewItem::indexOfChild(const QAccessibleInterface *pChild) const
183{
184 /* Search for corresponding child: */
185 for (int i = 0; i < childCount(); ++i)
186 if (child(i) == pChild)
187 return i;
188
189 /* -1 by default: */
190 return -1;
191}
192
193QRect QIAccessibilityInterfaceForQITreeViewItem::rect() const
194{
195 /* Sanity check: */
196 AssertPtrReturn(item(), QRect());
197 AssertPtrReturn(item()->parentTree(), QRect());
198 AssertPtrReturn(item()->parentTree()->viewport(), QRect());
199
200 /* Get the local rect: */
201 const QRect itemRectInViewport = item()->rect();
202 const QSize itemSize = itemRectInViewport.size();
203 const QPoint itemPosInViewport = itemRectInViewport.topLeft();
204 const QPoint itemPosInScreen = item()->parentTree()->viewport()->mapToGlobal(itemPosInViewport);
205 const QRect itemRectInScreen = QRect(itemPosInScreen, itemSize);
206
207 /* Return the rect: */
208 return itemRectInScreen;
209}
210
211QString QIAccessibilityInterfaceForQITreeViewItem::text(QAccessible::Text enmTextRole) const
212{
213 /* Sanity check: */
214 AssertPtrReturn(item(), QString());
215
216 /* Return a text for the passed enmTextRole: */
217 switch (enmTextRole)
218 {
219 case QAccessible::Name: return item()->text();
220 default: break;
221 }
222
223 /* Null-string by default: */
224 return QString();
225}
226
227QAccessible::Role QIAccessibilityInterfaceForQITreeViewItem::role() const
228{
229 /* List if there are children, ListItem by default: */
230 return childCount() ? QAccessible::List : QAccessible::ListItem;
231}
232
233QAccessible::State QIAccessibilityInterfaceForQITreeViewItem::state() const
234{
235 /* Empty state by default: */
236 return QAccessible::State();
237}
238
239
240/*********************************************************************************************************************************
241* Class QIAccessibilityInterfaceForQITreeView implementation. *
242*********************************************************************************************************************************/
243
244int QIAccessibilityInterfaceForQITreeView::childCount() const
245{
246 /* Sanity check: */
247 AssertPtrReturn(tree(), 0);
248 AssertPtrReturn(tree()->model(), 0);
249
250 /* Acquire root model-index: */
251 const QModelIndex rootIndex = tree()->rootIndex();
252
253 /* Return the number of children: */
254 return tree()->model()->rowCount(rootIndex);
255}
256
257QAccessibleInterface *QIAccessibilityInterfaceForQITreeView::child(int iIndex) const
258{
259 /* Sanity check: */
260 AssertPtrReturn(tree(), 0);
261 AssertPtrReturn(tree()->model(), 0);
262 AssertReturn(iIndex >= 0, 0);
263 if (iIndex >= childCount())
264 {
265 // WORKAROUND:
266 // Normally I would assert here, but Qt5 accessibility code has
267 // a hard-coded architecture for a tree-views which we do not like
268 // but have to live with and this architecture enumerates children
269 // of all levels as children of level 0, so Qt5 can try to address
270 // our interface with index which surely out of bounds by our laws.
271 // So let's assume that's exactly such case and try to enumerate
272 // visible children like they are a part of the list, not tree.
273 // printf("Invalid index: %d\n", iIndex);
274
275 // Take into account we also have header with 'column count' indexes,
276 // so we should start enumerating tree indexes since 'column count'.
277 const int iColumnCount = tree()->model()->columnCount();
278 int iCurrentIndex = iColumnCount;
279
280 // Set iterator to root model-index initially:
281 QModelIndex index = tree()->rootIndex();
282 // But if it has child, go deeper:
283 if (tree()->model()->index(0, 0, index).isValid())
284 index = tree()->model()->index(0, 0, index);
285
286 // Search for sibling with corresponding index:
287 while (index.isValid() && iCurrentIndex < iIndex)
288 {
289 ++iCurrentIndex;
290 if (iCurrentIndex % iColumnCount == 0)
291 index = tree()->indexBelow(index);
292 }
293
294 // Check whether we have proxy model set or source one otherwise:
295 const QSortFilterProxyModel *pProxyModel = qobject_cast<const QSortFilterProxyModel*>(tree()->model());
296 // Acquire source model-index, which can be the same as model-index:
297 const QModelIndex sourceIndex = pProxyModel ? pProxyModel->mapToSource(index) : index;
298
299 // Return what we found:
300 // if (sourceIndex.isValid())
301 // printf("Item found: [%s]\n", ((QITreeViewItem*)sourceIndex.internalPointer())->text().toUtf8().constData());
302 // else
303 // printf("Item not found\n");
304 return sourceIndex.isValid() ? QAccessible::queryAccessibleInterface((QITreeViewItem*)sourceIndex.internalPointer()) : 0;
305 }
306
307 /* Acquire root model-index: */
308 const QModelIndex rootIndex = tree()->rootIndex();
309 /* Acquire child model-index: */
310 const QModelIndex childIndex = tree()->model()->index(iIndex, 0, rootIndex);
311
312 /* Check whether we have proxy model set or source one otherwise: */
313 const QSortFilterProxyModel *pProxyModel = qobject_cast<const QSortFilterProxyModel*>(tree()->model());
314 /* Acquire source child model-index, which can be the same as child model-index: */
315 const QModelIndex sourceChildIndex = pProxyModel ? pProxyModel->mapToSource(childIndex) : childIndex;
316 /* Acquire source child item: */
317 QITreeViewItem *pItem = reinterpret_cast<QITreeViewItem*>(sourceChildIndex.internalPointer());
318 /* Return the child with the passed iIndex: */
319 return QAccessible::queryAccessibleInterface(pItem);
320}
321
322int QIAccessibilityInterfaceForQITreeView::indexOfChild(const QAccessibleInterface *pChild) const
323{
324 /* Search for corresponding child: */
325 for (int i = 0; i < childCount(); ++i)
326 if (child(i) == pChild)
327 return i;
328
329 /* -1 by default: */
330 return -1;
331}
332
333QString QIAccessibilityInterfaceForQITreeView::text(QAccessible::Text /* enmTextRole */) const
334{
335 /* Sanity check: */
336 AssertPtrReturn(tree(), QString());
337
338 /* Return tree whats-this: */
339 return tree()->whatsThis();
340}
341
342
343/*********************************************************************************************************************************
344* Class QITreeViewItem implementation. *
345*********************************************************************************************************************************/
346
347QRect QITreeViewItem::rect() const
348{
349 /* Redirect call to parent-tree: */
350 return parentTree() ? parentTree()->visualRect(modelIndex()) : QRect();
351}
352
353QModelIndex QITreeViewItem::modelIndex() const
354{
355 /* Acquire model: */
356 const QAbstractItemModel *pModel = parentTree()->model();
357 /* Check whether we have proxy model set or source one otherwise: */
358 const QSortFilterProxyModel *pProxyModel = qobject_cast<const QSortFilterProxyModel*>(pModel);
359
360 /* Acquire root model-index: */
361 const QModelIndex rootIndex = parentTree()->rootIndex();
362 /* Acquire source root model-index, which can be the same as root model-index: */
363 const QModelIndex sourceRootModelIndex = pProxyModel ? pProxyModel->mapToSource(rootIndex) : rootIndex;
364
365 /* Check whether we have root model-index here: */
366 if ( sourceRootModelIndex.internalPointer()
367 && sourceRootModelIndex.internalPointer() == this)
368 return rootIndex;
369
370 /* Determine our parent model-index: */
371 const QModelIndex parentIndex = parentItem() ? parentItem()->modelIndex() : rootIndex;
372
373 /* Determine our position inside parent: */
374 int iPositionInParent = -1;
375 for (int i = 0; i < pModel->rowCount(parentIndex); ++i)
376 {
377 /* Acquire child model-index: */
378 const QModelIndex childIndex = pModel->index(i, 0, parentIndex);
379 /* Acquire source child model-index, which can be the same as child model-index: */
380 const QModelIndex sourceChildModelIndex = pProxyModel ? pProxyModel->mapToSource(childIndex) : childIndex;
381
382 /* Check whether we have child model-index here: */
383 if ( sourceChildModelIndex.internalPointer()
384 && sourceChildModelIndex.internalPointer() == this)
385 {
386 iPositionInParent = i;
387 break;
388 }
389 }
390 /* Make sure we found something: */
391 if (iPositionInParent == -1)
392 return QModelIndex();
393
394 /* Return model-index as child of parent model-index: */
395 return pModel->index(iPositionInParent, 0, parentIndex);
396}
397
398
399/*********************************************************************************************************************************
400* Class QITreeView implementation. *
401*********************************************************************************************************************************/
402
403QITreeView::QITreeView(QWidget *pParent)
404 : QTreeView(pParent)
405{
406 /* Prepare all: */
407 prepare();
408}
409
410void QITreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
411{
412 /* Notify listeners about it: */
413 emit currentItemChanged(current, previous);
414 /* Call to base-class: */
415 QTreeView::currentChanged(current, previous);
416}
417
418void QITreeView::drawBranches(QPainter *pPainter, const QRect &rect, const QModelIndex &index) const
419{
420 /* Notify listeners about it: */
421 emit drawItemBranches(pPainter, rect, index);
422 /* Call to base-class: */
423 QTreeView::drawBranches(pPainter, rect, index);
424}
425
426void QITreeView::mouseMoveEvent(QMouseEvent *pEvent)
427{
428 /* Reject event initially: */
429 pEvent->setAccepted(false);
430 /* Notify listeners about event allowing them to handle it: */
431 emit mouseMoved(pEvent);
432 /* Call to base-class only if event was not yet accepted: */
433 if (!pEvent->isAccepted())
434 QTreeView::mouseMoveEvent(pEvent);
435}
436
437void QITreeView::mousePressEvent(QMouseEvent *pEvent)
438{
439 /* Reject event initially: */
440 pEvent->setAccepted(false);
441 /* Notify listeners about event allowing them to handle it: */
442 emit mousePressed(pEvent);
443 /* Call to base-class only if event was not yet accepted: */
444 if (!pEvent->isAccepted())
445 QTreeView::mousePressEvent(pEvent);
446}
447
448void QITreeView::mouseReleaseEvent(QMouseEvent *pEvent)
449{
450 /* Reject event initially: */
451 pEvent->setAccepted(false);
452 /* Notify listeners about event allowing them to handle it: */
453 emit mouseReleased(pEvent);
454 /* Call to base-class only if event was not yet accepted: */
455 if (!pEvent->isAccepted())
456 QTreeView::mouseReleaseEvent(pEvent);
457}
458
459void QITreeView::mouseDoubleClickEvent(QMouseEvent *pEvent)
460{
461 /* Reject event initially: */
462 pEvent->setAccepted(false);
463 /* Notify listeners about event allowing them to handle it: */
464 emit mouseDoubleClicked(pEvent);
465 /* Call to base-class only if event was not yet accepted: */
466 if (!pEvent->isAccepted())
467 QTreeView::mouseDoubleClickEvent(pEvent);
468}
469
470void QITreeView::dragEnterEvent(QDragEnterEvent *pEvent)
471{
472 /* Reject event initially: */
473 pEvent->setAccepted(false);
474 /* Notify listeners about event allowing them to handle it: */
475 emit dragEntered(pEvent);
476 /* Call to base-class only if event was not yet accepted: */
477 if (!pEvent->isAccepted())
478 QTreeView::dragEnterEvent(pEvent);
479}
480
481void QITreeView::dragMoveEvent(QDragMoveEvent *pEvent)
482{
483 /* Reject event initially: */
484 pEvent->setAccepted(false);
485 /* Notify listeners about event allowing them to handle it: */
486 emit dragMoved(pEvent);
487 /* Call to base-class only if event was not yet accepted: */
488 if (!pEvent->isAccepted())
489 QTreeView::dragMoveEvent(pEvent);
490}
491
492void QITreeView::dragLeaveEvent(QDragLeaveEvent *pEvent)
493{
494 /* Reject event initially: */
495 pEvent->setAccepted(false);
496 /* Notify listeners about event allowing them to handle it: */
497 emit dragLeft(pEvent);
498 /* Call to base-class only if event was not yet accepted: */
499 if (!pEvent->isAccepted())
500 QTreeView::dragLeaveEvent(pEvent);
501}
502
503void QITreeView::dropEvent(QDropEvent *pEvent)
504{
505 /* Reject event initially: */
506 pEvent->setAccepted(false);
507 /* Notify listeners about event allowing them to handle it: */
508 emit dragDropped(pEvent);
509 /* Call to base-class only if event was not yet accepted: */
510 if (!pEvent->isAccepted())
511 QTreeView::dropEvent(pEvent);
512}
513
514void QITreeView::prepare()
515{
516 /* Install QITreeViewItem accessibility interface factory: */
517 QAccessible::installFactory(QIAccessibilityInterfaceForQITreeViewItem::pFactory);
518 /* Install QITreeView accessibility interface factory: */
519 QAccessible::installFactory(QIAccessibilityInterfaceForQITreeView::pFactory);
520
521 /* Mark header hidden: */
522 setHeaderHidden(true);
523 /* Mark root hidden: */
524 setRootIsDecorated(false);
525}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use