[california/wip/725763-google] Updated documentation, small fixes in new classes
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725763-google] Updated documentation, small fixes in new classes
- Date: Fri, 4 Apr 2014 00:08:29 +0000 (UTC)
commit 635b807b8c15b6e16e3c3fb973309b1da0e5ba98
Author: Jim Nelson <jim yorba org>
Date: Thu Apr 3 14:24:51 2014 -0700
Updated documentation, small fixes in new classes
src/util/util-deck.vala | 110 +++++++++++++++++++++++++-
src/util/util-listbox-model.vala | 159 ++++++++++++++++++++++++++++++++++----
2 files changed, 251 insertions(+), 18 deletions(-)
---
diff --git a/src/util/util-deck.vala b/src/util/util-deck.vala
index 2cd2693..bf1f587 100644
--- a/src/util/util-deck.vala
+++ b/src/util/util-deck.vala
@@ -6,24 +6,98 @@
namespace California {
+/**
+ * A Card is a single pane of widget(s) in a { link Deck}.
+ *
+ * The navigation of Cards is tracked within their Deck, and Cards can request navigation via their
+ * various signals. They're also notified when nevigation which affects them is made.
+ */
+
public interface Card : Gtk.Widget {
+ /**
+ * Each { link Card} has its own identifier that should be unique within the { link Deck}.
+ *
+ * In the Gtk.Stack, this is its name.
+ */
public abstract string card_id { get; }
+ /**
+ * A user-visible string that may be used elsewhere in the application.
+ *
+ * Gtk.StackSwitcher uses this title. { link Deck} does not use the title in any way.
+ */
public abstract string? title { get; }
+ /**
+ * Fired when the { link Card} wishes to jump to another Card in the same { link Deck.}
+ *
+ * Each Card can accept a message which parameterizes its activation. It's up to Cards
+ * navigating to the new one to construct and pass an appropriate message.
+ *
+ * @see jump_to_card_by_name
+ */
public signal void jump_to_card(Card next, Value? message);
+ /**
+ * Fired when the { link Card} wishes to jump to another Card by its name.
+ *
+ * @see jump_to_card
+ */
public signal void jump_to_card_by_name(string name, Value? message);
+ /**
+ * Fired when the { link Card} wishes to jump to the previous Card in the { link Deck}.
+ *
+ * Note that this Card's position in the navigation stack is lost; there is no "jump forward".
+ */
public signal void jump_back();
+ /**
+ * Fired when the { link Card} wishes to jump to the first Card in the { link Deck}.
+ *
+ * This clears the Deck's navigation stack, meaning { link jump_back} will not return to
+ * this Card.
+ */
+ public signal void jump_home();
+
+ /**
+ * Fired when the { link Deck}'s work is cancelled, closed, or dismissed, whether due to
+ * programmatic reasons or by user request.
+ *
+ * Implementing classes should fire this after firing the { link completed signal} so
+ * subscribers can maintain their cleanup in a single handler.
+ */
public signal void dismissed(bool user_request);
+ /**
+ * Fired when the { link Deck}'s work has completed successfully.
+ *
+ * This should only be fired if the Deck requires valid input from the user to perform
+ * some intensive operation. Merely displaying information and closing the Deck
+ * should simply fire { link dismissed}.
+ *
+ * "completed" implies that dismissed will be called shortly thereafter, meaning all
+ * cleanup can be handled there.
+ */
public signal void completed();
+ /**
+ * Called by { link Deck} when the { link Card} has been activated, i.e. put to the "top" of
+ * the Deck.
+ *
+ * message may be null even if the Card expects one; generally this means { link jump_back}
+ * or { link jump_home} was invoked, resulting in this Card being activated.
+ */
public abstract void jumped_to(Card from, Value? message);
}
+/**
+ * A Deck is a collection of { link Card}s maintained within a Gtk.Stack.
+ *
+ * Cards control navigation through their various signals, which Deck monitors and acts upon.
+ * It also notifies Cards of nagivation changes which affect them via their abstract methods.
+ */
+
public class Deck : Gtk.Stack, Host.Interaction {
/**
* @inheritedDoc
@@ -33,9 +107,17 @@ public class Deck : Gtk.Stack, Host.Interaction {
public int size { get { return names.size; } }
private Card? top = null;
+ private Card? home = null;
private Gee.Deque<Card> navigation_stack = new Gee.LinkedList<Card>();
private Gee.HashMap<string, Card> names = new Gee.HashMap<string, Card>();
+ /**
+ * Create a new { link Deck}.
+ *
+ * By default the Deck configures the underlying Gtk.Stack to slide left and right, depending
+ * on the position of the { link Card}s. This can be changed, but the recommended
+ * transition types are SLIDE_LEFT_RIGHT and SLIDE_UP_DOWN.
+ */
public Deck() {
transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
notify["visible-child"].connect(on_child_to_top);
@@ -47,6 +129,7 @@ public class Deck : Gtk.Stack, Host.Interaction {
top.jump_to_card.disconnect(on_jump_to_card);
top.jump_to_card_by_name.disconnect(on_jump_to_card_by_name);
top.jump_back.disconnect(on_jump_back);
+ top.jump_home.disconnect(on_jump_home);
top.dismissed.disconnect(on_dismissed);
top.completed.disconnect(on_completed);
@@ -60,16 +143,26 @@ public class Deck : Gtk.Stack, Host.Interaction {
top.jump_to_card.connect(on_jump_to_card);
top.jump_to_card_by_name.connect(on_jump_to_card_by_name);
top.jump_back.connect(on_jump_back);
+ top.jump_home.connect(on_jump_home);
top.dismissed.connect(on_dismissed);
top.completed.connect(on_completed);
}
}
+ /**
+ * Add { link Card}s to the { link Deck}.
+ *
+ * Cards can be added in multiple batches, but the ordering is important as it dictates how
+ * they're presented to the user via transitions and slides.
+ *
+ * The first Card added is the "home" Card. The Deck will automatically show it first.
+ */
public void add_cards(Gee.List<Card> cards) {
if (cards.size == 0)
return;
- bool set_first_visible = size == 0;
+ // if empty, first card is home and should be made visible when added
+ bool set_home_visible = size == 0;
// add each Card using the title if possible, otherwise by ID
foreach (Card card in cards) {
@@ -83,10 +176,14 @@ public class Deck : Gtk.Stack, Host.Interaction {
add_titled(card, card.card_id, card.title);
names.set(card.card_id, card);
+
+ // first Card seen is home card
+ if (home == null)
+ home = card;
}
- if (set_first_visible)
- set_visible_child(cards[0]);
+ if (set_home_visible)
+ set_visible_child(home);
}
private void on_jump_to_card(Card card, Card next, Value? message) {
@@ -119,6 +216,13 @@ public class Deck : Gtk.Stack, Host.Interaction {
on_jump_to_card(card, navigation_stack.poll_head(), null);
}
+ private void on_jump_home(Card card) {
+ // jumping home clears the navigation stack
+ navigation_stack.clear();
+
+ on_jump_to_card(card, home, null);
+ }
+
private void on_dismissed(bool user_request) {
dismissed(user_request);
}
diff --git a/src/util/util-listbox-model.vala b/src/util/util-listbox-model.vala
index 370c9d9..090d336 100644
--- a/src/util/util-listbox-model.vala
+++ b/src/util/util-listbox-model.vala
@@ -6,31 +6,86 @@
namespace California {
+/**
+ * A { link Mutable} is an Object which can internally change state (i.e. is no immutable).
+ *
+ * { link ListBoxModel} recognizes when an Object supports this interface and will monitor its
+ * { link mutated} signal.
+ */
+
public interface Mutable : Object {
+ /**
+ * Fired when important internal state has changed.
+ *
+ * This can be used by collections and other containers to update their own state, such as
+ * re-sorting or re-applying filters.
+ */
public signal void mutated();
}
+/**
+ * A simple model for Gtk.ListBox.
+ *
+ * ListBoxModel is designed to make it easier to maintain a sorted list of objects and make sure
+ * the associated Gtk.ListBox is always up-to-date reflecting the state of the model.
+ *
+ * If the added objects implement the { link Mutable} interface, their { link Mutable.mutated}
+ * signsl is monitored. When fired, the listbox's sort and filters will be invalidated.
+ */
+
public class ListBoxModel<G> : BaseObject {
public const string PROP_SELECTED = "selected";
private const string KEY = "org.yorba.california.listbox-model.model";
+ /**
+ * Returns a Gtk.Widget that is held by the Gtk.ListBox representing the particular item.
+ */
public delegate Gtk.Widget ModelPresentation<G>(G item);
public Gtk.ListBox listbox { get; private set; }
+ /**
+ * The number if items in the { link ListBoxModel}.
+ */
public int size { get { return items.size; } }
+ /**
+ * The item currently selected by the { link listbox}, null if no selection has been made.
+ */
public G? selected { get; private set; default = null; }
private unowned ModelPresentation model_presentation;
private unowned CompareDataFunc<G>? comparator;
- private Gee.HashSet<G> items;
+ private Gee.HashMap<G, Gtk.ListBoxRow> items;
+ /**
+ * Fired when an item is added to the { link ListBoxModel}.
+ *
+ * @see add
+ */
public signal void added(G item);
+ /**
+ * Fired when an item is removed from the { link ListBoxModel}.
+ *
+ * @see remove
+ */
+ public signal void removed(G item);
+
+ /**
+ * Fired when the { link listbox} activates an item.
+ *
+ * Gtk.ListBox can activate an item with a double- or single-click, depending on configuration.
+ */
public signal void activated(G item);
+ /**
+ * Create a { link ListBoxModel} and tie it to a Gtk.ListBox.
+ *
+ * The list will be sorted if a comparator is supplied, otherwise added items are appended to
+ * the list.
+ */
public ListBoxModel(Gtk.ListBox listbox, ModelPresentation<G> model_presentation,
CompareDataFunc<G>? comparator = null, owned Gee.HashDataFunc<G>? hash_func = null,
owned Gee.EqualDataFunc<G>? equal_func = null) {
@@ -38,8 +93,9 @@ public class ListBoxModel<G> : BaseObject {
this.model_presentation = model_presentation;
this.comparator = comparator;
- items = new Gee.HashSet<G>((owned) hash_func, (owned) equal_func);
+ items = new Gee.HashMap<G, Gtk.ListBoxRow>((owned) hash_func, (owned) equal_func);
+ listbox.remove.connect(on_listbox_removed);
listbox.set_sort_func(listbox_sort_func);
listbox.row_activated.connect(on_row_activated);
listbox.row_selected.connect(on_row_selected);
@@ -49,42 +105,108 @@ public class ListBoxModel<G> : BaseObject {
listbox.row_activated.disconnect(on_row_activated);
listbox.row_selected.disconnect(on_row_selected);
- foreach (G item in items) {
+ foreach (G item in items.keys) {
Mutable? mutable = item as Mutable;
if (mutable != null)
mutable.mutated.disconnect(on_mutated);
}
}
+ /**
+ * Add an item to the model, which in turns adds it to the { link listbox}.
+ *
+ * If the item implements the { link Mutable} interface, its { link Mutable.mutated} signal
+ * is monitored and will invalidate the listbox's sort and filters.
+ *
+ * Returns true if the model (and therefore the listbox) were altered due to the addition.
+ *
+ * @see added
+ */
public bool add(G item) {
- if (!items.add(item))
+ if (items.has_key(item))
return false;
Mutable? mutable = item as Mutable;
if (mutable != null)
mutable.mutated.connect(on_mutated);
- Gtk.Widget widget = model_presentation(item);
- widget.set_data<G>(KEY, item);
+ // item -> Gtk.ListBoxRow
+ Gtk.ListBoxRow row = new Gtk.ListBoxRow();
+ row.add(model_presentation(item));
- listbox.add(widget);
- widget.show_all();
+ // mappings
+ row.set_data<G>(KEY, item);
+ items.set(item, row);
+
+ listbox.add(row);
+ row.show_all();
added(item);
return true;
}
+ /**
+ * Removes an item from the model, which in turn removes it from the { link listbox}.
+ *
+ * Returns true if the model (and therefore the listbox) were altered due to the removal.
+ *
+ * @see removed
+ */
+ public bool remove(G item) {
+ return internal_remove(item, true);
+ }
+
+ private bool internal_remove(G item, bool remove_from_listbox) {
+ Gtk.ListBoxRow row;
+ if (!items.unset(item, out row))
+ return false;
+
+ Mutable? mutable = item as Mutable;
+ if (mutable != null)
+ mutable.mutated.disconnect(on_mutated);
+
+ if (remove_from_listbox)
+ listbox.remove(row);
+
+ removed(item);
+
+ return true;
+ }
+
+ /**
+ * Returns true if the model holds the item.
+ */
public bool contains(G item) {
- return items.contains(item);
+ return items.has_key(item);
}
+ /**
+ * Clears all items from the { link ListBoxModel}.
+ *
+ * Each removed item generates a { link removed} signal.
+ */
public void clear() {
+ foreach (G item in items.keys)
+ remove(item);
+ }
+
+ // This can be called by our add() method or externally, so don't be too absolutist here
+ private void on_listbox_removed(Gtk.Widget widget) {
+ // get the actual widget, not the wrapping object
+ Gtk.ListBoxRow? row = widget as Gtk.ListBoxRow;
+ if (row == null) {
+ message("GtkListBox removed non-GtkListBoxRow child");
+
+ return;
+ }
+
+ internal_remove(row.get_data<G>(KEY), false);
}
private int listbox_sort_func(Gtk.ListBoxRow a, Gtk.ListBoxRow b) {
- unowned G item_a = a.get_child().get_data<G>(KEY);
- unowned G item_b = b.get_child().get_data<G>(KEY);
+ unowned G item_a = a.get_data<G>(KEY);
+ unowned G item_b = b.get_data<G>(KEY);
if (comparator != null)
return comparator(item_a, item_b);
@@ -93,15 +215,22 @@ public class ListBoxModel<G> : BaseObject {
}
private void on_row_activated(Gtk.ListBoxRow row) {
- activated(row.get_child().get_data<G>(KEY));
+ activated(row.get_data<G>(KEY));
}
private void on_row_selected(Gtk.ListBoxRow? row) {
- selected = (row != null) ? row.get_child().get_data<G>(KEY) : null;
+ selected = (row != null) ? row.get_data<G>(KEY) : null;
}
- private void on_mutated() {
- listbox.invalidate_sort();
+ private void on_mutated(Mutable mutable) {
+ Gtk.ListBoxRow? row = items.get((G) mutable);
+ if (row == null) {
+ message("Mutable not found in ListBoxRow");
+
+ return;
+ }
+
+ row.changed();
}
public override string to_string() {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]