VirtualBox

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

Last change on this file was 102125, checked in by vboxsync, 6 months ago

FE/Qt: bugref:10450: QITableWidget: Accessibility interface fixes for Qt6; Which seems to be treating horizontal and vertical headers as table items as well; This widget is used in OCI Cloud Profile options only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: QITableWidget.cpp 102125 2023-11-16 16:40:24Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QITableWidget 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 <QAccessibleWidget>
30#include <QPainter>
31#include <QResizeEvent>
32
33/* GUI includes: */
34#include "QITableWidget.h"
35
36/* Other VBox includes: */
37#include "iprt/assert.h"
38
39
40/** QAccessibleObject extension used as an accessibility interface for QITableWidgetItem. */
41class QIAccessibilityInterfaceForQITableWidgetItem : 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 QITableWidgetItem accessibility interface: */
49 if (pObject && strClassname == QLatin1String("QITableWidgetItem"))
50 return new QIAccessibilityInterfaceForQITableWidgetItem(pObject);
51
52 /* Null by default: */
53 return 0;
54 }
55
56 /** Constructs an accessibility interface passing @a pObject to the base-class. */
57 QIAccessibilityInterfaceForQITableWidgetItem(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 { return 0; }
66 /** Returns the child with the passed @a iIndex. */
67 virtual QAccessibleInterface *child(int iIndex) const RT_OVERRIDE { Q_UNUSED(iIndex); return 0; }
68 /** Returns the index of the passed @a pChild. */
69 virtual int indexOfChild(const QAccessibleInterface *pChild) const RT_OVERRIDE { Q_UNUSED(pChild); return -1; }
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 QITableWidgetItem. */
84 QITableWidgetItem *item() const { return qobject_cast<QITableWidgetItem*>(object()); }
85};
86
87
88/** QAccessibleWidget extension used as an accessibility interface for QITableWidget. */
89class QIAccessibilityInterfaceForQITableWidget : 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 QITableWidget accessibility interface: */
97 if (pObject && strClassname == QLatin1String("QITableWidget"))
98 return new QIAccessibilityInterfaceForQITableWidget(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 QIAccessibilityInterfaceForQITableWidget(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 QITableWidget. */
122 QITableWidget *table() const { return qobject_cast<QITableWidget*>(widget()); }
123};
124
125
126/*********************************************************************************************************************************
127* Class QIAccessibilityInterfaceForQITableWidgetItem implementation. *
128*********************************************************************************************************************************/
129
130QAccessibleInterface *QIAccessibilityInterfaceForQITableWidgetItem::parent() const
131{
132 /* Make sure item still alive: */
133 AssertPtrReturn(item(), 0);
134
135 /* Return the parent: */
136 return QAccessible::queryAccessibleInterface(item()->parentTable());
137}
138
139QRect QIAccessibilityInterfaceForQITableWidgetItem::rect() const
140{
141 /* Make sure item still alive: */
142 AssertPtrReturn(item(), QRect());
143
144 /* Compose common region: */
145 QRegion region;
146
147 /* Append item rectangle: */
148 const QRect itemRectInViewport = item()->parentTable()->visualItemRect(item());
149 const QSize itemSize = itemRectInViewport.size();
150 const QPoint itemPosInViewport = itemRectInViewport.topLeft();
151 const QPoint itemPosInScreen = item()->parentTable()->viewport()->mapToGlobal(itemPosInViewport);
152 const QRect itemRectInScreen = QRect(itemPosInScreen, itemSize);
153 region += itemRectInScreen;
154
155 /* Return common region bounding rectangle: */
156 return region.boundingRect();
157}
158
159QString QIAccessibilityInterfaceForQITableWidgetItem::text(QAccessible::Text enmTextRole) const
160{
161 /* Make sure item still alive: */
162 AssertPtrReturn(item(), QString());
163
164 /* Return a text for the passed enmTextRole: */
165 switch (enmTextRole)
166 {
167 case QAccessible::Name: return item()->text();
168 default: break;
169 }
170
171 /* Null-string by default: */
172 return QString();
173}
174
175QAccessible::Role QIAccessibilityInterfaceForQITableWidgetItem::role() const
176{
177 return QAccessible::ListItem;
178}
179
180QAccessible::State QIAccessibilityInterfaceForQITableWidgetItem::state() const
181{
182 /* Make sure item still alive: */
183 AssertPtrReturn(item(), QAccessible::State());
184
185 /* Compose the state: */
186 QAccessible::State state;
187 state.focusable = true;
188 state.selectable = true;
189
190 /* Compose the state of current item: */
191 if ( item()
192 && item() == QITableWidgetItem::toItem(item()->tableWidget()->currentItem()))
193 {
194 state.active = true;
195 state.focused = true;
196 state.selected = true;
197 }
198
199 /* Compose the state of checked item: */
200 if ( item()
201 && item()->checkState() != Qt::Unchecked)
202 {
203 state.checked = true;
204 if (item()->checkState() == Qt::PartiallyChecked)
205 state.checkStateMixed = true;
206 }
207
208 /* Return the state: */
209 return state;
210}
211
212
213/*********************************************************************************************************************************
214* Class QIAccessibilityInterfaceForQITableWidget implementation. *
215*********************************************************************************************************************************/
216
217int QIAccessibilityInterfaceForQITableWidget::childCount() const
218{
219 /* Make sure table still alive: */
220 AssertPtrReturn(table(), 0);
221
222 /* Return the number of children: */
223 // Since Qt6 both horizontal and vertical table headers
224 // are treated as items as well, so we have to take them
225 // into account while calculating overall child count.
226 return (table()->rowCount() + 1) * (table()->columnCount() + 1);
227}
228
229QAccessibleInterface *QIAccessibilityInterfaceForQITableWidget::child(int iIndex) const
230{
231 /* Make sure table still alive: */
232 AssertPtrReturn(table(), 0);
233 /* Make sure index is valid: */
234 AssertReturn(iIndex >= 0 && iIndex < childCount(), 0);
235
236 /* Return the child with the passed iIndex: */
237 // Since Qt6 both horizontal and vertical table headers
238 // are treated as items as well, so we have to take them
239 // into account while addressing actual table children.
240 const int iRow = iIndex / (table()->columnCount() + 1) - 1;
241 const int iColumn = iIndex % (table()->columnCount() + 1) - 1;
242 return QAccessible::queryAccessibleInterface(table()->childItem(iRow, iColumn));
243}
244
245int QIAccessibilityInterfaceForQITableWidget::indexOfChild(const QAccessibleInterface *pChild) const
246{
247 /* Search for corresponding child: */
248 for (int iIndex = 0; iIndex < childCount(); ++iIndex)
249 if (child(iIndex) == pChild)
250 return iIndex;
251
252 /* -1 by default: */
253 return -1;
254}
255
256QString QIAccessibilityInterfaceForQITableWidget::text(QAccessible::Text /* enmTextRole */) const
257{
258 /* Make sure table still alive: */
259 AssertPtrReturn(table(), QString());
260
261 /* Gather suitable text: */
262 QString strText = table()->toolTip();
263 if (strText.isEmpty())
264 strText = table()->whatsThis();
265 return strText;
266}
267
268
269/*********************************************************************************************************************************
270* Class QITableWidgetItem implementation. *
271*********************************************************************************************************************************/
272
273/* static */
274QITableWidgetItem *QITableWidgetItem::toItem(QTableWidgetItem *pItem)
275{
276 /* Make sure alive QITableWidgetItem passed: */
277 if (!pItem || pItem->type() != ItemType)
278 return 0;
279
280 /* Return casted QITableWidgetItem: */
281 return static_cast<QITableWidgetItem*>(pItem);
282}
283
284/* static */
285const QITableWidgetItem *QITableWidgetItem::toItem(const QTableWidgetItem *pItem)
286{
287 /* Make sure alive QITableWidgetItem passed: */
288 if (!pItem || pItem->type() != ItemType)
289 return 0;
290
291 /* Return casted QITableWidgetItem: */
292 return static_cast<const QITableWidgetItem*>(pItem);
293}
294
295QITableWidgetItem::QITableWidgetItem(const QString &strText /* = QString() */)
296 : QTableWidgetItem(strText, ItemType)
297{
298}
299
300QITableWidget *QITableWidgetItem::parentTable() const
301{
302 return tableWidget() ? qobject_cast<QITableWidget*>(tableWidget()) : 0;
303}
304
305
306/*********************************************************************************************************************************
307* Class QITableWidget implementation. *
308*********************************************************************************************************************************/
309
310QITableWidget::QITableWidget(QWidget *pParent)
311 : QTableWidget(pParent)
312{
313 /* Install QITableWidget accessibility interface factory: */
314 QAccessible::installFactory(QIAccessibilityInterfaceForQITableWidget::pFactory);
315 /* Install QITableWidgetItem accessibility interface factory: */
316 QAccessible::installFactory(QIAccessibilityInterfaceForQITableWidgetItem::pFactory);
317
318 // WORKAROUND:
319 // Ok, what do we have here..
320 // There is a bug in QAccessible framework which might be just treated like
321 // a functionality flaw. It consist in fact that if an accessibility client
322 // is enabled, base-class can request an accessibility interface in own
323 // constructor before the sub-class registers own factory, so we have to
324 // recreate interface after we finished with our own initialization.
325 QAccessibleInterface *pInterface = QAccessible::queryAccessibleInterface(this);
326 if (pInterface)
327 {
328 QAccessible::deleteAccessibleInterface(QAccessible::uniqueId(pInterface));
329 QAccessible::queryAccessibleInterface(this); // <= new one, proper..
330 }
331}
332
333QITableWidgetItem *QITableWidget::childItem(int iRow, int iColumn) const
334{
335 return item(iRow, iColumn) ? QITableWidgetItem::toItem(item(iRow, iColumn)) : 0;
336}
337
338QModelIndex QITableWidget::itemIndex(QTableWidgetItem *pItem)
339{
340 return indexFromItem(pItem);
341}
342
343void QITableWidget::paintEvent(QPaintEvent *pEvent)
344{
345 /* Call to base-class: */
346 QTableWidget::paintEvent(pEvent);
347
348 /* Create item painter: */
349 QPainter painter;
350 painter.begin(viewport());
351
352 /* Notify listeners about painting: */
353 for (int iRow = 0; iRow < rowCount(); ++iRow)
354 for (int iColumn = 0; iColumn < rowCount(); ++iColumn)
355 emit painted(item(iRow, iColumn), &painter);
356
357 /* Close item painter: */
358 painter.end();
359}
360
361void QITableWidget::resizeEvent(QResizeEvent *pEvent)
362{
363 /* Call to base-class: */
364 QTableWidget::resizeEvent(pEvent);
365
366 /* Notify listeners about resizing: */
367 emit resized(pEvent->size(), pEvent->oldSize());
368}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use