Add accessibility support for wxDataViewCtrl and wxDataViewTreeCtrl

Implemented wxDataViewCtrlAccessible and wxDataViewTreeCtrlAccessible classes.
This commit is contained in:
Artur Wieczorek 2016-10-09 21:12:59 +02:00
parent 29d310c6f0
commit 9c3c6074eb
4 changed files with 943 additions and 4 deletions

View File

@ -54,6 +54,9 @@ class WXDLLIMPEXP_FWD_ADV wxDataViewCtrl;
class WXDLLIMPEXP_FWD_ADV wxDataViewColumn;
class WXDLLIMPEXP_FWD_ADV wxDataViewRenderer;
class WXDLLIMPEXP_FWD_ADV wxDataViewModelNotifier;
#if wxUSE_ACCESSIBILITY
class WXDLLIMPEXP_FWD_ADV wxDataViewCtrlAccessible;
#endif // wxUSE_ACCESSIBILITY
extern WXDLLIMPEXP_DATA_ADV(const char) wxDataViewCtrlNameStr[];
@ -1301,9 +1304,17 @@ public:
//-----------------------------------------------------------------------------
#if wxUSE_ACCESSIBILITY
class WXDLLIMPEXP_FWD_ADV wxDataViewTreeCtrlAccessible;
#endif // wxUSE_ACCESSIBILITY
class WXDLLIMPEXP_ADV wxDataViewTreeCtrl: public wxDataViewCtrl,
public wxWithImages
{
#if wxUSE_ACCESSIBILITY
friend class wxDataViewTreeCtrlAccessible;
#endif // wxUSE_ACCESSIBILITY
public:
wxDataViewTreeCtrl() { }
wxDataViewTreeCtrl(wxWindow *parent,
@ -1401,6 +1412,21 @@ private:
#define wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE
#define wxEVT_COMMAND_DATAVIEW_ITEM_DROP wxEVT_DATAVIEW_ITEM_DROP
#if wxUSE_ACCESSIBILITY
//-----------------------------------------------------------------------------
// wxDataViewTreeCtrlAccessible
//-----------------------------------------------------------------------------
class WXDLLIMPEXP_ADV wxDataViewTreeCtrlAccessible: public wxDataViewCtrlAccessible
{
public:
wxDataViewTreeCtrlAccessible(wxDataViewTreeCtrl* win);
virtual ~wxDataViewTreeCtrlAccessible() {};
virtual wxAccStatus GetName(int childId, wxString* name) wxOVERRIDE;
};
#endif // wxUSE_ACCESSIBILITY
#endif // wxUSE_DATAVIEWCTRL
#endif

View File

@ -17,9 +17,15 @@
#include "wx/scrolwin.h"
#include "wx/icon.h"
#include "wx/vector.h"
#if wxUSE_ACCESSIBILITY
#include "wx/access.h"
#endif // wxUSE_ACCESSIBILITY
class WXDLLIMPEXP_FWD_ADV wxDataViewMainWindow;
class WXDLLIMPEXP_FWD_ADV wxDataViewHeaderWindow;
#if wxUSE_ACCESSIBILITY
class WXDLLIMPEXP_FWD_ADV wxDataViewCtrlAccessible;
#endif // wxUSE_ACCESSIBILITY
// ---------------------------------------------------------
// wxDataViewColumn
@ -172,6 +178,9 @@ class WXDLLIMPEXP_ADV wxDataViewCtrl : public wxDataViewCtrlBase,
friend class wxDataViewHeaderWindow;
friend class wxDataViewHeaderWindowMSW;
friend class wxDataViewColumn;
#if wxUSE_ACCESSIBILITY
friend class wxDataViewCtrlAccessible;
#endif // wxUSE_ACCESSIBILITY
public:
wxDataViewCtrl() : wxScrollHelper(this)
@ -376,5 +385,58 @@ private:
wxDECLARE_EVENT_TABLE();
};
#if wxUSE_ACCESSIBILITY
//-----------------------------------------------------------------------------
// wxDataViewCtrlAccessible
//-----------------------------------------------------------------------------
class WXDLLIMPEXP_ADV wxDataViewCtrlAccessible: public wxWindowAccessible
{
public:
wxDataViewCtrlAccessible(wxDataViewCtrl* win);
virtual ~wxDataViewCtrlAccessible() {};
virtual wxAccStatus HitTest(const wxPoint& pt, int* childId,
wxAccessible** childObject) wxOVERRIDE;
virtual wxAccStatus GetLocation(wxRect& rect, int elementId) wxOVERRIDE;
virtual wxAccStatus Navigate(wxNavDir navDir, int fromId,
int* toId, wxAccessible** toObject) wxOVERRIDE;
virtual wxAccStatus GetName(int childId, wxString* name) wxOVERRIDE;
virtual wxAccStatus GetChildCount(int* childCount) wxOVERRIDE;
virtual wxAccStatus GetChild(int childId, wxAccessible** child) wxOVERRIDE;
// wxWindowAccessible::GetParent() implementation is enough.
// virtual wxAccStatus GetParent(wxAccessible** parent) wxOVERRIDE;
virtual wxAccStatus DoDefaultAction(int childId) wxOVERRIDE;
virtual wxAccStatus GetDefaultAction(int childId, wxString* actionName) wxOVERRIDE;
virtual wxAccStatus GetDescription(int childId, wxString* description) wxOVERRIDE;
virtual wxAccStatus GetHelpText(int childId, wxString* helpText) wxOVERRIDE;
virtual wxAccStatus GetKeyboardShortcut(int childId, wxString* shortcut) wxOVERRIDE;
virtual wxAccStatus GetRole(int childId, wxAccRole* role) wxOVERRIDE;
virtual wxAccStatus GetState(int childId, long* state) wxOVERRIDE;
virtual wxAccStatus GetValue(int childId, wxString* strValue) wxOVERRIDE;
virtual wxAccStatus Select(int childId, wxAccSelectionFlags selectFlags) wxOVERRIDE;
virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) wxOVERRIDE;
#if wxUSE_VARIANT
virtual wxAccStatus GetSelections(wxVariant* selections) wxOVERRIDE;
#endif // wxUSE_VARIANT
};
#endif // wxUSE_ACCESSIBILITY
#endif // __GENERICDATAVIEWCTRLH__

