Improved boundary handling
[qt-at-spi:qt-at-spi.git] / src / adaptor.cpp
1 /*
2  * D-Bus AT-SPI, Qt Adaptor
3  *
4  * Copyright 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include <QtCore/QMetaObject>
22 #include <QtCore/QByteArray>
23 #include <QtCore/QList>
24 #include <QtCore/QMap>
25 #include <QtCore/QString>
26 #include <QtCore/QStringList>
27 #include <QtCore/QVariant>
28
29 #include <QAccessibleTextInterface>
30 #include <QAccessibleEditableTextInterface>
31 #include <QAccessibleTableInterface>
32 #include <QAccessibleActionInterface>
33 #include <QAccessibleValueInterface>
34
35 #include <QtCore/QtDebug>
36 #include <QtGui/QApplication>
37 #include <QtGui/QWidget>
38
39 #include "adaptor.h"
40 #include "bridge.h"
41 #include "constant_mappings.h"
42
43
44 QSpiAdaptor::QSpiAdaptor(QAccessibleInterface *interface_, int child)
45     : interface(interface_), child(child)
46 {
47 }
48
49 QObject* QSpiAdaptor::getObject() const
50 {
51     return interface->object();
52 }
53
54 QSpiObjectReference QSpiAdaptor::getReference() const
55 {
56     return reference;
57 }
58
59 QStringList QSpiAdaptor::getSupportedInterfaces() const
60 {
61     return supportedInterfaces;
62 }
63
64 bool QSpiAdaptor::checkInterface() const
65 {
66     // The interface can be deleted behind our back with no notification.
67     if (!interface->isValid()) {
68         spiBridge->removeAdaptor(const_cast<QSpiAdaptor*>(this));
69         return false;
70     }
71     return true;
72 }
73
74 QSpiAccessibleCacheItem QSpiAdaptor::getCacheItem() const
75 {
76     Q_ASSERT(interface);
77     if (!interface->isValid()) {
78         qWarning() << "QSpiObject::getCacheItem: invalid interface" << reference.path.path();
79         return QSpiAccessibleCacheItem();
80     }
81
82     QSpiAccessibleCacheItem item;
83     item.path = getReference();
84     item.parent = getParentReference();
85     item.application = spiBridge->getRootReference();
86     item.children = GetChildren();
87     item.supportedInterfaces = getSupportedInterfaces();
88     item.name = interface->text(QAccessible::Name, child);
89     item.role = qSpiRoleMapping.value(interface->role(child)).spiRole();
90     item.description = interface->text(QAccessible::Description, child);
91     item.state = GetState();
92     return item;
93 }
94
95 void QSpiAdaptor::signalChildrenChanged(const QString &type, int detail1, int detail2, const QDBusVariant &data)
96 {
97     emit ChildrenChanged(type, detail1, detail2, data, spiBridge->getRootReference());
98 }
99
100 int QSpiAdaptor::childCount() const
101 {
102     if (!checkInterface()) return 0;
103
104     if (child)
105         return 0;
106     return interface->childCount();
107 }
108
109 QString QSpiAdaptor::description() const
110 {
111     if (!checkInterface()) return QString();
112     return interface->text(QAccessible::Description, child);
113 }
114
115 QString QSpiAdaptor::name() const
116 {
117     if (!checkInterface()) return QString();
118     QString name = interface->text(QAccessible::Name, child);
119     if (!name.isEmpty()) {
120         return name;
121     }
122     return interface->text(QAccessible::Value, child);
123 }
124
125 QSpiObjectReference QSpiAdaptor::parent() const
126 {
127     if (!checkInterface()) return QSpiObjectReference();
128     return getParentReference();
129 }
130
131 QSpiObjectReference QSpiAdaptor::GetApplication() const
132 {
133     if (!checkInterface()) return QSpiObjectReference();
134     return spiBridge->getRootReference();
135 }
136
137 QSpiAttributeSet QSpiAdaptor::GetAttributes() const
138 {
139     if (!checkInterface()) return QSpiAttributeSet();
140     // No attributes interface in QAccessible so a blank list seems the sensible option.
141     QSpiAttributeSet out0;
142     return out0;
143 }
144
145 QSpiObjectReference QSpiAdaptor::GetChildAtIndex(int index) const
146 {
147     if (!checkInterface()) return QSpiObjectReference();
148
149     // if we are the child of a complex widget, we cannot have any children
150     Q_ASSERT(child == 0);
151     Q_ASSERT(index < interface->childCount());
152
153     qDebug() << "QSpiAdaptor::GetChildAtIndex get child " << index << " of " << interface->childCount()
154              << interface->text(QAccessible::Name, 0) << interface->object();
155
156     QSpiAdaptor* child = getChild(index+1);
157     if (!child) {
158         qWarning() << "QSpiAdaptor::GetChildAtIndex could not find child!";
159         return QSpiObjectReference();
160     }
161
162     return child->getReference();
163 }
164
165 QSpiObjectReferenceArray QSpiAdaptor::GetChildren() const
166 {
167     QList<QSpiObjectReference> children;
168     if (!checkInterface()) return children;
169
170     // when we are a child that means that we cannot have children of our own
171     if (child)
172         return children;
173
174     for (int i = 1; i <= interface->childCount(); ++i) {
175         QSpiAdaptor* child = getChild(i);
176         if (child)
177             children << child->getReference();
178     }
179     return children;
180 }
181
182 QSpiAdaptor* QSpiAdaptor::getChild(int index) const
183 {
184     Q_ASSERT(index > 0 && index <= interface->childCount());
185     QAccessibleInterface *child = 0;
186     int ret = interface->navigate(QAccessible::Child, index, &child);
187     if (ret == 0) {
188         return spiBridge->interfaceToAccessible(child, 0, true);
189     } else if (ret > 0){
190         Q_ASSERT(ret <= interface->childCount());
191         return spiBridge->interfaceToAccessible(interface, ret, true);
192     }
193     qWarning() << "QSpiAdaptor::getChild INVALID CHILD: " << interface->object() << index;
194     return 0;
195 }
196
197 int QSpiAdaptor::GetIndexInParent() const
198 {
199     if (!checkInterface()) return -1;
200
201 //    qDebug() << "QSpiAdaptor::GetIndexInParent" << interface->text(QAccessible::Name, 0);
202 //    qDebug() << "  obj: " << interface->object();
203     if (child)
204         return child;
205
206     QAccessibleInterface* parent;
207     interface->navigate(QAccessible::Ancestor, 1, &parent);
208     if (parent) {
209         qDebug() << "QSpiAdaptor::GetIndexInParent" << parent->text(QAccessible::Name, 0);
210         int index = parent->indexOfChild(interface);
211         qDebug() << "Index: " << index;
212         return index;
213     }
214     return -1;
215 }
216
217 QString QSpiAdaptor::GetLocalizedRoleName() const
218 {
219     if (!checkInterface()) return QString();
220
221     QString out0;
222     out0 = qSpiRoleMapping.value(interface->role(child)).localizedName();
223     return out0;
224 }
225
226 QSpiRelationArray QSpiAdaptor::GetRelationSet() const
227 {
228     if (!checkInterface()) return QSpiRelationArray();
229
230     const QAccessible::RelationFlag relationsToCheck[] = {QAccessible::Label, QAccessible::Labelled, QAccessible::Controller, QAccessible::Controlled, static_cast<QAccessible::RelationFlag>(-1)};
231     const AtspiRelationType relationTypes[] = {ATSPI_RELATION_LABELLED_BY, ATSPI_RELATION_LABEL_FOR, ATSPI_RELATION_CONTROLLED_BY, ATSPI_RELATION_CONTROLLER_FOR};
232
233     QSpiRelationArray relations;
234     
235     QAccessibleInterface *target;
236
237     for (int i = 0; relationsToCheck[i] >= 0; i++) {
238         QList<QSpiObjectReference> related;
239         int navigateResult = 1;
240
241         for (int j = 1; navigateResult >= 0; j++) {
242             navigateResult = interface->navigate(relationsToCheck[i], j, &target);
243
244             if (navigateResult == 0) {
245                 QSpiAdaptor *targetAdaptor = spiBridge->interfaceToAccessible(target, 0, false);
246                 related.append(targetAdaptor->getReference());
247                 delete target;
248             } else if (navigateResult > 0) {
249                 //Then it's a child of the object
250                 related.append(this->GetChildAtIndex(navigateResult));
251             }
252         }
253         if (!related.isEmpty())
254             relations.append(QSpiRelationArrayEntry(relationTypes[i], related));
255     }
256
257     return relations;
258 }
259
260 uint QSpiAdaptor::GetRole() const
261 {
262     if (!checkInterface()) return QAccessible::NoRole;
263
264     QAccessible::Role role = interface->role(child);
265     return qSpiRoleMapping[role].spiRole();
266 }
267
268 QString QSpiAdaptor::GetRoleName() const
269 {
270     if (!checkInterface()) return QString();
271
272     return qSpiRoleMapping[interface->role(child)].name();
273 }
274
275 QSpiUIntList QSpiAdaptor::GetState() const
276 {
277     if (!checkInterface()) return QSpiUIntList();
278
279     quint64 spiState = spiStatesFromQState(interface->state(child));
280     if (interface->tableInterface()) {
281         setSpiStateBit(&spiState, STATE_MANAGES_DESCENDANTS);
282     }
283     return spiStateSetFromSpiStates(spiState);
284 }
285
286 int QSpiAdaptor::nActions() const
287 {
288     if (!checkInterface()) return 0;
289
290     return interface->actionInterface()->actionCount();
291 }
292
293 bool QSpiAdaptor::DoAction(int index)
294 {
295     if (!checkInterface()) return false;
296
297     interface->actionInterface()->doAction(index);
298     return TRUE;
299 }
300
301 /* AT-SPI Action interface --------------------------------------------------*/
302 /*---------------------------------------------------------------------------*/
303
304 QSpiActionArray QSpiAdaptor::GetActions()
305 {
306     QSpiActionArray index;
307     if (!checkInterface()) return index;
308
309     for (int i = 0; i < interface->actionInterface()->actionCount(); i++)
310     {
311         QSpiAction action;
312         QStringList keyBindings;
313
314         action.name = interface->actionInterface()->name(i);
315         action.description = interface->actionInterface()->description(i);
316
317         keyBindings = interface->actionInterface()->keyBindings(i);
318
319         if (keyBindings.length() > 0)
320                 action.keyBinding = keyBindings[0];
321         else
322                 action.keyBinding = "";
323
324         index << action;
325     }
326     return index;
327 }
328
329 QString QSpiAdaptor::GetDescription(int index)
330 {
331     if (!checkInterface()) return QString();
332
333     return interface->actionInterface()->description(index);
334 }
335
336 QString QSpiAdaptor::GetKeyBinding(int index)
337 {
338     if (!checkInterface()) return QString();
339     QStringList keyBindings;
340
341     keyBindings = interface->actionInterface()->keyBindings(index);
342     /* Might as well return the first key binding, what are the other options? */
343     if (keyBindings.length() > 0)
344         return keyBindings[0];
345     else
346         return "";
347 }
348
349 QString QSpiAdaptor::GetName(int index)
350 {
351     if (!checkInterface()) return QString();
352     return interface->actionInterface()->name(index);
353 }
354
355 /* AT-SPI Application interface ---------------------------------------------*/
356 /*---------------------------------------------------------------------------*/
357
358 int QSpiAdaptor::id() const
359 {
360     if (!checkInterface()) return -1;
361     return property("Id").toInt();
362 }
363
364 QString QSpiAdaptor::toolkitName() const
365 {
366     if (!checkInterface()) return QString();
367 //    qWarning() << "QSpiAdaptor::toolkitName FIXME: We pretend to be GAIL as toolkit. This is evil and needs fixing.";
368     return QLatin1String("Qt");
369 //    return QLatin1String("GAIL");
370 }
371
372 QString QSpiAdaptor::version() const
373 {
374     if (!checkInterface()) return QString();
375     return QLatin1String(QT_VERSION_STR);
376 }
377
378 /// The bus address for direct (p2p) connections.
379 /// Not supported atm.
380 QString QSpiAdaptor::GetApplicationBusAddress() const
381 {
382     qDebug() << "QSpiAdaptor::GetApplicationBusAddress implement me!";
383     return QString();
384 }
385
386 QString QSpiAdaptor::GetLocale(uint lctype)
387 {
388     if (!checkInterface()) return QString();
389     Q_UNUSED(lctype)
390     QLocale currentLocale;
391     return currentLocale.languageToString(currentLocale.language());
392 }
393
394 /* AT-SPI Component interface -----------------------------------------------*/
395 /*---------------------------------------------------------------------------*/
396
397 static QAccessibleInterface *getWindow(QAccessibleInterface* interface)
398 {
399     QAccessibleInterface *current=NULL, *tmp=NULL;
400
401     interface->navigate(QAccessible::Ancestor, 0, &current);
402
403     while (current &&
404            current->role(0) != QAccessible::Window &&
405            current->role(0) != QAccessible::Application)
406     {
407         tmp = NULL;
408         current->navigate (QAccessible::Ancestor, 1, &tmp);
409         current = tmp;
410     }
411
412     if (current) {
413         return current;
414     } else {
415         return NULL;
416     }
417 }
418
419 static QRect getRelativeRect(QAccessibleInterface* interface, int child)
420 {
421     QAccessibleInterface *window;
422     QRect wr, cr;
423
424     cr = interface->rect(child);
425
426     window = getWindow(interface);
427     if (window)
428     {
429         wr = window->rect(child);
430
431         cr.setX(cr.x() - wr.x());
432         cr.setY(cr.x() - wr.y());
433     }
434     return cr;
435 }
436
437 bool QSpiAdaptor::Contains(int x, int y, uint coord_type)
438 {
439     if (!checkInterface()) return false;
440     if (coord_type == 0)
441         return interface->rect(child).contains(x, y);
442     else
443         return getRelativeRect(interface, child).contains(x, y);
444 }
445
446 QSpiObjectReference QSpiAdaptor::GetAccessibleAtPoint(int x, int y, uint coord_type)
447 {
448     if (!checkInterface()) return QSpiObjectReference();
449     Q_UNUSED (coord_type)
450
451     // Grab the top level widget. For complex widgets we want to return a child
452     // at the right position instead.
453     QWidget* w = qApp->widgetAt(x,y);
454     if (w) {
455         QSpiAdaptor* adaptor = spiBridge->objectToAccessible(w);
456
457         int i = adaptor->associatedInterface()->childAt(x, y);
458         if (i > 0) {
459             QSpiAdaptor* child = adaptor->getChild(i);
460             return child->getReference();
461         }
462         return adaptor->getReference();
463     } else {
464         return QSpiObjectReference(spiBridge->dBusConnection(), QDBusObjectPath(QSPI_OBJECT_PATH_NULL));
465     }
466 }
467
468 double QSpiAdaptor::GetAlpha()
469 {
470     if (!checkInterface()) return 0.0;
471     // TODO Find out if the QAccessible iterface needs extending to provide an alpha value.
472     return 1.0;
473 }
474
475 QSpiRect QSpiAdaptor::GetExtents(uint coord_type)
476 {
477     QSpiRect val;
478     if (!checkInterface()) return val;
479
480     QRect rect;
481     if (coord_type == 0)
482         rect = interface->rect(child);
483     else
484         rect = getRelativeRect(interface, child);
485
486     val.x = rect.x ();
487     val.y = rect.y ();
488     val.width = rect.width ();
489     val.height = rect.height ();
490     return val;
491 }
492
493 uint QSpiAdaptor::GetLayer()
494 {
495     if (!checkInterface()) return 0;
496     // TODO Find out if QT has any concept of 'Layers'
497     return 1; // Corresponds to LAYER_WINDOW.
498 }
499
500 short QSpiAdaptor::GetMDIZOrder()
501 {
502     if (!checkInterface()) return 0;
503     // TODO Does Qt have any concept of Layers?
504     return 0;
505 }
506
507 int QSpiAdaptor::GetPosition(uint coord_type, int &y)
508 {
509     if (!checkInterface()) return 0;
510     QRect rect;
511     if (coord_type == 0)
512         rect = interface->rect(child);
513     else
514         rect = getRelativeRect(interface, child);
515     y = rect.y ();
516     return rect.x ();
517 }
518
519 int QSpiAdaptor::GetSize(int &height)
520 {
521     if (!checkInterface()) return 0;
522     QRect rect = interface->rect(child);
523     height = rect.height();
524     return rect.width();
525 }
526
527 bool QSpiAdaptor::GrabFocus()
528 {
529     if (!checkInterface()) return false;
530     // TODO This does not seem to be supported by QAccessibleInterface.
531     // FIXME: raise the window to make it active also?
532     // FIXME: graphics/qml items
533
534     if (interface->object()->isWidgetType()) {
535         QWidget* w = static_cast<QWidget*>(interface->object());
536         w->setFocus(Qt::OtherFocusReason);
537         return true;
538     }
539
540     return false;
541 }
542
543 /* AT-SPI EditableText interface --------------------------------------------*/
544 /*---------------------------------------------------------------------------*/
545
546 void QSpiAdaptor::CopyText(int startPos, int endPos)
547 {
548     if (!checkInterface()) return;
549     return interface->editableTextInterface()->copyText(startPos, endPos);
550 }
551
552 bool QSpiAdaptor::CutText(int startPos, int endPos)
553 {
554     if (!checkInterface()) return false;
555     interface->editableTextInterface()->cutText(startPos, endPos);
556     return TRUE;
557 }
558
559 bool QSpiAdaptor::DeleteText(int startPos, int endPos)
560 {
561     if (!checkInterface()) return false;
562     interface->editableTextInterface()->deleteText(startPos, endPos);
563     return TRUE;
564 }
565
566 bool QSpiAdaptor::InsertText(int position, const QString &text, int length)
567 {
568     if (!checkInterface()) return false;
569     QString resized (text);
570     resized.resize(length);
571     interface->editableTextInterface()->insertText(position, resized);
572     return TRUE;
573 }
574
575 bool QSpiAdaptor::PasteText(int position)
576 {
577     if (!checkInterface()) return false;
578     interface->editableTextInterface()->pasteText(position);
579     return TRUE;
580 }
581
582 bool QSpiAdaptor::SetTextContents(const QString &newContents)
583 {
584     if (!checkInterface()) return false;
585     interface->editableTextInterface()->replaceText(0, interface->textInterface()->characterCount(), newContents);
586     return TRUE;
587 }
588
589 /* AT-SPI Table interface ---------------------------------------------------*/
590 /*---------------------------------------------------------------------------*/
591
592 #define MAX_SELECTED_COLUMNS 1000
593 #define MAX_SELECTED_ROWS    1000
594
595 QSpiObjectReference QSpiAdaptor::caption() const
596 {
597     if (!checkInterface()) return QSpiObjectReference();
598     return spiBridge->objectToAccessible (interface->tableInterface()->caption()->object())->getReference();
599 }
600
601 int QSpiAdaptor::nColumns() const
602 {
603     if (!checkInterface()) return 0;
604     return interface->tableInterface()->columnCount ();
605 }
606
607 int QSpiAdaptor::nRows() const
608 {
609     if (!checkInterface()) return 0;
610     return interface->tableInterface()->rowCount ();
611 }
612
613 int QSpiAdaptor::nSelectedColumns() const
614 {
615     if (!checkInterface()) return 0;
616     return interface->tableInterface()->selectedColumnCount ();
617 }
618
619 int QSpiAdaptor::nSelectedRows() const
620 {
621     if (!checkInterface()) return 0;
622     return interface->tableInterface()->selectedRowCount ();
623 }
624
625 QSpiObjectReference QSpiAdaptor::summary() const
626 {
627     if (!checkInterface()) return QSpiObjectReference();
628     return spiBridge->objectToAccessible(interface->tableInterface()->summary()->object())->getReference();
629 }
630
631 bool QSpiAdaptor::AddColumnSelection(int column)
632 {
633     if (!checkInterface()) return false;
634     interface->tableInterface()->selectColumn(column);
635     return TRUE;
636 }
637
638 bool QSpiAdaptor::AddRowSelection(int row)
639 {
640     if (!checkInterface()) return false;
641     interface->tableInterface()->selectRow(row);
642     return TRUE;
643 }
644
645 QSpiObjectReference QSpiAdaptor::GetAccessibleAt(int row, int column)
646 {
647     if (!checkInterface()) return QSpiObjectReference();
648     Q_ASSERT(interface->tableInterface());
649
650     QAccessibleInterface* cell = interface->tableInterface()->accessibleAt(row, column);
651     if (cell && cell->object()) {
652         return spiBridge->objectToAccessible(cell->object())->getReference();
653     }
654     qWarning() << "Invalid table cell: " << row << ", " << column;
655     return QSpiObjectReference();
656 }
657
658 int QSpiAdaptor::GetColumnAtIndex(int index)
659 {
660     if (!checkInterface()) return 0;
661     return interface->tableInterface()->columnIndex(index);
662 }
663
664 QString QSpiAdaptor::GetColumnDescription(int column)
665 {
666     if (!checkInterface()) return QString();
667     return interface->tableInterface()->columnDescription(column);
668 }
669
670 int QSpiAdaptor::GetColumnExtentAt(int row, int column)
671 {
672     if (!checkInterface()) return 0;
673     return interface->tableInterface()->columnSpan(row, column);
674 }
675
676 QSpiObjectReference QSpiAdaptor::GetColumnHeader(int column)
677 {
678     if (!checkInterface()) return QSpiObjectReference();
679     Q_UNUSED (column);
680     // TODO There should be a column param in this function right?
681     return spiBridge->objectToAccessible(interface->tableInterface()->columnHeader()->object())->getReference();
682 }
683
684 int QSpiAdaptor::GetIndexAt(int row, int column)
685 {
686     if (!checkInterface()) return 0;
687     return interface->tableInterface()->childIndex(row, column);
688 }
689
690 int QSpiAdaptor::GetRowAtIndex(int index)
691 {
692     if (!checkInterface()) return 0;
693     int row, column, rowSpan, columnSpan;
694     bool isSelected;
695
696     interface->tableInterface()->cellAtIndex (index, &row, &column, &rowSpan, &columnSpan, &isSelected);
697     return row;
698 }
699
700 bool QSpiAdaptor::GetRowColumnExtentsAtIndex(int index,
701                                                   int &row,
702                                                   int &col,
703                                                   int &row_extents,
704                                                   int &col_extents,
705                                                   bool &is_selected)
706 {
707     if (!checkInterface()) return false;
708     int row0, column, rowSpan, columnSpan;
709     bool isSelected;
710
711     interface->tableInterface()->cellAtIndex (index, &row0, &column, &rowSpan, &columnSpan, &isSelected);
712     row = row0;
713     col = column;
714     row_extents = rowSpan;
715     col_extents = columnSpan;
716     is_selected = isSelected;
717     if (index < interface->childCount())
718         return TRUE;
719     else
720         return FALSE;
721 }
722
723 QString QSpiAdaptor::GetRowDescription(int row)
724 {
725     if (!checkInterface()) return QString();
726     return interface->tableInterface()->rowDescription (row);
727 }
728
729 int QSpiAdaptor::GetRowExtentAt(int row, int column)
730 {
731     if (!checkInterface()) return 0;
732     return interface->tableInterface()->rowSpan (row, column);
733 }
734
735 QSpiObjectReference QSpiAdaptor::GetRowHeader(int row)
736 {
737     if (!checkInterface()) return QSpiObjectReference();
738     Q_UNUSED (row);
739     qWarning() << "Implement: QSpiAdaptor::GetRowHeader";
740     return QSpiObjectReference();
741
742     // TODO There should be a row param here right?
743 //    return spiBridge->objectToAccessible(interface->tableInterface()->rowHeader()->object())->getReference();
744 }
745
746 QSpiIntList QSpiAdaptor::GetSelectedColumns()
747 {
748     QSpiIntList columns;
749     if (!checkInterface()) return columns;
750     interface->tableInterface()->selectedColumns(MAX_SELECTED_COLUMNS, &columns);
751     return columns;
752 }
753
754 QSpiIntList QSpiAdaptor::GetSelectedRows()
755 {
756     QSpiIntList rows;
757     if (!checkInterface()) return rows;
758     interface->tableInterface()->selectedRows(MAX_SELECTED_ROWS, &rows);
759     return rows;
760 }
761
762 bool QSpiAdaptor::IsColumnSelected(int column)
763 {
764     if (!checkInterface()) return false;
765     return interface->tableInterface()->isColumnSelected (column);
766 }
767
768 bool QSpiAdaptor::IsRowSelected(int row)
769 {
770     if (!checkInterface()) return false;
771     return interface->tableInterface()->isRowSelected (row);
772 }
773
774 bool QSpiAdaptor::IsSelected(int row, int column)
775 {
776     if (!checkInterface()) return false;
777     return interface->tableInterface()->isSelected (row, column);
778 }
779
780 bool QSpiAdaptor::RemoveColumnSelection(int column)
781 {
782     if (!checkInterface()) return false;
783     interface->tableInterface()->unselectColumn (column);
784     return TRUE;
785 }
786
787 bool QSpiAdaptor::RemoveRowSelection(int row)
788 {
789     if (!checkInterface()) return false;
790     interface->tableInterface()->unselectRow (row);
791     return TRUE;
792 }
793
794 /* AT-SPI Text interface ----------------------------------------------------*/
795 /*---------------------------------------------------------------------------*/
796
797 int QSpiAdaptor::caretOffset() const
798 {
799     if (!checkInterface()) return 0;
800     return interface->textInterface()->cursorPosition();
801 }
802
803 int QSpiAdaptor::characterCount() const
804 {
805     if (!checkInterface()) return 0;
806     return interface->textInterface()->characterCount();
807 }
808
809 bool QSpiAdaptor::AddSelection(int startOffset, int endOffset)
810 {
811     if (!checkInterface()) return false;
812     int lastSelection = interface->textInterface()->selectionCount ();
813     interface->textInterface()->setSelection (lastSelection, startOffset, endOffset);
814     return interface->textInterface()->selectionCount() > lastSelection;
815 }
816
817 QSpiAttributeSet QSpiAdaptor::GetAttributeRun(int offset,
818                                               bool includeDefaults,
819                                               int &startOffset,
820                                               int &endOffset)
821 {
822     if (!checkInterface()) return QSpiAttributeSet();
823     Q_UNUSED (includeDefaults);
824     return GetAttributes (offset, startOffset, endOffset);
825 }
826
827 QString QSpiAdaptor::GetAttributeValue(int offset,
828                                       const QString &attributeName,
829                                       int &startOffset,
830                                       int &endOffset,
831                                       bool &defined)
832 {
833     if (!checkInterface()) return QString();
834     QString     mapped;
835     QString     joined;
836     QStringList attributes;
837     QSpiAttributeSet map;
838
839     joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
840     attributes = joined.split (';', QString::SkipEmptyParts, Qt::CaseSensitive);
841     foreach (QString attr, attributes)
842     {
843         QStringList items;
844         items = attr.split(':', QString::SkipEmptyParts, Qt::CaseSensitive);
845         map[items[0]] = items[1];
846     }
847     mapped = map[attributeName];
848     if (mapped == "")
849        defined = TRUE;
850     else
851        defined = FALSE;
852     return mapped;
853 }
854
855 QSpiAttributeSet QSpiAdaptor::GetAttributes(int offset, int &startOffset, int &endOffset)
856 {
857     QSpiAttributeSet set;
858     if (!checkInterface()) return set;
859
860     QString     joined;
861     QStringList attributes;
862
863     joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
864     attributes = joined.split (';', QString::SkipEmptyParts, Qt::CaseSensitive);
865     foreach (const QString &attr, attributes)
866     {
867         QStringList items;
868         items = attr.split(':', QString::SkipEmptyParts, Qt::CaseSensitive);
869         set[items[0]] = items[1];
870     }
871     return set;
872 }
873
874 QSpiRangeList QSpiAdaptor::GetBoundedRanges(int x,
875                                                 int y,
876                                                 int width,
877                                                 int height,
878                                                 uint coordType,
879                                                 uint xClipType,
880                                                 uint yClipType)
881 {
882     if (!checkInterface()) return QSpiRangeList();
883     qWarning("Not implemented: QSpiAdaptor::GetBoundedRanges");
884     Q_UNUSED(x) Q_UNUSED (y) Q_UNUSED(width)
885     Q_UNUSED(height) Q_UNUSED(coordType)
886     Q_UNUSED(xClipType) Q_UNUSED(yClipType)
887     QSpiRangeList out0;
888     return out0;
889 }
890
891 int QSpiAdaptor::GetCharacterAtOffset(int offset)
892 {
893     if (!checkInterface()) return 0;
894     int start=offset, end=offset+1;
895     QString result;
896     result = interface->textInterface()->textAtOffset(offset, QAccessible2::CharBoundary, &start, &end);
897     return *(qPrintable (result));
898 }
899
900 int QSpiAdaptor::GetCharacterExtents(int offset, uint coordType, int &y, int &width, int &height)
901 {
902     if (!checkInterface()) return 0;
903     int x;
904
905     // QAccessible2 has RelativeToParent as a coordinate type instead of relative
906     // to top-level window, which is an AT-SPI coordinate type.
907     if (static_cast<QAccessible2::CoordinateType>(coordType) != QAccessible2::RelativeToScreen) {
908         const QWidget *widget = qobject_cast<const QWidget*>(interface->object());
909         if (!widget) {
910             y = 0;
911             width = 0;
912             height = 0;
913             return 0;
914         }
915         const QWidget *parent = widget->parentWidget();
916         while (parent) {
917             widget = parent;
918             parent = widget->parentWidget();
919         }
920         x = -widget->x();
921         y = -widget->y();
922     } else {
923         x = 0;
924         y = 0;
925     }
926     
927     QRect rect = interface->textInterface()->characterRect(offset, QAccessible2::RelativeToScreen);
928     width = rect.width();
929     height = rect.height();
930     y += rect.y();
931     return x+rect.x();
932 }
933
934 QSpiAttributeSet QSpiAdaptor::GetDefaultAttributeSet()
935 {
936     // Empty set seems reasonable. There is no default attribute set.
937     QSpiAttributeSet attributes;
938     if (!checkInterface()) return attributes;
939     return attributes;
940 }
941
942 QSpiAttributeSet QSpiAdaptor::GetDefaultAttributes()
943 {
944     // Deprecated in favour of default attribute set.
945     return GetDefaultAttributeSet();
946 }
947
948 int QSpiAdaptor::GetNSelections()
949 {
950     if (!checkInterface()) return 0;
951     return interface->textInterface()->selectionCount();
952 }
953
954 int QSpiAdaptor::GetOffsetAtPoint(int x, int y, uint coordType)
955 {
956     if (!checkInterface()) return -1;
957     return interface->textInterface()->offsetAtPoint (QPoint (x, y), static_cast <QAccessible2::CoordinateType> (coordType));
958 }
959
960 int QSpiAdaptor::GetRangeExtents(int startOffset, int endOffset, uint coordType, int &y, int &width, int &height)
961 {
962     if (!checkInterface()) return -1;
963
964     if (endOffset == -1)
965         endOffset = interface->textInterface()->characterCount();
966
967     if (endOffset <= startOffset) {
968         y=0;
969         width = 0;
970         height = 0;
971         return 0;
972     }
973
974     int xOffset = 0, yOffset = 0;
975     QAccessibleTextInterface *textInterface = interface->textInterface();
976
977     // QAccessible2 has RelativeToParent as a coordinate type instead of relative
978     // to top-level window, which is an AT-SPI coordinate type.
979     if (static_cast<QAccessible2::CoordinateType>(coordType) != QAccessible2::RelativeToScreen) {
980         const QWidget *widget = qobject_cast<const QWidget*>(interface->object());
981         if (!widget) {
982             y = 0;
983             width = 0;
984             height = 0;
985             return 0;
986         }
987         const QWidget *parent = widget->parentWidget();
988         while (parent) {
989             widget = parent;
990             parent = widget->parentWidget();
991         }
992         xOffset = -widget->x();
993         yOffset = -widget->y();
994     }
995
996     int minX=INT_MAX, minY=INT_MAX, maxX=0, maxY=0;
997
998     for (int i=startOffset; i<endOffset; i++) {
999         QRect rect = textInterface->characterRect(i, QAccessible2::RelativeToScreen);
1000         if (rect.x() < minX) {
1001             minX = rect.x();
1002         }
1003         if (rect.y() < minY) {
1004             minY = rect.y();
1005         }
1006         if ((rect.x() + rect.width()) > maxX) {
1007             maxX = (rect.x() + rect.width());
1008         }
1009         if ((rect.y() + rect.height()) > maxY) {
1010             maxY = (rect.y() + rect.height());
1011         }
1012     }
1013
1014     width = maxX - minX;
1015     height = maxY - minY;
1016     y = minY + yOffset;
1017     return minX + xOffset;
1018 }
1019
1020 int QSpiAdaptor::GetSelection(int selectionNum, int &endOffset)
1021 {
1022     if (!checkInterface()) return -1;
1023     int start, end;
1024     interface->textInterface()->selection(selectionNum, &start, &end);
1025
1026     if (start<0) {
1027         endOffset = interface->textInterface()->cursorPosition();
1028         return endOffset;
1029     }
1030
1031     endOffset = end;
1032     return start;
1033 }
1034
1035 QString QSpiAdaptor::GetText(int startOffset, int endOffset)
1036 {
1037     if (!checkInterface()) return QString();
1038     if (endOffset == -1)
1039         endOffset = interface->textInterface()->characterCount();
1040     return interface->textInterface()->text(startOffset, endOffset);
1041 }
1042
1043 QString QSpiAdaptor::GetTextAfterOffset(int offset, uint type, int &startOffset, int &endOffset)
1044 {
1045     if (!checkInterface()) return QString();
1046     // FIXME find out if IA2 types are the same as the ones in at-spi
1047     return interface->textInterface()->textAfterOffset(offset, (QAccessible2::BoundaryType)type, &startOffset, &endOffset);
1048 }
1049
1050 QString QSpiAdaptor::GetTextAtOffset(int offset, uint type, int &startOffset, int &endOffset)
1051 {
1052     if (!checkInterface()) return QString();
1053     QAccessibleTextInterface * t = interface->textInterface();
1054     QAccessible2::BoundaryType rType;
1055     switch (type) {
1056     case ATSPI_TEXT_BOUNDARY_CHAR:
1057         rType = QAccessible2::CharBoundary;
1058         break;
1059     case ATSPI_TEXT_BOUNDARY_WORD_START: {
1060         QString text = t->textAtOffset(offset, QAccessible2::WordBoundary, &startOffset, &endOffset);
1061
1062         if ((startOffset < 0) || (endOffset < 0))
1063             return text;
1064
1065         int limit = t->characterCount();
1066         for (int i=endOffset + 1; i < limit; i++) {
1067             int j;
1068             int k;
1069             t->textAtOffset(i, QAccessible2::WordBoundary, &j, &k);
1070             if (j <= i) {
1071                 endOffset = j;
1072                 break;
1073             }
1074         }
1075         return t->text(startOffset, endOffset); }
1076     case ATSPI_TEXT_BOUNDARY_WORD_END: {
1077         QString text = t->textAtOffset(offset, QAccessible2::WordBoundary, &startOffset, &endOffset);
1078
1079         if ((startOffset < 0) || (endOffset < 0))
1080             return text;
1081
1082         for (int i=startOffset - 1; i >= 0; i--) {
1083             int j;
1084             int k;
1085             t->textAtOffset(i, QAccessible2::WordBoundary, &j, &k);
1086             if (k >= i) {
1087                 startOffset = k;
1088                 break;
1089             }
1090         }
1091         return t->text(startOffset, endOffset); }
1092     case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
1093     case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
1094         rType = QAccessible2::SentenceBoundary;
1095         break;
1096     case ATSPI_TEXT_BOUNDARY_LINE_START: {
1097         QString text = t->textAtOffset(offset, QAccessible2::LineBoundary, &startOffset, &endOffset);
1098
1099         if ((startOffset < 0) || (endOffset < 0))
1100             return text;
1101
1102         int limit = t->characterCount();
1103         for (int i=endOffset + 1; i < limit; i++) {
1104             int j;
1105             int k;
1106             t->textAtOffset(i, QAccessible2::LineBoundary, &j, &k);
1107             if (j <= i) {
1108                 endOffset = j;
1109                 break;
1110             }
1111         }
1112         return t->text(startOffset, endOffset); }
1113     case ATSPI_TEXT_BOUNDARY_LINE_END: {
1114         QString text = t->textAtOffset(offset, QAccessible2::LineBoundary, &startOffset, &endOffset);
1115
1116         if ((startOffset < 0) || (endOffset < 0))
1117             return text;
1118
1119         if (startOffset <= offset)
1120             text = t->textAtOffset(offset + 1, QAccessible2::LineBoundary, &startOffset, &endOffset);
1121
1122         for (int i=startOffset - 1; i >= 0; i--) {
1123             int j;
1124             int k;
1125             t->textAtOffset(i, QAccessible2::LineBoundary, &j, &k);
1126             if (k >= i) {
1127                 startOffset = k;
1128                 break;
1129             }
1130         }
1131         return t->text(startOffset, endOffset); }
1132     default:
1133         startOffset = -1;
1134         endOffset = -1;
1135         return QString();
1136     }
1137
1138     return t->textAtOffset(offset, rType, &startOffset, &endOffset);
1139 }
1140
1141 QString QSpiAdaptor::GetTextBeforeOffset(int offset, uint type, int &startOffset, int &endOffset)
1142 {
1143     if (!checkInterface()) return QString();
1144     // FIXME find out if IA2 types are the same as the ones in at-spi
1145     return interface->textInterface()->textBeforeOffset(offset, (QAccessible2::BoundaryType)type, &startOffset, &endOffset);
1146 }
1147
1148 bool QSpiAdaptor::RemoveSelection(int selectionNum)
1149 {
1150     if (!checkInterface()) return false;
1151     interface->textInterface()->removeSelection(selectionNum);
1152     return true;
1153 }
1154
1155 bool QSpiAdaptor::SetCaretOffset(int offset)
1156 {
1157     if (!checkInterface()) return false;
1158     interface->textInterface()->setCursorPosition(offset);
1159     return true;
1160 }
1161
1162 bool QSpiAdaptor::SetSelection(int selectionNum, int startOffset, int endOffset)
1163 {
1164     if (!checkInterface()) return false;
1165     interface->textInterface()->setSelection(selectionNum, startOffset, endOffset);
1166     return true;
1167 }
1168
1169 /* AT-SPI Value interface ---------------------------------------------------*/
1170 /*---------------------------------------------------------------------------*/
1171
1172 double QSpiAdaptor::currentValue() const
1173 {
1174     if (!checkInterface()) return 0.0;
1175     double val;
1176     bool success;
1177     val = interface->valueInterface()->currentValue().toDouble (&success);
1178     if (success)
1179     {
1180         return val;
1181     }
1182     else
1183     {
1184         qDebug ("QSpiAccessibleBridge: Could not convert current value to double");
1185         return 0.0;
1186     }
1187 }
1188
1189 void QSpiAdaptor::setCurrentValue(double value)
1190 {
1191     if (!checkInterface()) return;
1192     interface->valueInterface()->setCurrentValue(QVariant (value));
1193 }
1194
1195 double QSpiAdaptor::maximumValue() const
1196 {
1197     if (!checkInterface()) return 0.0;
1198     double val;
1199     bool success;
1200     val = interface->valueInterface()->maximumValue().toDouble (&success);
1201     if (success)
1202     {
1203         return val;
1204     }
1205     else
1206     {
1207         qDebug ("QSpiAccessibleBridge: Could not convert maximum value to double");
1208         return 0.0;
1209     }
1210 }
1211
1212 double QSpiAdaptor::minimumIncrement() const
1213 {
1214     if (!checkInterface()) return 0.0;
1215     // FIXME: should be in value interface
1216     return 0.0;
1217 }
1218
1219 double QSpiAdaptor::minimumValue() const
1220 {
1221     if (!checkInterface()) return 0.0;
1222     double val;
1223     bool success;
1224     val = interface->valueInterface()->minimumValue().toDouble (&success);
1225     if (success)
1226     {
1227         return val;
1228     }
1229     else
1230     {
1231         qDebug ("QSpiAccessibleBridge: Could not convert minimum value to double");
1232         return 0.0;
1233     }
1234 }
1235
1236 /*END------------------------------------------------------------------------*/