[hyena] [Hyena.Gui] Only fire ListView Changed signal on KeyReleased when navigating via keyboard
- From: Alex Launi <alexlauni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hyena] [Hyena.Gui] Only fire ListView Changed signal on KeyReleased when navigating via keyboard
- Date: Wed, 15 Dec 2010 20:59:31 +0000 (UTC)
commit 4db8e87f6cf5615fa6daf0f57d10c33524287a87
Author: Alex Launi <alex launi canonical com>
Date: Thu Nov 25 02:54:23 2010 -0500
[Hyena.Gui] Only fire ListView Changed signal on KeyReleased when navigating via keyboard
Prevents Hyena from hammering the database when a key is held down. (bgo#635565).
.../ListView/ListView_Interaction.cs | 287 ++++++++++++--------
Hyena/Hyena.Collections/Selection.cs | 57 +++-
2 files changed, 222 insertions(+), 122 deletions(-)
---
diff --git a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
index dee5241..d466289 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
@@ -5,9 +5,11 @@
// Aaron Bockover <abockover novell com>
// Gabriel Burt <gburt novell com>
// Eitan Isaacson <eitan ascender com>
+// Alex Launi <alex launi canonical com>
//
// Copyright (C) 2007-2009 Novell, Inc.
// Copyright (C) 2009 Eitan Isaacson
+// Copyright (C) 2010 Alex Launi
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -40,6 +42,11 @@ namespace Hyena.Data.Gui
{
public partial class ListView<T> : ListViewBase
{
+ private enum KeyDirection {
+ Press,
+ Release
+ }
+
private bool header_focused = false;
public bool HeaderFocused {
get { return header_focused; }
@@ -118,7 +125,7 @@ namespace Hyena.Data.Gui
return true;
}
- int row_index = Math.Min (Model.Count - 1, Math.Max (0, Selection.FocusedIndex + relative_row));
+ int scroll_target_item_index = Math.Min (Model.Count - 1, Math.Max (0, Selection.FocusedIndex + relative_row));
if (Selection != null) {
if ((modifier & Gdk.ModifierType.ControlMask) != 0) {
@@ -128,21 +135,21 @@ namespace Hyena.Data.Gui
// is not selected, select it and don't move the focus or vadjustment.
// Otherwise, select the new row and scroll etc as necessary.
if (relative_row * relative_row != 1) {
- Selection.SelectFromFirst (row_index, true);
+ Selection.SelectFromFirst (scroll_target_item_index, true, false);
} else if (Selection.Contains (Selection.FocusedIndex)) {
- Selection.SelectFromFirst (row_index, true);
+ Selection.SelectFromFirst (scroll_target_item_index, true, false);
} else {
- Selection.Select (Selection.FocusedIndex);
+ Selection.Select (Selection.FocusedIndex, false);
return true;
}
} else {
Selection.Clear (false);
- Selection.Select (row_index);
+ Selection.Select (scroll_target_item_index, false);
}
}
// Scroll if needed
- double y_at_row = GetViewPointForModelRow (row_index).Y;
+ double y_at_row = GetViewPointForModelRow (scroll_target_item_index).Y;
if (align_y) {
if (y_at_row < VadjustmentValue) {
ScrollToY (y_at_row);
@@ -158,145 +165,203 @@ namespace Hyena.Data.Gui
ScrollToY (vadjustment.Value + y_at_row - GetViewPointForModelRow (Selection.FocusedIndex).Y);
}
- Selection.FocusedIndex = row_index;
+ Selection.FocusedIndex = scroll_target_item_index;
InvalidateList ();
return true;
}
+ private bool UpdateSelectionForKeyboardScroll (Gdk.ModifierType modifier, int relative_row)
+ {
+ if (Selection != null) {
+ if ((modifier & Gdk.ModifierType.ControlMask) != 0) {
+ // Don't change the selection
+ } else {
+ //Console.WriteLine ("Selection.Notify!");
+ Selection.Notify ();
+ }
+ }
+ return true;
+ }
+
protected override bool OnKeyPressEvent (Gdk.EventKey press)
{
bool handled = false;
+
+ switch (press.Key) {
+ case Gdk.Key.a:
+ if ((press.State & Gdk.ModifierType.ControlMask) != 0 && Model.Count > 0) {
+ SelectionProxy.Selection.SelectAll ();
+ handled = true;
+ }
+ break;
+
+ case Gdk.Key.A:
+ if ((press.State & Gdk.ModifierType.ControlMask) != 0 && Selection.Count > 0) {
+ SelectionProxy.Selection.Clear ();
+ handled = true;
+ }
+ break;
+
+ case Gdk.Key.Return:
+ case Gdk.Key.KP_Enter:
+ if (!HeaderFocused) {
+ handled = ActivateSelection ();
+ } else if (HeaderFocused && ActiveColumn >= 0) {
+ OnColumnLeftClicked (
+ column_cache[ActiveColumn].Column);
+ handled = true;
+ }
+ break;
+
+ case Gdk.Key.Escape:
+ handled = CancelColumnDrag ();
+ break;
+
+ case Gdk.Key.space:
+ if (Selection != null && Selection.FocusedIndex != 1 &&
+ !HeaderFocused) {
+ Selection.ToggleSelect (Selection.FocusedIndex);
+ handled = true;
+ }
+ break;
+
+ case Gdk.Key.F10:
+ if ((press.State & Gdk.ModifierType.ShiftMask) != 0)
+ goto case Gdk.Key.Menu;
+ break;
+
+ case Gdk.Key.Menu:
+ // OnPopupMenu() is reserved for list items in derived classes.
+ if (HeaderFocused) {
+ InvokeColumnHeaderMenu (ActiveColumn);
+ handled = true;
+ }
+ break;
+
+ default:
+ handled = HandleKeyboardScrollKey (press, KeyDirection.Press);
+ break;
+ }
+
+ Console.WriteLine ("OnKeyPress for {0}; handled? {1}", press.Key, handled);
+ return handled ? true : base.OnKeyPressEvent (press);
+ }
+
+ private bool HandleKeyboardScrollKey (Gdk.EventKey press, KeyDirection direction)
+ {
+ bool handled = false;
// FIXME: hard-coded grid logic here...
bool grid = ViewLayout != null;
int items_per_row = grid ? (ViewLayout as DataViewLayoutGrid).Columns : 1;
switch (press.Key) {
- case Gdk.Key.a:
- if ((press.State & Gdk.ModifierType.ControlMask) != 0 && Model.Count > 0) {
- SelectionProxy.Selection.SelectAll ();
- handled = true;
- }
- break;
-
- case Gdk.Key.A:
- if ((press.State & Gdk.ModifierType.ControlMask) != 0 && Selection.Count > 0) {
- SelectionProxy.Selection.Clear ();
- handled = true;
- }
- break;
-
- case Gdk.Key.k:
- case Gdk.Key.K:
- case Gdk.Key.Up:
- case Gdk.Key.KP_Up:
- if (!HeaderFocused) {
- handled = KeyboardScroll (press.State, -items_per_row, true);
- }
- break;
+ case Gdk.Key.k:
+ case Gdk.Key.K:
+ case Gdk.Key.Up:
+ case Gdk.Key.KP_Up:
+ if (!HeaderFocused) {
+ handled = (direction == KeyDirection.Press)
+ ? KeyboardScroll (press.State, -items_per_row, true)
+ : UpdateSelectionForKeyboardScroll (press.State, -items_per_row);
+ }
+ break;
- case Gdk.Key.j:
- case Gdk.Key.J:
- case Gdk.Key.Down:
- case Gdk.Key.KP_Down:
+ case Gdk.Key.j:
+ case Gdk.Key.J:
+ case Gdk.Key.Down:
+ case Gdk.Key.KP_Down:
+ if (direction == KeyDirection.Press) {
if (!HeaderFocused) {
handled = KeyboardScroll (press.State, items_per_row, true);
} else {
handled = true;
HeaderFocused = false;
}
- break;
- case Gdk.Key.l:
- case Gdk.Key.L:
- case Gdk.Key.Right:
- case Gdk.Key.KP_Right:
- handled = true;
+ } else if (!HeaderFocused) {
+ handled = UpdateSelectionForKeyboardScroll (press.State, items_per_row);
+ }
+ break;
+
+ case Gdk.Key.l:
+ case Gdk.Key.L:
+ case Gdk.Key.Right:
+ case Gdk.Key.KP_Right:
+ handled = true;
+ if (direction == KeyDirection.Press) {
if (grid && !HeaderFocused) {
handled = KeyboardScroll (press.State, 1, true);
} else if (ActiveColumn + 1 < column_cache.Length) {
ActiveColumn++;
InvalidateHeader ();
}
- break;
- case Gdk.Key.h:
- case Gdk.Key.H:
- case Gdk.Key.Left:
- case Gdk.Key.KP_Left:
- handled = true;
+ } else if (grid && !HeaderFocused) {
+ handled = UpdateSelectionForKeyboardScroll (press.State, 1);
+ }
+ break;
+
+ case Gdk.Key.h:
+ case Gdk.Key.H:
+ case Gdk.Key.Left:
+ case Gdk.Key.KP_Left:
+ handled = true;
+ if (direction == KeyDirection.Press) {
if (grid && !HeaderFocused) {
handled = KeyboardScroll (press.State, -1, true);
} else if (ActiveColumn - 1 >= 0) {
ActiveColumn--;
InvalidateHeader ();
}
- break;
- case Gdk.Key.Page_Up:
- case Gdk.Key.KP_Page_Up:
- if (!HeaderFocused)
- handled = vadjustment != null && KeyboardScroll (press.State,
- (int)(-vadjustment.PageIncrement / (double)ChildSize.Height) * items_per_row, false);
- break;
-
- case Gdk.Key.Page_Down:
- case Gdk.Key.KP_Page_Down:
- if (!HeaderFocused)
- handled = vadjustment != null && KeyboardScroll (press.State,
- (int)(vadjustment.PageIncrement / (double)ChildSize.Height) * items_per_row, false);
- break;
-
- case Gdk.Key.Home:
- case Gdk.Key.KP_Home:
- if (!HeaderFocused)
- handled = KeyboardScroll (press.State, -10000000, true);
- break;
-
- case Gdk.Key.End:
- case Gdk.Key.KP_End:
- if (!HeaderFocused)
- handled = KeyboardScroll (press.State, 10000000, true);
- break;
-
- case Gdk.Key.Return:
- case Gdk.Key.KP_Enter:
- if (!HeaderFocused) {
- handled = ActivateSelection ();
- } else if (HeaderFocused && ActiveColumn >= 0) {
- OnColumnLeftClicked (
- column_cache[ActiveColumn].Column);
- handled = true;
- }
- break;
-
- case Gdk.Key.Escape:
- handled = CancelColumnDrag ();
- break;
-
- case Gdk.Key.space:
- if (Selection != null && Selection.FocusedIndex != 1 &&
- !HeaderFocused) {
- Selection.ToggleSelect (Selection.FocusedIndex);
- handled = true;
- }
- break;
-
- case Gdk.Key.F10:
- if ((press.State & Gdk.ModifierType.ShiftMask) != 0)
- goto case Gdk.Key.Menu;
- break;
-
- case Gdk.Key.Menu:
- // OnPopupMenu() is reserved for list items in derived classes.
- if (HeaderFocused) {
- InvokeColumnHeaderMenu (ActiveColumn);
- handled = true;
- }
- break;
+ } else if (grid && !HeaderFocused) {
+ handled = UpdateSelectionForKeyboardScroll (press.State, -1);
+ }
+ break;
+
+ case Gdk.Key.Page_Up:
+ case Gdk.Key.KP_Page_Up:
+ if (!HeaderFocused) {
+ int relativeRow = (int)(-vadjustment.PageIncrement / (double)ChildSize.Height) * items_per_row;
+ handled = vadjustment != null && (direction == KeyDirection.Press
+ ? KeyboardScroll (press.State, relativeRow, false)
+ : UpdateSelectionForKeyboardScroll (press.State, relativeRow));
+ }
+ break;
+
+ case Gdk.Key.Page_Down:
+ case Gdk.Key.KP_Page_Down:
+ if (!HeaderFocused) {
+ int relativeRow = (int)(vadjustment.PageIncrement / (double)ChildSize.Height) * items_per_row;
+ handled = vadjustment != null && (direction == KeyDirection.Press
+ ? KeyboardScroll (press.State, relativeRow, false)
+ : UpdateSelectionForKeyboardScroll (press.State, relativeRow));
+ }
+ break;
+
+ case Gdk.Key.Home:
+ case Gdk.Key.KP_Home:
+ if (!HeaderFocused) {
+ handled = direction == KeyDirection.Press
+ ? KeyboardScroll (press.State, int.MinValue, true)
+ : UpdateSelectionForKeyboardScroll (press.State, int.MinValue);
+ }
+ break;
+
+ case Gdk.Key.End:
+ case Gdk.Key.KP_End:
+ if (!HeaderFocused) {
+ handled = direction == KeyDirection.Press
+ ? KeyboardScroll (press.State, int.MaxValue, true)
+ : UpdateSelectionForKeyboardScroll (press.State, int.MaxValue);
+ }
+ break;
}
- if (handled) {
- return true;
- }
+ return handled;
+ }
- return base.OnKeyPressEvent (press);
+ protected override bool OnKeyReleaseEvent (Gdk.EventKey press)
+ {
+ Console.WriteLine ("OnKeyRelease for {0}", press.Key);
+ return HandleKeyboardScrollKey (press, KeyDirection.Release) ? true : base.OnKeyReleaseEvent (press);
}
protected bool ActivateSelection ()
diff --git a/Hyena/Hyena.Collections/Selection.cs b/Hyena/Hyena.Collections/Selection.cs
index 39a86b1..32fb7f2 100644
--- a/Hyena/Hyena.Collections/Selection.cs
+++ b/Hyena/Hyena.Collections/Selection.cs
@@ -4,8 +4,10 @@
// Author:
// Aaron Bockover <abockover novell com>
// Gabriel Burt <gburt novell com>
+// Alex Launi <alex launi canonical com>
//
// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2010 Alex Launi
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -72,6 +74,11 @@ namespace Hyena.Collections
}
}
+ public void Notify ()
+ {
+ OnChanged ();
+ }
+
protected virtual void OnChanged ()
{
EventHandler handler = Changed;
@@ -89,12 +96,21 @@ namespace Hyena.Collections
OnChanged ();
}
- public void Select (int index)
+ public void Select (int index, bool notify)
{
ranges.Add (index);
- if (Count == 1)
+ if (Count == 1) {
first_selected_index = index;
- OnChanged ();
+ }
+
+ if (notify) {
+ OnChanged ();
+ }
+ }
+
+ public void Select (int index)
+ {
+ Select (index, true);
}
public void QuietSelect (int index)
@@ -120,20 +136,25 @@ namespace Hyena.Collections
return ranges.Contains (index);
}
- public void SelectFromFirst (int end, bool clear)
+ public void SelectFromFirst (int end, bool clear, bool notify)
{
bool contains = Contains (first_selected_index);
if (clear)
- Clear(false);
+ Clear (false);
if (contains)
- SelectRange (first_selected_index, end);
+ SelectRange (first_selected_index, end, notify);
else
- Select (end);
+ Select (end, notify);
}
- public void SelectRange (int a, int b)
+ public void SelectFromFirst (int end, bool clear)
+ {
+ SelectFromFirst (end, clear, true);
+ }
+
+ public void SelectRange (int a, int b, bool notify)
{
int start = Math.Min (a, b);
int end = Math.Max (a, b);
@@ -146,10 +167,17 @@ namespace Hyena.Collections
if (Count == i)
first_selected_index = a;
- OnChanged ();
+ if (notify) {
+ OnChanged ();
+ }
}
- public void UnselectRange (int a, int b)
+ public void SelectRange (int a, int b)
+ {
+ SelectRange (a, b, true);
+ }
+
+ public void UnselectRange (int a, int b, bool notify)
{
int start = Math.Min (a, b);
int end = Math.Max (a, b);
@@ -159,7 +187,14 @@ namespace Hyena.Collections
ranges.Remove (i);
}
- OnChanged ();
+ if (notify) {
+ OnChanged ();
+ }
+ }
+
+ public void UnselectRange (int a, int b)
+ {
+ UnselectRange (a, b, true);
}
public virtual void SelectAll ()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]