View File

@ -31,6 +31,9 @@
#include "wx/choice.h"
#include "wx/imaglist.h"
#include "wx/renderer.h"
#if wxUSE_ACCESSIBILITY
#include "wx/access.h"
#endif // wxUSE_ACCESSIBILITY
const char wxDataViewCtrlNameStr[] = "dataviewCtrl";
@ -2567,6 +2570,10 @@ bool wxDataViewTreeCtrl::Create( wxWindow *parent, wxWindowID id,
0 // not resizable
);
#if wxUSE_ACCESSIBILITY
SetAccessible(new wxDataViewTreeCtrlAccessible(this));
#endif // wxUSE_ACCESSIBILITY
return true;
}
@ -2736,5 +2743,50 @@ void wxDataViewTreeCtrl::OnSize( wxSizeEvent &event )
event.Skip( true );
}
#if wxUSE_ACCESSIBILITY
//-----------------------------------------------------------------------------
// wxDataViewTreeCtrlAccessible
//-----------------------------------------------------------------------------
wxDataViewTreeCtrlAccessible::wxDataViewTreeCtrlAccessible(wxDataViewTreeCtrl* win)
: wxDataViewCtrlAccessible(win)
{
}
// Gets the name of the specified object.
wxAccStatus wxDataViewTreeCtrlAccessible::GetName(int childId, wxString* name)
{
wxDataViewTreeCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewTreeCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId == wxACC_SELF )
{
*name = dvCtrl->GetName();
}
else
{
wxDataViewItem item = dvCtrl->GetItemByRow(childId-1);
if ( !item.IsOk() )
{
return wxACC_NOT_IMPLEMENTED;
}
wxString itemName = dvCtrl->GetItemText(item);
if ( itemName.empty() )
{
// Return row number if not textual column found.
// Rows are numbered from 1.
*name = _("Row") + wxString::Format(wxS(" %i"), childId);
}
else
{
*name = itemName;
}
}
return wxACC_OK;
}
#endif // wxUSE_ACCESSIBILITY
#endif // wxUSE_DATAVIEWCTRL

