VirtualBox

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

Last change on this file was 104514, checked in by vboxsync, 4 months ago

FE/Qt: bugref:10681: Our own QIListWidget implementation; Required to have own accessibility interface for QListWidget subclasses.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: QIListWidget.cpp 104514 2024-05-03 18:10:47Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QIListWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2024 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 <QPainter>
31#include <QResizeEvent>
32
33/* GUI includes: */
34#include "QIListWidget.h"
35
36/* Other VBox includes: */
37#include "iprt/assert.h"
38
39
40/** QAccessibleObject extension used as an accessibility interface for QIListWidgetItem. */
41class QIAccessibilityInterfaceForQIListWidgetItem : public QAccessibleObject
42{
43public:
44
45 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
46 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
47 {
48 /* Creating QIListWidgetItem accessibility interface: */
49 if (pObject && strClassname == QLatin1String("QIListWidgetItem"))
50 return new QIAccessibilityInterfaceForQIListWidgetItem(pObject);
51
52 /* Null by default: */
53 return 0;
54 }
55
56 /** Constructs an accessibility interface passing @a pObject to the base-class. */
57 QIAccessibilityInterfaceForQIListWidgetItem(QObject *pObject)
58 : QAccessibleObject(pObject)
59 {}
60
61 /** Returns the parent. */
62 virtual QAccessibleInterface *parent() const RT_OVERRIDE;
63
64 /** Returns the number of children. */
65 virtual int childCount() const RT_OVERRIDE;
66 /** Returns the child with the passed @a iIndex. */
67 virtual QAccessibleInterface *child(int iIndex) const RT_OVERRIDE;
68 /** Returns the index of the passed @a pChild. */
69 virtual int indexOfChild(const QAccessibleInterface *pChild) const RT_OVERRIDE;
70
71 /** Returns the rect. */
72 virtual QRect rect() const RT_OVERRIDE;
73 /** Returns a text for the passed @a enmTextRole. */
74 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE;
75
76 /** Returns the role. */
77 virtual QAccessible::Role role() const RT_OVERRIDE;
78 /** Returns the state. */
79 virtual QAccessible::State state() const RT_OVERRIDE;
80
81private:
82
83 /** Returns corresponding QIListWidgetItem. */
84 QIListWidgetItem *item() const { return qobject_cast<QIListWidgetItem*>(object()); }
85};
86
87
88/** QAccessibleWidget extension used as an accessibility interface for QIListWidget. */
89class QIAccessibilityInterfaceForQIListWidget : public QAccessibleWidget
90{
91public:
92
93 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
94 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
95 {
96 /* Creating QIListWidget accessibility interface: */
97 if (pObject && strClassname == QLatin1String("QIListWidget"))
98 return new QIAccessibilityInterfaceForQIListWidget(qobject_cast<QWidget*>(pObject));
99
100 /* Null by default: */
101 return 0;
102 }
103
104 /** Constructs an accessibility interface passing @a pWidget to the base-class. */
105 QIAccessibilityInterfaceForQIListWidget(QWidget *pWidget)
106 : QAccessibleWidget(pWidget, QAccessible::List)
107 {}
108
109 /** Returns the number of children. */
110 virtual int childCount() const RT_OVERRIDE;
111 /** Returns the child with the passed @a iIndex. */
112 virtual QAccessibleInterface *child(int iIndex) const RT_OVERRIDE;
113 /** Returns the index of the passed @a pChild. */
114 virtual int indexOfChild(const QAccessibleInterface *pChild) const RT_OVERRIDE;
115
116 /** Returns a text for the passed @a enmTextRole. */
117 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE;
118
119private:
120
121 /** Returns corresponding QIListWidget. */
122 QIListWidget *list() const { return qobject_cast<QIListWidget*>(widget()); }
123};
124
125
126/*********************************************************************************************************************************
127* Class QIAccessibilityInterfaceForQIListWidgetItem implementation. *
128*********************************************************************************************************************************/
129
130QAccessibleInterface *QIAccessibilityInterfaceForQIListWidgetItem::parent() const
131{
132 /* Make sure item still alive: */
133 AssertPtrReturn(item(), 0);
134
135 /* Return the parent: */
136 return QAccessible::queryAccessibleInterface(item()->parentList());
137}
138
139int QIAccessibilityInterfaceForQIListWidgetItem::childCount() const
140{
141 /* Make sure item still alive: */
142 AssertPtrReturn(item(), 0);
143
144 /* Zero in any case: */
145 return 0;
146}
147
148QAccessibleInterface *QIAccessibilityInterfaceForQIListWidgetItem::child(int iIndex) const
149{
150 /* Make sure item still alive: */
151 AssertPtrReturn(item(), 0);
152 /* Make sure index is valid: */
153 AssertReturn(iIndex >= 0 && iIndex < childCount(), 0);
154
155 /* Null in any case: */
156 return 0;
157}
158
159int QIAccessibilityInterfaceForQIListWidgetItem::indexOfChild(const QAccessibleInterface*) const
160{
161 /* -1 in any case: */
162 return -1;
163}
164
165QRect QIAccessibilityInterfaceForQIListWidgetItem::rect() const
166{
167 /* Make sure item still alive: */
168 AssertPtrReturn(item(), QRect());
169
170 /* Compose common region: */
171 QRegion region;
172
173 /* Append item rectangle: */
174 const QRect itemRectInViewport = item()->parentList()->visualItemRect(item());
175 const QSize itemSize = itemRectInViewport.size();
176 const QPoint itemPosInViewport = itemRectInViewport.topLeft();
177 const QPoint itemPosInScreen = item()->parentList()->viewport()->mapToGlobal(itemPosInViewport);
178 const QRect itemRectInScreen = QRect(itemPosInScreen, itemSize);
179 region += itemRectInScreen;
180
181 /* Return common region bounding rectangle: */
182 return region.boundingRect();
183}
184
185QString QIAccessibilityInterfaceForQIListWidgetItem::text(QAccessible::Text enmTextRole) const
186{
187 /* Make sure item still alive: */
188 AssertPtrReturn(item(), QString());
189
190 /* Return a text for the passed enmTextRole: */
191 switch (enmTextRole)
192 {
193 case QAccessible::Name: return item()->defaultText();
194 default: break;
195 }
196
197 /* Null-string by default: */
198 return QString();
199}
200
201QAccessible::Role QIAccessibilityInterfaceForQIListWidgetItem::role() const
202{
203 /* ListItem in any case: */
204 return QAccessible::ListItem;
205}
206
207QAccessible::State QIAccessibilityInterfaceForQIListWidgetItem::state() const
208{
209 /* Make sure item still alive: */
210 AssertPtrReturn(item(), QAccessible::State());
211
212 /* Compose the state: */
213 QAccessible::State state;
214 state.focusable = true;
215 state.selectable = true;
216
217 /* Compose the state of current item: */
218 if ( item()
219 && item() == QIListWidgetItem::toItem(item()->listWidget()->currentItem()))
220 {
221 state.active = true;
222 state.focused = true;
223 state.selected = true;
224 }
225
226 /* Compose the state of checked item: */
227 if ( item()
228 && item()->checkState() != Qt::Unchecked)
229 {
230 state.checked = true;
231 if (item()->checkState() == Qt::PartiallyChecked)
232 state.checkStateMixed = true;
233 }
234
235 /* Return the state: */
236 return state;
237}
238
239
240/*********************************************************************************************************************************
241* Class QIAccessibilityInterfaceForQIListWidget implementation. *
242*********************************************************************************************************************************/
243
244int QIAccessibilityInterfaceForQIListWidget::childCount() const
245{
246 /* Make sure list still alive: */
247 AssertPtrReturn(list(), 0);
248
249 /* Return the number of children: */
250 return list()->childCount();
251}
252
253QAccessibleInterface *QIAccessibilityInterfaceForQIListWidget::child(int iIndex) const
254{
255 /* Make sure list still alive: */
256 AssertPtrReturn(list(), 0);
257 /* Make sure index is valid: */
258 AssertReturn(iIndex >= 0, 0);
259
260 /* Return the child with the passed iIndex: */
261 return QAccessible::queryAccessibleInterface(list()->childItem(iIndex));
262}
263
264int QIAccessibilityInterfaceForQIListWidget::indexOfChild(const QAccessibleInterface *pChild) const
265{
266 /* Make sure list still alive: */
267 AssertPtrReturn(list(), -1);
268 /* Make sure child is valid: */
269 AssertReturn(pChild, -1);
270
271 // WORKAROUND:
272 // Not yet sure how to handle this for list widget with multiple columns, so this is a simple hack:
273 const QModelIndex index = list()->itemIndex(qobject_cast<QIListWidgetItem*>(pChild->object()));
274 const int iIndex = index.row();
275 return iIndex;
276}
277
278QString QIAccessibilityInterfaceForQIListWidget::text(QAccessible::Text /* enmTextRole */) const
279{
280 /* Make sure list still alive: */
281 AssertPtrReturn(list(), QString());
282
283 /* Gather suitable text: */
284 QString strText = list()->toolTip();
285 if (strText.isEmpty())
286 strText = list()->whatsThis();
287 return strText;
288}
289
290
291/*********************************************************************************************************************************
292* Class QIListWidgetItem implementation. *
293*********************************************************************************************************************************/
294
295/* static */
296QIListWidgetItem *QIListWidgetItem::toItem(QListWidgetItem *pItem)
297{
298 /* Make sure alive QIListWidgetItem passed: */
299 if (!pItem || pItem->type() != ItemType)
300 return 0;
301
302 /* Return casted QIListWidgetItem: */
303 return static_cast<QIListWidgetItem*>(pItem);
304}
305
306/* static */
307const QIListWidgetItem *QIListWidgetItem::toItem(const QListWidgetItem *pItem)
308{
309 /* Make sure alive QIListWidgetItem passed: */
310 if (!pItem || pItem->type() != ItemType)
311 return 0;
312
313 /* Return casted QIListWidgetItem: */
314 return static_cast<const QIListWidgetItem*>(pItem);
315}
316
317/* static */
318QList<QIListWidgetItem*> QIListWidgetItem::toList(const QList<QListWidgetItem*> &initialList)
319{
320 QList<QIListWidgetItem*> resultingList;
321 foreach (QListWidgetItem *pItem, initialList)
322 resultingList << toItem(pItem);
323 return resultingList;
324}
325
326/* static */
327QList<const QIListWidgetItem*> QIListWidgetItem::toList(const QList<const QListWidgetItem*> &initialList)
328{
329 QList<const QIListWidgetItem*> resultingList;
330 foreach (const QListWidgetItem *pItem, initialList)
331 resultingList << toItem(pItem);
332 return resultingList;
333}
334
335QIListWidgetItem::QIListWidgetItem(QIListWidget *pListWidget)
336 : QListWidgetItem(pListWidget, ItemType)
337{
338}
339
340QIListWidgetItem::QIListWidgetItem(const QString &strText, QIListWidget *pListWidget)
341 : QListWidgetItem(strText, pListWidget, ItemType)
342{
343}
344
345QIListWidgetItem::QIListWidgetItem(const QIcon &icon, const QString &strText, QIListWidget *pListWidget)
346 : QListWidgetItem(icon, strText, pListWidget, ItemType)
347{
348}
349
350QIListWidget *QIListWidgetItem::parentList() const
351{
352 return listWidget() ? qobject_cast<QIListWidget*>(listWidget()) : 0;
353}
354
355QString QIListWidgetItem::defaultText() const
356{
357 /* Return item text as default: */
358 return text();
359}
360
361
362/*********************************************************************************************************************************
363* Class QIListWidget implementation. *
364*********************************************************************************************************************************/
365
366QIListWidget::QIListWidget(QWidget *pParent /* = 0 */, bool fDelegatePaintingToSubclass /* = false */)
367 : QListWidget(pParent)
368 , m_fDelegatePaintingToSubclass(fDelegatePaintingToSubclass)
369{
370 /* Install QIListWidget accessibility interface factory: */
371 QAccessible::installFactory(QIAccessibilityInterfaceForQIListWidget::pFactory);
372 /* Install QIListWidgetItem accessibility interface factory: */
373 QAccessible::installFactory(QIAccessibilityInterfaceForQIListWidgetItem::pFactory);
374
375 // WORKAROUND:
376 // Ok, what do we have here..
377 // There is a bug in QAccessible framework which might be just treated like
378 // a functionality flaw. It consist in fact that if an accessibility client
379 // is enabled, base-class can request an accessibility interface in own
380 // constructor before the sub-class registers own factory, so we have to
381 // recreate interface after we finished with our own initialization.
382 QAccessibleInterface *pInterface = QAccessible::queryAccessibleInterface(this);
383 if (pInterface)
384 {
385 QAccessible::deleteAccessibleInterface(QAccessible::uniqueId(pInterface));
386 QAccessible::queryAccessibleInterface(this); // <= new one, proper..
387 }
388
389 /* Do not paint frame and background unless requested: */
390 if (m_fDelegatePaintingToSubclass)
391 {
392 setFrameShape(QFrame::NoFrame);
393 viewport()->setAutoFillBackground(false);
394 }
395}
396
397void QIListWidget::setSizeHintForItems(const QSize &sizeHint)
398{
399 /* Pass the sizeHint to all the items: */
400 for (int i = 0; i < count(); ++i)
401 item(i)->setSizeHint(sizeHint);
402}
403
404int QIListWidget::childCount() const
405{
406 return count();
407}
408
409QIListWidgetItem *QIListWidget::childItem(int iIndex) const
410{
411 return item(iIndex) ? QIListWidgetItem::toItem(item(iIndex)) : 0;
412}
413
414QModelIndex QIListWidget::itemIndex(QListWidgetItem *pItem)
415{
416 return indexFromItem(pItem);
417}
418
419QList<QIListWidgetItem*> QIListWidget::selectedItems() const
420{
421 return QIListWidgetItem::toList(QListWidget::selectedItems());
422}
423
424QList<QIListWidgetItem*> QIListWidget::findItems(const QString &strText, Qt::MatchFlags flags) const
425{
426 return QIListWidgetItem::toList(QListWidget::findItems(strText, flags));
427}
428
429void QIListWidget::paintEvent(QPaintEvent *pEvent)
430{
431 /* Call to base-class if allowed: */
432 if (!m_fDelegatePaintingToSubclass)
433 QListWidget::paintEvent(pEvent);
434
435 /* Create item painter: */
436 QPainter painter;
437 painter.begin(viewport());
438
439 /* Notify listeners about painting: */
440 for (int iIndex = 0; iIndex < count(); ++iIndex)
441 emit painted(item(iIndex), &painter);
442
443 /* Close item painter: */
444 painter.end();
445}
446
447void QIListWidget::resizeEvent(QResizeEvent *pEvent)
448{
449 /* Call to base-class: */
450 QListWidget::resizeEvent(pEvent);
451
452 /* Notify listeners about resizing: */
453 emit resized(pEvent->size(), pEvent->oldSize());
454}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use