[banshee/a11y: 9/27] [a11y] Basic ListView accessibility.
- From: Gabriel Burt <gburt src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [banshee/a11y: 9/27] [a11y] Basic ListView accessibility.
- Date: Tue, 6 Oct 2009 00:21:45 +0000 (UTC)
commit a2cc549c122e7039e1d30a5579bf4fae77b7bcf4
Author: Eitan Isaacson <eitan ascender com>
Date: Wed Sep 30 15:48:35 2009 -0700
[a11y] Basic ListView accessibility.
.../Accessibility/ColumnCellAccessible.cs | 113 +++++++++
.../Accessibility/ICellAccessibleParent.cs | 14 +
.../Accessibility/ListViewAccessible.cs | 187 ++++++++++++++
.../Accessibility/ListViewAccessible_Selection.cs | 60 +++++
.../Accessibility/ListViewAccessible_Table.cs | 171 +++++++++++++
.../Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs | 14 +-
.../Hyena.Data.Gui/ListView/ListView_Accessible.cs | 150 +++++++++++
.../Hyena.Data.Gui/ListView/ListView_Header.cs | 6 +
.../Hyena.Data.Gui/ListView/ListView_Model.cs | 10 +
src/Libraries/Hyena.Gui/Hyena.Gui.csproj | 12 +-
.../Hyena.Gui/Hyena.Gui/BaseWidgetAccessible.cs | 260 ++++++++++++++++++++
src/Libraries/Hyena.Gui/Makefile.am | 7 +
src/Libraries/Hyena/Hyena.Collections/Selection.cs | 2 +-
13 files changed, 1003 insertions(+), 3 deletions(-)
---
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ColumnCellAccessible.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ColumnCellAccessible.cs
new file mode 100644
index 0000000..f376eb9
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ColumnCellAccessible.cs
@@ -0,0 +1,113 @@
+
+using System;
+
+namespace Hyena.Data.Gui.Accessibility
+{
+ public class ColumnCellAccessible: Atk.Object, Atk.ComponentImplementor
+ {
+ protected ColumnCell cell;
+ protected object bound_object;
+
+ public ColumnCellAccessible (object bound_object, ColumnCell cell, ICellAccessibleParent parent)
+ {
+ Role = Atk.Role.TableCell;
+ this.bound_object = bound_object;
+ this.cell = cell;
+ Parent = (Atk.Object) parent;
+ }
+
+ protected override Atk.StateSet OnRefStateSet ()
+ {
+ Atk.StateSet states = base.OnRefStateSet ();
+ states.AddState (Atk.StateType.Transient);
+ states.AddState (Atk.StateType.Focusable);
+ states.AddState (Atk.StateType.Enabled);
+ states.AddState (Atk.StateType.Sensitive);
+ states.AddState (Atk.StateType.Visible);
+
+ if (((ICellAccessibleParent)Parent).IsCellShowing (this))
+ states.AddState (Atk.StateType.Showing);
+
+ if (((ICellAccessibleParent)Parent).IsCellFocused (this))
+ states.AddState (Atk.StateType.Focused);
+
+ if (((ICellAccessibleParent)Parent).IsCellSelected (this))
+ states.AddState (Atk.StateType.Selected);
+
+ return states;
+ }
+
+ protected override int OnGetIndexInParent()
+ {
+ return ((ICellAccessibleParent)Parent).GetCellIndex (this);
+ }
+
+ public double Alpha {
+ get { return 1.0; }
+ }
+
+ public bool SetSize (int w, int h)
+ {
+ return false;
+ }
+
+ public bool SetPosition (int x, int y, Atk.CoordType coordType)
+ {
+ return false;
+ }
+
+ public bool SetExtents (int x, int y, int w, int h, Atk.CoordType coordType)
+ {
+ return false;
+ }
+
+ public void RemoveFocusHandler (uint handlerId)
+ {
+ }
+
+ public bool GrabFocus ()
+ {
+ return false;
+ }
+
+ public void GetSize (out int w, out int h)
+ {
+ Gdk.Rectangle rectangle = ((ICellAccessibleParent)Parent).GetCellExtents(this, Atk.CoordType.Screen);
+ w = rectangle.Width;
+ h = rectangle.Height;
+ }
+
+ public void GetPosition (out int x, out int y, Atk.CoordType coordType)
+ {
+ Gdk.Rectangle rectangle = ((ICellAccessibleParent)Parent).GetCellExtents(this, coordType);
+
+ x = rectangle.X;
+ y = rectangle.Y;
+ }
+
+ public void GetExtents (out int x, out int y, out int w, out int h, Atk.CoordType coordType)
+ {
+ Gdk.Rectangle rectangle = ((ICellAccessibleParent)Parent).GetCellExtents(this, coordType);
+
+ x = rectangle.X;
+ y = rectangle.Y;
+ w = rectangle.Width;
+ h = rectangle.Height;
+ }
+
+ public virtual Atk.Object RefAccessibleAtPoint (int x, int y, Atk.CoordType coordType)
+ {
+ return null;
+ }
+
+ public bool Contains (int x, int y, Atk.CoordType coordType)
+ {
+ return false;
+ }
+
+ public uint AddFocusHandler (Atk.FocusHandler handler)
+ {
+ return 0;
+ }
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ICellAccessibleParent.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ICellAccessibleParent.cs
new file mode 100644
index 0000000..132066b
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ICellAccessibleParent.cs
@@ -0,0 +1,14 @@
+
+using System;
+
+namespace Hyena.Data.Gui.Accessibility
+{
+ public interface ICellAccessibleParent
+ {
+ Gdk.Rectangle GetCellExtents (ColumnCellAccessible cell, Atk.CoordType coord_type);
+ int GetCellIndex (ColumnCellAccessible cell);
+ bool IsCellShowing (ColumnCellAccessible cell);
+ bool IsCellFocused (ColumnCellAccessible cell);
+ bool IsCellSelected (ColumnCellAccessible cell);
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible.cs
new file mode 100644
index 0000000..3264139
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible.cs
@@ -0,0 +1,187 @@
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+using Hyena.Data.Gui;
+
+namespace Hyena.Data.Gui.Accessibility
+{
+ public partial class ListViewAccessible<T> : Hyena.Gui.BaseWidgetAccessible,
+ ICellAccessibleParent
+ {
+ private ListView<T> list_view;
+ private Dictionary<int, ColumnCellAccessible> cell_cache;
+
+ public ListViewAccessible (GLib.Object widget): base (widget as Gtk.Widget)
+ {
+ list_view = widget as ListView<T>;
+ // TODO replace with list_view.Name?
+ Name = "ListView";
+ Description = "ListView";
+ Role = Atk.Role.Table;
+ Parent = list_view.Parent.RefAccessible();
+
+ cell_cache = new Dictionary<int, ColumnCellAccessible>();
+
+ list_view.ModelChanged += (o, a) => OnModelChanged ();
+ list_view.Model.Reloaded += (o, a) => OnModelChanged ();
+ OnModelChanged ();
+
+ list_view.Selection.FocusRowChanged += OnSelectionFocusChanged;
+ list_view.Selection.FocusColumnChanged += OnSelectionFocusChanged;
+
+ ListViewAccessible_Selection ();
+ ListViewAccessible_Table ();
+ }
+
+ protected override Atk.StateSet OnRefStateSet ()
+ {
+ Atk.StateSet states = base.OnRefStateSet ();
+ states.AddState (Atk.StateType.ManagesDescendants);
+
+ return states;
+ }
+
+
+ protected override int OnGetIndexInParent()
+ {
+ for (int i=0; i < Parent.NAccessibleChildren; i++)
+ if (Parent.RefAccessibleChild (i) == this)
+ return i;
+
+ return -1;
+ }
+
+ protected override int OnGetNChildren()
+ {
+ return n_columns * n_rows + n_columns;
+ }
+
+ protected override Atk.Object OnRefChild(int index)
+ {
+ ColumnCellAccessible child;
+
+ if (cell_cache.ContainsKey(index))
+ {
+ return cell_cache[index];
+ }
+ if (0 > index - n_columns)
+ {
+ child = (ColumnCellAccessible) list_view.ColumnController.Where (c => c.Visible).ElementAtOrDefault (index).HeaderCell.GetAccessible (this);
+ }
+ else
+ {
+ int column = (index - n_columns)%n_columns;
+ int row = (index - n_columns)/n_columns;
+ var cell = list_view.ColumnController.Where (c => c.Visible).ElementAtOrDefault (column).GetCell (0);
+ cell.BindListItem (list_view.Model[row]);
+ child = (ColumnCellAccessible) cell.GetAccessible (this);
+ }
+
+ cell_cache.Add(index, child);
+
+ return child;
+ }
+
+ public override Atk.Object RefAccessibleAtPoint (int x, int y, Atk.CoordType coordType)
+ {
+ int row, col;
+ list_view.GetCellAtPoint(x, y, coordType, out row, out col);
+ return RefAt (row, col);
+ }
+
+ private void OnModelChanged ()
+ {
+ GLib.Signal.Emit (this, "model_changed");
+ cell_cache.Clear();
+ /*var handler = ModelChanged;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }*/
+ }
+
+ private void OnSelectionFocusChanged (object o, EventArgs a)
+ {
+ Atk.Object cell;
+
+ if (list_view.HeaderFocused)
+ cell = OnRefChild (list_view.Selection.FocusedColumnIndex);
+ else
+ cell = RefAt (list_view.Selection.FocusedRowIndex,
+ list_view.Selection.FocusedColumnIndex);
+
+ GLib.Signal.Emit (this, "active-descendant-changed", cell.Handle);
+ }
+
+ private int n_columns {
+ get { return list_view.ColumnController.Count (c => c.Visible); }
+ set {}
+ }
+
+ private int n_rows {
+ get { return list_view.Model.Count; }
+ set {}
+ }
+
+ # region ICellAccessibleParent
+
+ public int GetCellIndex (ColumnCellAccessible cell)
+ {
+ foreach (KeyValuePair<int, ColumnCellAccessible> kv in cell_cache)
+ {
+ if ((ColumnCellAccessible)kv.Value == cell)
+ return (int)kv.Key;
+ }
+
+ return -1;
+ }
+
+ public Gdk.Rectangle GetCellExtents (ColumnCellAccessible cell, Atk.CoordType coord_type)
+ {
+ int cache_index = GetCellIndex (cell);
+ int minval = int.MinValue;
+ if (cache_index == -1)
+ return new Gdk.Rectangle(minval, minval, minval, minval);
+
+ if (cache_index - n_columns >= 0)
+ {
+ int column = (cache_index - NColumns)%NColumns;
+ int row = (cache_index - NColumns)/NColumns;
+ return list_view.GetColumnCellExtents (row, column, true, coord_type);
+ } else
+ {
+ return list_view.GetColumnHeaderCellExtents (cache_index, true, coord_type);
+ }
+ }
+
+ public bool IsCellShowing (ColumnCellAccessible cell)
+ {
+ Gdk.Rectangle cell_extents = GetCellExtents (cell, Atk.CoordType.Window);
+
+ if (cell_extents.X == int.MinValue && cell_extents.Y == int.MinValue)
+ return false;
+
+ return true;
+ }
+
+ public bool IsCellFocused (ColumnCellAccessible cell)
+ {
+ int cell_index = GetCellIndex (cell);
+ if (cell_index%NColumns != 0)
+ return false; // Only 0 column cells get focus now.
+
+ int row = cell_index/NColumns;
+
+ return row == list_view.Selection.FocusedRowIndex;
+ }
+
+ public bool IsCellSelected (ColumnCellAccessible cell)
+ {
+ int cell_index = GetCellIndex (cell);
+ return IsChildSelected (cell_index);
+ }
+
+ # endregion ICellAccessibleParent
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Selection.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Selection.cs
new file mode 100644
index 0000000..392155a
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Selection.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+using Hyena.Data.Gui;
+
+namespace Hyena.Data.Gui.Accessibility
+{
+ public partial class ListViewAccessible<T> : Atk.SelectionImplementor
+ {
+ public void ListViewAccessible_Selection ()
+ {
+ list_view.SelectionProxy.Changed += OnSelectionChanged;
+ }
+
+ public bool AddSelection (int index)
+ {
+ return AddRowSelection (GetRowAtIndex (index));
+ }
+
+ public bool ClearSelection ()
+ {
+ list_view.Selection.Clear ();
+ return true;
+ }
+
+ public bool IsChildSelected (int index)
+ {
+ return IsRowSelected (GetRowAtIndex (index));
+ }
+
+ public bool RemoveSelection (int index)
+ {
+ int row = list_view.Selection.RangeCollection [index/n_columns];
+ return RemoveRowSelection (row);
+ }
+
+ public Atk.Object RefSelection (int index)
+ {
+ int row = list_view.Selection.RangeCollection [index/n_columns];
+ int column = index%n_columns;
+ return RefAt (row, column);
+ }
+
+ public int SelectionCount {
+ get { return list_view.Selection.Count * n_columns; }
+ }
+
+ public bool SelectAllSelection ()
+ {
+ list_view.Selection.SelectAll ();
+ return true;
+ }
+
+ private void OnSelectionChanged (object o, EventArgs a)
+ {
+ GLib.Signal.Emit (this, "selection_changed");
+ }
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Table.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Table.cs
new file mode 100644
index 0000000..129c721
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/Accessibility/ListViewAccessible_Table.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+using Hyena.Data.Gui;
+
+namespace Hyena.Data.Gui.Accessibility
+{
+ public partial class ListViewAccessible<T> : Atk.TableImplementor
+ {
+ public void ListViewAccessible_Table ()
+ {
+ }
+
+ public Atk.Object Caption {
+ get { return new Atk.NoOpObject (list_view); }
+ set {}
+ }
+
+ public int NColumns {
+ get { return n_columns; }
+ set {}
+ }
+
+ public int NRows {
+ get { return n_rows; }
+ set {}
+ }
+
+ public Atk.Object Summary {
+ get { return new Atk.NoOpObject (list_view); }
+ set {}
+ }
+
+ public bool AddColumnSelection (int column)
+ {
+ return false;
+ }
+
+ public bool AddRowSelection (int row)
+ {
+ list_view.Selection.Select (row);
+ return true;
+ }
+
+ public int GetColumnAtIndex (int index)
+ {
+ if (NColumns == 0)
+ return -1;
+ return (index-NColumns)%NColumns;
+ }
+
+ public string GetColumnDescription (int column)
+ {
+ var col = list_view.ColumnController.Where (c => c.Visible).ElementAtOrDefault (column);
+ return col == null ? null : col.LongTitle;
+ }
+
+ public int GetColumnExtentAt (int row, int column)
+ {
+ return 1;
+ }
+
+ public Atk.Object GetColumnHeader (int column)
+ {
+ if (column >= NColumns)
+ return new Atk.NoOpObject (list_view);
+ else
+ return OnRefChild (column);
+ }
+
+ public int GetIndexAt (int row, int column)
+ {
+ return row * NColumns + column + NColumns;
+ }
+
+ public int GetRowAtIndex (int index)
+ {
+ if (NColumns == 0)
+ return -1;
+ return (index-NColumns)/NColumns;
+ }
+
+ public string GetRowDescription (int row)
+ {
+ return "";
+ }
+
+ public int GetRowExtentAt (int row, int column)
+ {
+ return 1;
+ }
+
+ public Atk.Object GetRowHeader (int row)
+ {
+ return new Atk.NoOpObject (list_view);
+ }
+
+ private static readonly int [] empty_int_array = new int[0];
+ public int [] SelectedColumns {
+ get { return empty_int_array; }
+ }
+
+ public int [] SelectedRows {
+ get { return list_view.Selection.ToArray (); }
+ }
+
+ public bool IsColumnSelected (int column)
+ {
+ return false;
+ }
+
+ public bool IsRowSelected (int row)
+ {
+ return list_view.Selection.Contains (row);
+ }
+
+ public bool IsSelected (int row, int column)
+ {
+ return list_view.Selection.Contains (row);
+ }
+
+ public Atk.Object RefAt (int row, int column)
+ {
+ int index = NColumns*row + column + NColumns;
+ return OnRefChild (index);
+ }
+
+ public bool RemoveColumnSelection (int column)
+ {
+ return false;
+ }
+
+ public bool RemoveRowSelection (int row)
+ {
+ list_view.Selection.Unselect (row);
+ return true;
+ }
+
+ public void SetColumnDescription (int column, string description)
+ {
+ }
+
+ public void SetColumnHeader (int column, Atk.Object header)
+ {
+ }
+
+ public void SetRowDescription (int row, string description)
+ {
+ }
+
+ public void SetRowHeader (int row, Atk.Object header)
+ {
+ }
+
+ #pragma warning disable 0067
+
+ /*
+ public event Atk.ColumnDeletedHandler ColumnDeleted;
+ public event Atk.ColumnInsertedHandler ColumnInserted;
+ public event EventHandler ColumnReordered;
+ public event EventHandler ModelChanged;
+ public event Atk.RowDeletedHandler RowDeleted;
+ public event Atk.RowInsertedHandler RowInserted;
+ public event EventHandler RowReordered;
+ */
+
+ #pragma warning restore 0067
+
+ }
+}
\ No newline at end of file
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
index 7812d1a..05cfb2a 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
@@ -31,6 +31,8 @@ using System.Reflection;
using Gtk;
using Cairo;
+using Hyena.Data.Gui.Accessibility;
+
namespace Hyena.Data.Gui
{
public abstract class ColumnCell
@@ -40,7 +42,17 @@ namespace Hyena.Data.Gui
private PropertyInfo property_info, sub_property_info;
private object bound_object;
private object bound_object_parent;
-
+
+ public virtual Atk.Object GetAccessible (ICellAccessibleParent parent)
+ {
+ return new ColumnCellAccessible (BoundObject, this, parent);
+ }
+
+ public virtual string GetTextAlternative (object obj)
+ {
+ return string.Empty;
+ }
+
public ColumnCell (string property, bool expand)
{
Property = property;
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs
new file mode 100644
index 0000000..e8f93c1
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs
@@ -0,0 +1,150 @@
+//
+// ListView_Accessible.cs
+//
+// Author:
+// Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+using Gtk;
+
+using Hyena.Data.Gui.Accessibility;
+
+namespace Hyena.Data.Gui
+{
+ public partial class ListView<T> : ListViewBase
+ {
+ static ListView ()
+ {
+ ListViewAccessibleFactory<T>.Init ();
+ }
+
+ public Gdk.Rectangle GetColumnCellExtents (int row, int column)
+ {
+ return GetColumnCellExtents (row, column, true);
+ }
+
+ public Gdk.Rectangle GetColumnCellExtents (int row, int column, bool clip) {
+ return GetColumnCellExtents (row, column, clip, Atk.CoordType.Window);
+ }
+
+ public Gdk.Rectangle GetColumnCellExtents (int row, int column, bool clip, Atk.CoordType coord_type)
+ {
+ int width = GetColumnWidth (column);
+ int height = RowHeight;
+
+ int y = (int)GetYAtRow (row) - VadjustmentValue + ListAllocation.Y;
+
+ int x = ListAllocation.X - HadjustmentValue;
+ for (int index=0;index<column;index++)
+ x += GetColumnWidth(index);
+
+ Gdk.Rectangle rectangle = new Gdk.Rectangle(x, y, width, height);
+
+ if (clip && !ListAllocation.Contains (rectangle))
+ return new Gdk.Rectangle(int.MinValue, int.MinValue, int.MinValue, int.MinValue);
+
+ if (coord_type == Atk.CoordType.Window)
+ return rectangle;
+
+ int origin_x, origin_y;
+ GdkWindow.GetPosition (out origin_x, out origin_y);
+
+ rectangle.X += origin_x;
+ rectangle.Y += origin_y;
+
+ return rectangle;
+ }
+
+ public Gdk.Rectangle GetColumnHeaderCellExtents (int column, bool clip, Atk.CoordType coord_type)
+ {
+ if (!HeaderVisible)
+ return new Gdk.Rectangle(int.MinValue, int.MinValue,
+ int.MinValue, int.MinValue);
+ int width = GetColumnWidth (column);
+ int height = HeaderHeight;
+
+ int x = header_rendering_alloc.X - HadjustmentValue + Theme.BorderWidth;
+ if (column != 0)
+ x += Theme.InnerBorderWidth;
+ for (int index=0;index<column;index++)
+ x += GetColumnWidth(index);
+
+ int y = Theme.BorderWidth + header_rendering_alloc.Y;
+
+ Gdk.Rectangle rectangle = new Gdk.Rectangle(x, y, width, height);
+
+ if (coord_type == Atk.CoordType.Window)
+ return rectangle;
+
+ int origin_x, origin_y;
+ GdkWindow.GetPosition (out origin_x, out origin_y);
+
+ rectangle.X += origin_x;
+ rectangle.Y += origin_y;
+
+ return rectangle;
+ }
+
+ public void GetCellAtPoint (int x, int y, Atk.CoordType coord_type, out int row, out int col)
+ {
+ int origin_x = 0;
+ int origin_y = 0;
+ if (coord_type == Atk.CoordType.Screen)
+ GdkWindow.GetPosition (out origin_x, out origin_y);
+
+ x = x - ListAllocation.X - origin_x;
+ y = y - ListAllocation.Y - origin_y;
+
+ Column column = GetColumnAt (x);
+
+ CachedColumn cached_column = GetCachedColumnForColumn (column);
+
+ row = GetRowAtY (y);
+ col = cached_column.Index;
+ }
+ }
+
+ internal class ListViewAccessibleFactory<T> : Atk.ObjectFactory
+ {
+ public static void Init ()
+ {
+ new ListViewAccessibleFactory<T> ();
+ Atk.Global.DefaultRegistry.SetFactoryType ((GLib.GType)typeof(ListView<T>), (GLib.GType)typeof (ListViewAccessibleFactory<T>));
+ }
+
+ protected override Atk.Object OnCreateAccessible (GLib.Object obj)
+ {
+ return new ListViewAccessible<T> (obj);
+ }
+
+ protected override GLib.GType OnGetAccessibleType ()
+ {
+ return ListViewAccessible<T>.GType;
+ }
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Header.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Header.cs
index a7e08c4..819585b 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Header.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Header.cs
@@ -414,6 +414,12 @@ namespace Hyena.Data.Gui
return null;
}
+ protected int GetColumnWidth (int column_index)
+ {
+ CachedColumn cached_column = column_cache[column_index];
+ return cached_column.Width;
+ }
+
private bool CanResizeColumn (int column_index)
{
// At least one column to the left (including the one being resized) should be resizable.
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Model.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Model.cs
index 891d557..e91accd 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Model.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Model.cs
@@ -35,6 +35,10 @@ namespace Hyena.Data.Gui
{
public partial class ListView<T> : ListViewBase
{
+ #pragma warning disable 0067
+ public event EventHandler ModelChanged;
+ #pragma warning restore 0067
+
public void SetModel (IListModel<T> model)
{
SetModel (model, 0.0);
@@ -73,8 +77,14 @@ namespace Hyena.Data.Gui
}
RefreshViewForModel (vpos);
+
+ var handler = ModelChanged;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
}
+
private void RefreshViewForModel (double? vpos)
{
if (Model == null) {
diff --git a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
index 64e70de..9621dc4 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
+++ b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
@@ -149,6 +149,13 @@
<Compile Include="Hyena.Gui.Theatrics\Pulsator.cs" />
<Compile Include="Hyena.Gui\PixbufImageSurface.cs" />
<Compile Include="Hyena.Widgets\TextViewEditable.cs" />
+ <Compile Include="Hyena.Data.Gui\ListView\ListView_Accessible.cs" />
+ <Compile Include="Hyena.Gui\BaseWidgetAccessible.cs" />
+ <Compile Include="Hyena.Data.Gui\Accessibility\ColumnCellAccessible.cs" />
+ <Compile Include="Hyena.Data.Gui\Accessibility\ListViewAccessible.cs" />
+ <Compile Include="Hyena.Data.Gui\Accessibility\ICellAccessibleParent.cs" />
+ <Compile Include="Hyena.Data.Gui\Accessibility\ListViewAccessible_Table.cs" />
+ <Compile Include="Hyena.Data.Gui\Accessibility\ListViewAccessible_Selection.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
@@ -167,4 +174,7 @@
</Properties>
</MonoDevelop>
</ProjectExtensions>
-</Project>
+ <ItemGroup>
+ <Folder Include="Hyena.Data.Gui\Accessibility\" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/Libraries/Hyena.Gui/Hyena.Gui/BaseWidgetAccessible.cs b/src/Libraries/Hyena.Gui/Hyena.Gui/BaseWidgetAccessible.cs
new file mode 100644
index 0000000..4ef1a3a
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Gui/BaseWidgetAccessible.cs
@@ -0,0 +1,260 @@
+//
+// BaseWidgetAccessible.cs
+//
+// Author:
+// Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+using Atk;
+
+namespace Hyena.Gui
+{
+ public class BaseWidgetAccessible : Gtk.Accessible, Atk.ComponentImplementor
+ {
+ private Gtk.Widget widget;
+ private uint focus_id = 0;
+ private Dictionary<uint, Atk.FocusHandler> focus_handlers = new Dictionary<uint, Atk.FocusHandler> ();
+
+ public BaseWidgetAccessible (Gtk.Widget widget)
+ {
+ this.widget = widget;
+ widget.SizeAllocated += OnAllocated;
+ widget.Mapped += OnMap;
+ widget.Unmapped += OnMap;
+ widget.FocusInEvent += OnFocus;
+ widget.FocusOutEvent += OnFocus;
+ widget.AddNotification ("sensitive", (o, a) => NotifyStateChange (StateType.Sensitive, widget.Sensitive));
+ widget.AddNotification ("visible", (o, a) => NotifyStateChange (StateType.Visible, widget.Visible));
+ }
+
+ public virtual new Atk.Layer Layer {
+ get { return Layer.Widget; }
+ }
+
+ protected override Atk.StateSet OnRefStateSet ()
+ {
+ var s = base.OnRefStateSet ();
+
+ AddStateIf (s, widget.CanFocus, StateType.Focusable);
+ AddStateIf (s, widget.HasFocus, StateType.Focused);
+ AddStateIf (s, widget.Sensitive, StateType.Sensitive);
+ AddStateIf (s, widget.Sensitive, StateType.Enabled);
+ AddStateIf (s, widget.HasDefault, StateType.Default);
+ AddStateIf (s, widget.Visible, StateType.Visible);
+ AddStateIf (s, widget.Visible && widget.IsMapped, StateType.Showing);
+
+ return s;
+ }
+
+ private static void AddStateIf (StateSet s, bool condition, StateType t)
+ {
+ if (condition) {
+ s.AddState (t);
+ }
+ }
+
+ private void OnFocus (object o, EventArgs args)
+ {
+ NotifyStateChange (StateType.Focused, widget.HasFocus);
+ var handler = FocusChanged;
+ if (handler != null) {
+ handler (this, widget.HasFocus);
+ }
+ }
+
+ private void OnMap (object o, EventArgs args)
+ {
+ NotifyStateChange (StateType.Showing, widget.Visible && widget.IsMapped);
+ }
+
+ private void OnAllocated (object o, EventArgs args)
+ {
+ var a = widget.Allocation;
+ var bounds = new Atk.Rectangle () { X = a.X, Y = a.Y, Width = a.Width, Height = a.Height };
+ GLib.Signal.Emit (this, "bounds_changed", bounds);
+ /*var handler = BoundsChanged;
+ if (handler != null) {
+ handler (this, new BoundsChangedArgs () { Args = new object [] { bounds } });
+ }*/
+ }
+
+ private event FocusHandler FocusChanged;
+
+ #region Atk.Component
+
+ public uint AddFocusHandler (Atk.FocusHandler handler)
+ {
+ if (!focus_handlers.ContainsValue (handler)) {
+ FocusChanged += handler;
+ focus_handlers[++focus_id] = handler;
+ return focus_id;
+ }
+ return 0;
+ }
+
+ public bool Contains (int x, int y, Atk.CoordType coordType)
+ {
+ int x_extents, y_extents, w, h;
+ GetExtents (out x_extents, out y_extents, out w, out h, coordType);
+ Gdk.Rectangle extents = new Gdk.Rectangle(x_extents, y_extents, w, h);
+ return extents.Contains(x, y);
+ }
+
+ public virtual Atk.Object RefAccessibleAtPoint (int x, int y, Atk.CoordType coordType)
+ {
+ return new NoOpObject (widget);
+ }
+
+ public void GetExtents (out int x, out int y, out int w, out int h, Atk.CoordType coordType)
+ {
+ w = widget.Allocation.Width;
+ h = widget.Allocation.Height;
+
+ GetPosition (out x, out y, coordType);
+ }
+
+ public void GetPosition (out int x, out int y, Atk.CoordType coordType)
+ {
+ Gdk.Window window = null;
+
+ if (!widget.IsDrawable) {
+ x = y = Int32.MinValue;
+ return;
+ }
+
+ if (widget.Parent != null) {
+ x = widget.Allocation.X;
+ y = widget.Allocation.Y;
+ window = widget.ParentWindow;
+ } else {
+ x = 0;
+ y = 0;
+ window = widget.GdkWindow;
+ }
+
+ int x_window, y_window;
+ window.GetOrigin (out x_window, out y_window);
+ x += x_window;
+ y += y_window;
+
+ if (coordType == Atk.CoordType.Window) {
+ window = widget.GdkWindow.Toplevel;
+ int x_toplevel, y_toplevel;
+ window.GetOrigin (out x_toplevel, out y_toplevel);
+
+ x -= x_toplevel;
+ y -= y_toplevel;
+ }
+ }
+
+ public void GetSize (out int w, out int h)
+ {
+ w = widget.Allocation.Width;
+ h = widget.Allocation.Height;
+ }
+
+ public bool GrabFocus ()
+ {
+ if (!widget.CanFocus) {
+ return false;
+ }
+
+ widget.GrabFocus ();
+
+ var toplevel_window = widget.Toplevel as Gtk.Window;
+ if (toplevel_window != null) {
+ toplevel_window.Present ();
+ }
+
+ return true;
+ }
+
+ public void RemoveFocusHandler (uint handlerId)
+ {
+ if (focus_handlers.ContainsKey (handlerId)) {
+ FocusChanged -= focus_handlers[handlerId];
+ focus_handlers.Remove (handlerId);
+ }
+ }
+
+ public bool SetExtents (int x, int y, int w, int h, Atk.CoordType coordType)
+ {
+ return SetSizeAndPosition (x, y, w, h, coordType, true);
+ }
+
+ public bool SetPosition (int x, int y, Atk.CoordType coordType)
+ {
+ return SetSizeAndPosition (x, y, 0, 0, coordType, false);
+ }
+
+ private bool SetSizeAndPosition (int x, int y, int w, int h, Atk.CoordType coordType, bool setSize)
+ {
+ if (!widget.IsTopLevel) {
+ return false;
+ }
+
+ if (coordType == CoordType.Window) {
+ int x_off, y_off;
+ widget.GdkWindow.GetOrigin (out x_off, out y_off);
+ x += x_off;
+ y += y_off;
+
+ if (x < 0 || y < 0) {
+ return false;
+ }
+ }
+
+ #pragma warning disable 0612
+ widget.SetUposition (x, y);
+ #pragma warning restore 0612
+
+ if (setSize) {
+ widget.SetSizeRequest (w, h);
+ }
+
+ return true;
+ }
+
+ public bool SetSize (int w, int h)
+ {
+ if (widget.IsTopLevel) {
+ widget.SetSizeRequest (w, h);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public double Alpha {
+ get { return 1.0; }
+ }
+
+ #endregion Atk.Component
+
+ }
+}
diff --git a/src/Libraries/Hyena.Gui/Makefile.am b/src/Libraries/Hyena.Gui/Makefile.am
index b17a50d..d9952df 100644
--- a/src/Libraries/Hyena.Gui/Makefile.am
+++ b/src/Libraries/Hyena.Gui/Makefile.am
@@ -3,6 +3,11 @@ ASSEMBLY_BUILD_FLAGS = -unsafe
TARGET = library
LINK = $(REF_HYENA_GUI)
SOURCES = \
+ Hyena.Data.Gui/Accessibility/ColumnCellAccessible.cs \
+ Hyena.Data.Gui/Accessibility/ICellAccessibleParent.cs \
+ Hyena.Data.Gui/Accessibility/ListViewAccessible.cs \
+ Hyena.Data.Gui/Accessibility/ListViewAccessible_Selection.cs \
+ Hyena.Data.Gui/Accessibility/ListViewAccessible_Table.cs \
Hyena.Data.Gui/CellContext.cs \
Hyena.Data.Gui/Column.cs \
Hyena.Data.Gui/ColumnCell.cs \
@@ -18,6 +23,7 @@ SOURCES = \
Hyena.Data.Gui/ITextCell.cs \
Hyena.Data.Gui/ITooltipCell.cs \
Hyena.Data.Gui/ListView/ListView.cs \
+ Hyena.Data.Gui/ListView/ListView_Accessible.cs \
Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs \
Hyena.Data.Gui/ListView/ListView_Header.cs \
Hyena.Data.Gui/ListView/ListView_Interaction.cs \
@@ -42,6 +48,7 @@ SOURCES = \
Hyena.Gui.Theming/Theme.cs \
Hyena.Gui.Theming/ThemeContext.cs \
Hyena.Gui.Theming/ThemeEngine.cs \
+ Hyena.Gui/BaseWidgetAccessible.cs \
Hyena.Gui/CairoExtensions.cs \
Hyena.Gui/CleanRoomStartup.cs \
Hyena.Gui/CompositeUtils.cs \
diff --git a/src/Libraries/Hyena/Hyena.Collections/Selection.cs b/src/Libraries/Hyena/Hyena.Collections/Selection.cs
index 078edc7..5640666 100644
--- a/src/Libraries/Hyena/Hyena.Collections/Selection.cs
+++ b/src/Libraries/Hyena/Hyena.Collections/Selection.cs
@@ -214,7 +214,7 @@ namespace Hyena.Collections
}
}
- protected RangeCollection RangeCollection {
+ public RangeCollection RangeCollection {
get { return ranges; }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]