View File

@ -241,6 +241,12 @@ public:
wxDataViewHeaderWindow(wxDataViewCtrl *parent)
: wxHeaderCtrl(parent)
{
#if wxUSE_ACCESSIBILITY
// Under MSW wxHeadrCtrl is a native control
// so we just need to pass all requests
// to the accessibility framework.
SetAccessible(new wxAccessible(this));
#endif // wxUSE_ACCESSIBILITY
}
wxDataViewCtrl *GetOwner() const
@ -824,6 +830,10 @@ public:
// specified item in the given column.
void StartEditing(const wxDataViewItem& item, const wxDataViewColumn* col);
void FinishEditing();
bool HasEditableColumn(const wxDataViewItem& item) const
{
return FindColumnForEditing(item, wxDATAVIEW_CELL_EDITABLE) != NULL;
}
int GetSortColumn() const { return m_sortColumn; }
bool IsAscendingSort() const { return m_sortAscending; }
@ -843,7 +853,7 @@ private:
wxDataViewTreeNode * FindNode( const wxDataViewItem & item );
wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode);
wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode) const;
bool IsCellEditableInMode(const wxDataViewItem& item, const wxDataViewColumn *col, wxDataViewCellMode mode) const;
@ -3575,7 +3585,7 @@ void wxDataViewMainWindow::DestroyTree()
}
wxDataViewColumn*
wxDataViewMainWindow::FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode)
wxDataViewMainWindow::FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode) const
{
// Edit the current column editable in 'mode'. If no column is focused
// (typically because the user has full row selected), try to find the
@ -4659,6 +4669,10 @@ bool wxDataViewCtrl::Create(wxWindow *parent,
m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
#if wxUSE_ACCESSIBILITY
SetAccessible(new wxDataViewCtrlAccessible(this));
#endif // wxUSE_ACCESSIBILITY
// We use the cursor keys for moving the selection, not scrolling, so call
// this method to ensure wxScrollHelperEvtHandler doesn't catch all
// keyboard events forwarded to us from wxListMainWindow.
@ -5141,14 +5155,14 @@ wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
{
if ( m_sortingColumnIdxs.empty() )
return NULL;
return GetColumn(m_sortingColumnIdxs.front());
}
wxVector<wxDataViewColumn *> wxDataViewCtrl::GetSortingColumns() const
{
wxVector<wxDataViewColumn *> out;
for ( wxVector<int>::const_iterator it = m_sortingColumnIdxs.begin(),
end = m_sortingColumnIdxs.end();
it != end;
@ -5484,4 +5498,789 @@ void wxDataViewCtrl::DoEnableSystemTheme(bool enable, wxWindow* window)
#endif // !wxUSE_GENERICDATAVIEWCTRL
#if wxUSE_ACCESSIBILITY
//-----------------------------------------------------------------------------
// wxDataViewCtrlAccessible
//-----------------------------------------------------------------------------
wxDataViewCtrlAccessible::wxDataViewCtrlAccessible(wxDataViewCtrl* win)
: wxWindowAccessible(win)
{
}
// Can return either a child object, or an integer
// representing the child element, starting from 1.
wxAccStatus wxDataViewCtrlAccessible::HitTest(const wxPoint& pt,
int* childId, wxAccessible** childObject)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewItem item;
wxDataViewColumn* col;
const wxPoint posCtrl = dvCtrl->ScreenToClient(pt);
dvCtrl->HitTest(posCtrl, item, col);
if ( item.IsOk() )
{
*childId = dvCtrl->GetRowByItem(item)+1;
*childObject = NULL;
}
else
{
if( ((wxWindow*)dvCtrl)->HitTest(posCtrl) == wxHT_WINDOW_INSIDE )
{
// First check if provided point belongs to the header
// because header control handles accesibility requestes on its own.
wxHeaderCtrl* dvHdr = dvCtrl->GenericGetHeader();
if ( dvHdr )
{
const wxPoint posHdr = dvHdr->ScreenToClient(pt);
if ( dvHdr->HitTest(posHdr) == wxHT_WINDOW_INSIDE )
{
*childId = wxACC_SELF;
*childObject = dvHdr->GetOrCreateAccessible();
return wxACC_OK;
}
}
*childId = wxACC_SELF;
*childObject = this;
}
else
{
*childId = wxACC_SELF;
*childObject = NULL;
}
}
return wxACC_OK;
}
// Returns the rectangle for this object (id = 0) or a child element (id > 0).
wxAccStatus wxDataViewCtrlAccessible::GetLocation(wxRect& rect, int elementId)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( elementId == wxACC_SELF )
{
// Header accesibility requestes are handled separately
// so header is excluded from effective client area
// and hence only main window area is reported.
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
rect = dvWnd->GetScreenRect();
}
else
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
wxDataViewItem item = dvWnd->GetItemByRow(elementId-1);
if ( !item.IsOk() )
{
return wxACC_NOT_IMPLEMENTED;
}
rect = dvWnd->GetItemRect(item, NULL);
// Indentation and expander column should be included here and therefore
// reported row width should by the same as the width of the client area.
rect.width += rect.x;
rect.x = 0;
wxPoint posScreen = dvWnd->ClientToScreen(rect.GetPosition());
rect.SetPosition(posScreen);
}
return wxACC_OK;
}
// Navigates from fromId to toId/toObject.
wxAccStatus wxDataViewCtrlAccessible::Navigate(wxNavDir navDir, int fromId,
int* toId, wxAccessible** toObject)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
const int numRows = (int)dvWnd->GetRowCount();
if ( fromId == wxACC_SELF )
{
switch ( navDir )
{
case wxNAVDIR_FIRSTCHILD:
if ( numRows > 0 )
{
*toId = 1;
*toObject = NULL;
return wxACC_OK;
}
return wxACC_FALSE;
case wxNAVDIR_LASTCHILD:
if ( numRows > 0 )
{
*toId = numRows;
*toObject = NULL;
return wxACC_OK;
}
return wxACC_FALSE;
case wxNAVDIR_DOWN:
wxFALLTHROUGH;
case wxNAVDIR_NEXT:
wxFALLTHROUGH;
case wxNAVDIR_UP:
wxFALLTHROUGH;
case wxNAVDIR_PREVIOUS:
wxFALLTHROUGH;
case wxNAVDIR_LEFT:
wxFALLTHROUGH;
case wxNAVDIR_RIGHT:
// Standard wxWindow navigation is applicable here.
return wxWindowAccessible::Navigate(navDir, fromId, toId, toObject);
}
}
else
{
switch ( navDir )
{
case wxNAVDIR_FIRSTCHILD:
return wxACC_FALSE;
case wxNAVDIR_LASTCHILD:
return wxACC_FALSE;
case wxNAVDIR_LEFT:
return wxACC_FALSE;
case wxNAVDIR_RIGHT:
return wxACC_FALSE;
case wxNAVDIR_DOWN:
wxFALLTHROUGH;
case wxNAVDIR_NEXT:
if ( fromId < numRows )
{
*toId = fromId + 1;
*toObject = NULL;
return wxACC_OK;
}
return wxACC_FALSE;
case wxNAVDIR_PREVIOUS:
wxFALLTHROUGH;
case wxNAVDIR_UP:
if ( fromId > 1 )
{
*toId = fromId - 1;
*toObject = NULL;
return wxACC_OK;
}
return wxACC_FALSE;
}
}
// Let the framework handle the other cases.
return wxACC_NOT_IMPLEMENTED;
}
// Gets the name of the specified object.
wxAccStatus wxDataViewCtrlAccessible::GetName(int childId, wxString* name)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId == wxACC_SELF )
{
*name = dvCtrl->GetName();
}
else
{
wxDataViewItem item = dvCtrl->GetItemByRow(childId-1);
if ( !item.IsOk() )
{
return wxACC_NOT_IMPLEMENTED;
}
// Name is the value in the first textual column
// plus the name of this column:
// Column1: Value1
wxString itemName;
wxDataViewModel* model = dvCtrl->GetModel();
const unsigned int numCols = dvCtrl->GetColumnCount();
for ( unsigned int col = 0; col < numCols; col++ )
{
wxDataViewColumn *dvCol = dvCtrl->GetColumnAt(col);
if ( dvCol->IsHidden() )
continue; // skip it
wxVariant value;
model->GetValue(value, item, dvCol->GetModelColumn());
if ( !value.IsNull() && !value.IsType(wxS("bool")) )
{
wxString vs = value.MakeString();
if ( !vs.empty() )
{
wxString colName = dvCol->GetTitle();
// If column has no label then present its index.
if ( colName.empty() )
{
// Columns are numbered from 1.
colName = _("Column") + wxString::Format(wxS(" %u"), col+1);
}
itemName = colName + wxS(": ") + vs;
break;
}
}
}
if ( itemName.empty() )
{
// Return row number if not textual column found.
// Rows are numbered from 1.
*name = _("Row") + wxString::Format(wxS(" %i"), childId);
}
else
{
*name = itemName;
}
}
return wxACC_OK;
}
// Gets the number of children.
wxAccStatus wxDataViewCtrlAccessible::GetChildCount(int* childCount)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
*childCount = (int)dvWnd->GetRowCount();
return wxACC_OK;
}
// Gets the specified child (starting from 1).
// If *child is NULL and return value is wxACC_OK,
// this means that the child is a simple element and
// not an accessible object.
wxAccStatus wxDataViewCtrlAccessible::GetChild(int childId, wxAccessible** child)
{
*child = (childId == wxACC_SELF) ? this : NULL;
return wxACC_OK;
}
// Performs the default action. childId is 0 (the action for this object)
// or > 0 (the action for a child).
// Return wxACC_NOT_SUPPORTED if there is no default action for this
// window (e.g. an edit control).
wxAccStatus wxDataViewCtrlAccessible::DoDefaultAction(int childId)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId != wxACC_SELF )
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( !dvWnd->IsList() )
{
wxDataViewTreeNode* node = dvWnd->GetTreeNodeByRow(childId-1);
if ( node )
{
if ( node->HasChildren() )
{
// Expand or collapse the node.
node->ToggleOpen();
return wxACC_OK;
}
}
}
}
return wxACC_NOT_SUPPORTED;
}
// Gets the default action for this object (0) or > 0 (the action for a child).
// Return wxACC_OK even if there is no action. actionName is the action, or the empty
// string if there is no action.
// The retrieved string describes the action that is performed on an object,
// not what the object does as a result. For example, a toolbar button that prints
// a document has a default action of "Press" rather than "Prints the current document."
wxAccStatus wxDataViewCtrlAccessible::GetDefaultAction(int childId, wxString* actionName)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxString action;
if ( childId != wxACC_SELF )
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( !dvWnd->IsList() )
{
wxDataViewTreeNode* node = dvWnd->GetTreeNodeByRow(childId-1);
if ( node )
{
if ( node->HasChildren() )
{
if ( node->IsOpen() )
action = _("Collapse");
else
action = _("Expand");
}
}
}
}
*actionName = action;
return wxACC_OK;
}
// Returns the description for this object or a child.
wxAccStatus wxDataViewCtrlAccessible::GetDescription(int childId, wxString* description)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId == wxACC_SELF )
{
*description = wxString::Format(_("This %s has %u columns"),
dvCtrl->GetName().c_str(),
dvCtrl->GetColumnCount());
}
else
{
wxDataViewItem item = dvCtrl->GetItemByRow(childId-1);
if ( !item.IsOk() )
{
return wxACC_NOT_IMPLEMENTED;
}
// Description is concatenation of the contents of items in all columns:
// Column1: Value1, Column2: Value2, ...
// First textual item should be skipped because it is returned
// as a Name property.
wxString itemDesc;
bool firstTextSkipped = false;
wxDataViewModel* model = dvCtrl->GetModel();
const unsigned int numCols = dvCtrl->GetColumnCount();
for ( unsigned int col = 0; col < numCols; col++ )
{
if ( model->IsContainer(item) && !model->HasContainerColumns(item) )
continue; // skip it
wxDataViewColumn *dvCol = dvCtrl->GetColumnAt(col);
if ( dvCol->IsHidden() )
continue; // skip it
wxString valStr;
wxVariant value;
model->GetValue(value, item, dvCol->GetModelColumn());
if ( value.IsNull() )
{
valStr = _("null");
}
else if ( value.IsType(wxS("bool")) )
{
valStr = value.GetBool() ? _("yes") : _("no");
}
else
{
// First textual item is returned as Name property
// so it needs to be skipped for Description.
valStr = value.MakeString();
if ( !valStr.empty() && !firstTextSkipped )
{
firstTextSkipped = true;
valStr.Empty();
}
}
if ( !valStr.empty() )
{
wxString colName = dvCol->GetTitle();
// If column has no label then present its index.
if ( colName.empty() )
{
// Columns are numbered from 1.
colName = _("Column") + wxString::Format(wxS(" %u"), col+1);
}
if ( !itemDesc.empty() )
itemDesc.Append(wxS(", "));
itemDesc.Append(colName);
itemDesc.Append(wxS(": "));
itemDesc.Append(valStr);
}
}
*description = itemDesc;
}
return wxACC_OK;
}
// Returns help text for this object or a child, similar to tooltip text.
wxAccStatus wxDataViewCtrlAccessible::GetHelpText(int childId, wxString* helpText)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId == wxACC_SELF )
{
*helpText = dvCtrl->GetHelpText();
}
else
{
wxDataViewItem item = dvCtrl->GetItemByRow(childId-1);
if ( item.IsOk() )
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
wxRect rect = dvWnd->GetItemRect(item, NULL);
*helpText = dvWnd->GetHelpTextAtPoint(rect.GetPosition(), wxHelpEvent::Origin_Keyboard);
}
else
{
*helpText = wxEmptyString;
}
}
return wxACC_OK;
}
// Returns the keyboard shortcut for this object or child.
// Return e.g. ALT+K
wxAccStatus wxDataViewCtrlAccessible::GetKeyboardShortcut(int childId, wxString* shortcut)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
if ( childId != wxACC_SELF )
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( !dvWnd->IsList() )
{
wxDataViewTreeNode* node = dvWnd->GetTreeNodeByRow(childId-1);
if ( node )
{
if ( node->HasChildren() )
{
if ( node->IsOpen() )
*shortcut = _("Left");
else
*shortcut = _("Right");
return wxACC_OK;
}
}
}
}
return wxACC_FALSE;
}
// Returns a role constant.
wxAccStatus wxDataViewCtrlAccessible::GetRole(int childId, wxAccRole* role)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( childId == wxACC_SELF )
*role = dvWnd->IsList() ? wxROLE_SYSTEM_LIST : wxROLE_SYSTEM_OUTLINE;
else
*role = dvWnd->IsList() ? wxROLE_SYSTEM_LISTITEM : wxROLE_SYSTEM_OUTLINEITEM;
return wxACC_OK;
}
// Returns a state constant.
wxAccStatus wxDataViewCtrlAccessible::GetState(int childId, long* state)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
long st = 0;
if ( childId == wxACC_SELF )
{
if( dvWnd->IsFocusable() )
st |= wxACC_STATE_SYSTEM_FOCUSABLE;
if ( dvWnd->HasFocus() )
st |= wxACC_STATE_SYSTEM_FOCUSED;
}
else
{
if( dvWnd->IsFocusable() )
st |= wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_SELECTABLE;
if ( !dvWnd->IsSingleSel() )
st |= wxACC_STATE_SYSTEM_MULTISELECTABLE | wxACC_STATE_SYSTEM_EXTSELECTABLE;
if ( dvWnd->GetCurrentRow() == (unsigned int)childId-1 )
st |= wxACC_STATE_SYSTEM_FOCUSED;
if ( dvWnd->IsRowSelected(childId-1) )
st |= wxACC_STATE_SYSTEM_SELECTED;
if ( !dvWnd->IsList() )
{
wxDataViewTreeNode* node = dvWnd->GetTreeNodeByRow(childId-1);
if ( node )
{
if ( node->HasChildren() )
{
if ( node->IsOpen() )
st |= wxACC_STATE_SYSTEM_EXPANDED;
else
st |= wxACC_STATE_SYSTEM_COLLAPSED;
}
}
}
wxDataViewItem item = dvWnd->GetItemByRow(childId-1);
if ( item.IsOk() )
{
if ( !dvWnd->HasEditableColumn(item) )
{
st |= wxACC_STATE_SYSTEM_READONLY;
}
}
}
*state = st;
return wxACC_OK;
}
// Returns a localized string representing the value for the object
// or child.
wxAccStatus wxDataViewCtrlAccessible::GetValue(int childId, wxString* strValue)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxString val;
if ( childId != wxACC_SELF )
{
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( !dvWnd->IsList() )
{
// In the tree view each item within the control has a zero-based value
// that represents its level within the hierarchy and this value
// is returned as a Value property.
wxDataViewTreeNode *node = dvWnd->GetTreeNodeByRow(childId-1);
if ( node )
{
val = wxString::Format(wxS("%i"), node->GetIndentLevel());
}
}
}
*strValue = val;
return wxACC_OK;
}
// Selects the object or child.
wxAccStatus wxDataViewCtrlAccessible::Select(int childId, wxAccSelectionFlags selectFlags)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
if ( childId == wxACC_SELF )
{
if ( selectFlags == wxACC_SEL_TAKEFOCUS )
{
dvWnd->SetFocus();
}
else if ( selectFlags != wxACC_SEL_NONE )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
}
else
{
// These flags are not allowed in the single-selection mode:
if ( dvWnd->IsSingleSel() &&
selectFlags & (wxACC_SEL_EXTENDSELECTION | wxACC_SEL_ADDSELECTION | wxACC_SEL_REMOVESELECTION) )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
const int row = childId-1;
if ( selectFlags == wxACC_SEL_TAKEFOCUS )
{
dvWnd->ChangeCurrentRow(row);
}
else if ( selectFlags & wxACC_SEL_TAKESELECTION )
{
// This flag must not be combined with the following flags:
if ( selectFlags & (wxACC_SEL_EXTENDSELECTION | wxACC_SEL_ADDSELECTION | wxACC_SEL_REMOVESELECTION) )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
dvWnd->UnselectAllRows();
dvWnd->SelectRow(row, true);
if ( selectFlags & wxACC_SEL_TAKEFOCUS || dvWnd->IsSingleSel() )
{
dvWnd->ChangeCurrentRow(row);
}
}
else if ( selectFlags & wxACC_SEL_EXTENDSELECTION )
{
// This flag must not be combined with the following flag:
if ( selectFlags & wxACC_SEL_TAKESELECTION )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
// These flags cannot be set together:
if ( (selectFlags & (wxACC_SEL_ADDSELECTION | wxACC_SEL_REMOVESELECTION))
== (wxACC_SEL_ADDSELECTION | wxACC_SEL_REMOVESELECTION) )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
// We have to have a focused object as a selection anchor.
unsigned int focusedRow = dvWnd->GetCurrentRow();
if ( focusedRow == (unsigned int)-1 )
{
wxFAIL_MSG( wxS("No selection anchor") );
return wxACC_INVALID_ARG;
}
bool doSelect;
if ( selectFlags & wxACC_SEL_ADDSELECTION )
doSelect = true;
else if ( selectFlags & wxACC_SEL_REMOVESELECTION )
doSelect = false;
else
// If the anchor object is selected, the selection is extended.
// If the anchor object is not selected, all objects are unselected.
doSelect = dvWnd->IsRowSelected(focusedRow);
if ( doSelect )
{
dvWnd->SelectRows(focusedRow, row);
}
else
{
for( int r = focusedRow; r <= row; r++ )
dvWnd->SelectRow(r, false);
}
if ( selectFlags & wxACC_SEL_TAKEFOCUS )
{
dvWnd->ChangeCurrentRow(row);
}
}
else if ( selectFlags & wxACC_SEL_ADDSELECTION )
{
// This flag must not be combined with the following flags:
if ( selectFlags & (wxACC_SEL_TAKESELECTION | wxACC_SEL_REMOVESELECTION) )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
// Combination with wxACC_SEL_EXTENDSELECTION is already handled
// (see wxACC_SEL_EXTENDSELECTION block).
dvWnd->SelectRow(row, true);
if ( selectFlags & wxACC_SEL_TAKEFOCUS )
{
dvWnd->ChangeCurrentRow(row);
}
}
else if ( selectFlags & wxACC_SEL_REMOVESELECTION )
{
// This flag must not be combined with the following flags:
if ( selectFlags & (wxACC_SEL_TAKESELECTION | wxACC_SEL_ADDSELECTION) )
{
wxFAIL_MSG( wxS("Invalid selection flag") );
return wxACC_INVALID_ARG;
}
// Combination with wxACC_SEL_EXTENDSELECTION is already handled
// (see wxACC_SEL_EXTENDSELECTION block).
dvWnd->SelectRow(row, false);
if ( selectFlags & wxACC_SEL_TAKEFOCUS )
{
dvWnd->ChangeCurrentRow(row);
}
}
}
return wxACC_OK;
}
// Gets the window with the keyboard focus.
// If childId is 0 and child is NULL, no object in
// this subhierarchy has the focus.
// If this object has the focus, child should be 'this'.
wxAccStatus wxDataViewCtrlAccessible::GetFocus(int* childId, wxAccessible** child)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewMainWindow* dvWnd = wxDynamicCast(dvCtrl->GetMainWindow(), wxDataViewMainWindow);
const unsigned int row = dvWnd->GetCurrentRow();
if ( row != (unsigned int)childId-1 )
{
*childId = row+1;
*child = NULL;
}
else if ( dvWnd->HasFocus() )
{
*childId = wxACC_SELF;
*child = this;
}
else
{
*childId = 0;
*child = NULL;
}
return wxACC_OK;
}
#if wxUSE_VARIANT
// Gets a variant representing the selected children
// of this object.
// Acceptable values:
// - a null variant (IsNull() returns true)
// - a "void*" pointer to a wxAccessible child object
// - an integer representing the selected child element,
// or 0 if this object is selected (GetType() == wxT("long"))
// - a list variant (GetType() == wxT("list"))
wxAccStatus wxDataViewCtrlAccessible::GetSelections(wxVariant* selections)
{
wxDataViewCtrl* dvCtrl = wxDynamicCast(GetWindow(), wxDataViewCtrl);
wxCHECK( dvCtrl, wxACC_FAIL );
wxDataViewItemArray sel;
dvCtrl->GetSelections(sel);
if ( sel.IsEmpty() )
{
selections->MakeNull();
}
else
{
wxVariantList tempList;
wxVariant v(tempList);
for( size_t i = 0; i < sel.GetCount(); i++ )
{
int row = dvCtrl->GetRowByItem(sel[i]);
v.Append(wxVariant((long)row+1));
}
// Don't return the list if one child is selected.
if ( v.GetCount() == 1 )
*selections = wxVariant(v[0].GetLong());
else
*selections = v;
}
return wxACC_OK;
}
#endif // wxUSE_VARIANT
#endif // wxUSE_ACCESSIBILITY
#endif // wxUSE_DATAVIEWCTRL