[california/wip/725792-quick-add] Add Calendar selection to Quick Add dialog



commit c7cb79288efa42b4efc45d46b03b08264ee7cb18
Author: Jim Nelson <jim yorba org>
Date:   Mon Apr 21 19:18:22 2014 -0700

    Add Calendar selection to Quick Add dialog

 src/Makefile.am                               |    1 +
 src/host/host-quick-create-event.vala         |   17 +++
 src/rc/quick-create-event.ui                  |  105 ++++++++++++----
 src/toolkit/toolkit-combo-box-text-model.vala |  166 +++++++++++++++++++++++++
 4 files changed, 262 insertions(+), 27 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 868360f..65d5e0e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -101,6 +101,7 @@ california_VALASOURCES = \
        toolkit/toolkit.vala \
        toolkit/toolkit-calendar-popup.vala \
        toolkit/toolkit-card.vala \
+       toolkit/toolkit-combo-box-text-model.vala \
        toolkit/toolkit-deck.vala \
        toolkit/toolkit-deck-window.vala \
        toolkit/toolkit-listbox-model.vala \
diff --git a/src/host/host-quick-create-event.vala b/src/host/host-quick-create-event.vala
index af70b6e..418c677 100644
--- a/src/host/host-quick-create-event.vala
+++ b/src/host/host-quick-create-event.vala
@@ -22,9 +22,26 @@ public class QuickCreateEvent : Gtk.Grid, Toolkit.Card {
     private Gtk.Entry details_entry;
     
     [GtkChild]
+    private Gtk.ComboBoxText calendar_combo_box;
+    
+    [GtkChild]
     private Gtk.Button create_button;
     
+    private Toolkit.ComboBoxTextModel<Backing.CalendarSource> model;
+    
     public QuickCreateEvent() {
+        // create and initialize combo box model
+        model = new Toolkit.ComboBoxTextModel<Backing.CalendarSource>(calendar_combo_box,
+            (cal) => cal.title);
+        foreach (Backing.CalendarSource calendar_source in
+            Backing.Manager.instance.get_sources_of_type<Backing.CalendarSource>()) {
+            if (calendar_source.visible)
+                model.add(calendar_source);
+        }
+        
+        // make first item active
+        calendar_combo_box.active = 0;
+        
         Properties.value_to_bool(details_entry, "text-length", create_button, "sensitive",
             BindingFlags.SYNC_CREATE, () => !String.is_empty(details_entry.text));
     }
diff --git a/src/rc/quick-create-event.ui b/src/rc/quick-create-event.ui
index 3dd2983..431e8a8 100644
--- a/src/rc/quick-create-event.ui
+++ b/src/rc/quick-create-event.ui
@@ -11,7 +11,9 @@
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">Quick add event:</property>
+        <property name="label" translatable="yes">_Quick add event:</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">details_entry</property>
         <attributes>
           <attribute name="weight" value="bold"/>
         </attributes>
@@ -24,25 +26,6 @@
       </packing>
     </child>
     <child>
-      <object class="GtkEntry" id="details_entry">
-        <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="has_focus">True</property>
-        <property name="is_focus">True</property>
-        <property name="hexpand">True</property>
-        <property name="activates_default">True</property>
-        <property name="width_chars">40</property>
-        <property name="secondary_icon_name">edit-delete-symbolic</property>
-        <signal name="icon-release" handler="on_details_entry_icon_release" 
object="CaliforniaHostQuickCreateEvent" swapped="no"/>
-      </object>
-      <packing>
-        <property name="left_attach">0</property>
-        <property name="top_attach">1</property>
-        <property name="width">1</property>
-        <property name="height">1</property>
-      </packing>
-    </child>
-    <child>
       <object class="GtkButtonBox" id="buttonbox1">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
@@ -52,7 +35,7 @@
         <property name="layout_style">end</property>
         <child>
           <object class="GtkButton" id="cancel_button">
-            <property name="label" translatable="yes">_Cancel</property>
+            <property name="label" translatable="yes">C_ancel</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">True</property>
@@ -94,14 +77,82 @@
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="example_label">
+      <object class="GtkBox" id="box1">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="xalign">0</property>
-        <property name="label" translatable="yes">Example: Dinner at Tadich Grill 7:30pm tomorrow</property>
-        <attributes>
-          <attribute name="style" value="italic"/>
-        </attributes>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkEntry" id="details_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+            <property name="width_chars">40</property>
+            <property name="secondary_icon_name">edit-delete-symbolic</property>
+            <signal name="icon-release" handler="on_details_entry_icon_release" 
object="CaliforniaHostQuickCreateEvent" swapped="no"/>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="example_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Example: Dinner at Tadich Grill 
7:30pm tomorrow&lt;/i&gt;&lt;/small&gt;</property>
+            <property name="use_markup">True</property>
+            <property name="ellipsize">start</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="box2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">8</property>
+        <child>
+          <object class="GtkLabel" id="calendar_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Ca_lendar:</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">calendar_combo_box</property>
+            <property name="ellipsize">start</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBoxText" id="calendar_combo_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
       </object>
       <packing>
         <property name="left_attach">0</property>
diff --git a/src/toolkit/toolkit-combo-box-text-model.vala b/src/toolkit/toolkit-combo-box-text-model.vala
new file mode 100644
index 0000000..7bd613d
--- /dev/null
+++ b/src/toolkit/toolkit-combo-box-text-model.vala
@@ -0,0 +1,166 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Toolkit {
+
+/**
+ * A simple model for a Gtk.ComboBoxText.
+ */
+
+public class ComboBoxTextModel<G> : BaseObject {
+    public const string PROP_ACTIVE = "active";
+    
+    /**
+     * Returns a string that is the representation of the item in the Gtk.ComboBoxText.
+     */
+    public delegate string ModelPresentation<G>(G item);
+    
+    public Gtk.ComboBoxText combo_box { get; private set; }
+    
+    /**
+     * Synchronized to the active property of { link combo_box}.
+     */
+    public G? active { get; private set; }
+    
+    private unowned ModelPresentation<G> model_presentation;
+    private unowned CompareDataFunc<G>? comparator;
+    private unowned Gee.HashDataFunc<G> hash_func;
+    private unowned Gee.EqualDataFunc<G>? equal_func;
+    private Gee.ArrayList<G> items;
+    private Gee.HashMap<G, int> indices;
+    
+    public ComboBoxTextModel(Gtk.ComboBoxText combo_box, ModelPresentation<G> model_presentation,
+        CompareDataFunc<G>? comparator = null, Gee.HashDataFunc<G>? hash_func = null,
+        Gee.EqualDataFunc<G>? equal_func = null) {
+        this.combo_box = combo_box;
+        this.model_presentation = model_presentation;
+        this.comparator = comparator;
+        this.hash_func = hash_func;
+        this.equal_func = equal_func;
+        
+        items = new Gee.ArrayList<G>(item_equal_func);
+        indices = new Gee.HashMap<G, int>(item_hash_func, item_equal_func);
+        
+        combo_box.notify["active"].connect(on_combo_box_active);
+    }
+    
+    ~ComboBoxTextModel() {
+        combo_box.notify["active"].disconnect(on_combo_box_active);
+    }
+    
+    private int item_comparator(G a, G b) {
+        if (comparator != null)
+            return comparator(a, b);
+        
+        return Gee.Functions.get_compare_func_for(typeof(G))(a, b);
+    }
+    
+    private bool item_equal_func(G a, G b) {
+        if (equal_func != null)
+            return equal_func(a, b);
+        
+        return Gee.Functions.get_equal_func_for(typeof(G))(a, b);
+    }
+    
+    private uint item_hash_func(G item) {
+        if (hash_func != null)
+            return hash_func(item);
+        
+        return Gee.Functions.get_hash_func_for(typeof(G))(item);
+    }
+    
+    /**
+     * Add an item to the model and the Gtk.ComboBoxText.
+     *
+     * Returns false if the item was not added (already present in model).
+     */
+    public bool add(G item) {
+        if (!items.add(item))
+            return false;
+        
+        // sort item according to comparator and determine its index
+        items.sort(item_comparator);
+        int added_index = items.index_of(item);
+        
+        // any existing indices need to be incremented
+        foreach (G key in indices.keys) {
+            int existing_index = indices.get(key);
+            if (existing_index >= added_index)
+                indices.set(key, existing_index + 1);
+        }
+        
+        // add new item to index map
+        indices.set(item, added_index);
+        
+        combo_box.insert_text(added_index, model_presentation(item));
+        
+        return true;
+    }
+    
+    /**
+     * Removes the item from the model and the Gtk.ComboBoxText.
+     *
+     * Returns false if not removed (not present in model).
+     */
+    public bool remove(G item) {
+        if (!items.remove(item))
+            return false;
+        
+        int removed_index;
+        if (!indices.unset(item, out removed_index))
+            return false;
+        
+        foreach (G key in indices.keys) {
+            int existing_index = indices.get(key);
+            assert(existing_index != removed_index);
+            
+            if (existing_index > removed_index)
+                indices.set(key, existing_index - 1);
+        }
+        
+        combo_box.remove(removed_index);
+        
+        return true;
+    }
+    
+    /**
+     * Makes the item active in the Gtk.ComboBoxText.
+     *
+     * Returns true if the item is present in the model, whether or not it's already active.
+     */
+    public bool set_item_active(G item) {
+        if (!indices.has_key(item))
+            return false;
+        
+        combo_box.active = indices.get(item);
+        
+        return true;
+    }
+    
+    /**
+     * Returns the item at the Gtk.ComboBoxText index.
+     */
+    public G? get_item_at(int index) {
+        Gee.MapIterator<G, int> iter = indices.map_iterator();
+        while (iter.next()) {
+            if (iter.get_value() == index)
+                return iter.get_key();
+        }
+        
+        return null;
+    }
+    
+    private void on_combo_box_active() {
+        active = get_item_at(combo_box.active);
+    }
+    
+    public override string to_string() {
+        return "ComboBoxTextModel (%d items)".printf(items.size);
+    }
+}
+
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]