[california/wip/725786-edit-recurring: 4/4] Fleshed out the dialog, input logic in place



commit 428829c83a211a1b6bf1f0beafd88da8c7cc153a
Author: Jim Nelson <jim yorba org>
Date:   Wed Jul 9 18:33:26 2014 -0700

    Fleshed out the dialog, input logic in place
    
    Now need to fill in dialog with existing RRULE parameters and save
    RRULE parameters when OK is pressed.

 src/host/host-create-update-recurring.vala |  219 ++++++++++++++++-
 src/rc/create-update-recurring.ui          |  382 +++++++++++++++++++++++++++-
 src/toolkit/toolkit-calendar-popup.vala    |   26 ++-
 3 files changed, 606 insertions(+), 21 deletions(-)
---
diff --git a/src/host/host-create-update-recurring.vala b/src/host/host-create-update-recurring.vala
index 2993c3d..20b2a6a 100644
--- a/src/host/host-create-update-recurring.vala
+++ b/src/host/host-create-update-recurring.vala
@@ -10,18 +10,233 @@ namespace California.Host {
 public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
     public const string ID = "CreateUpdateRecurring";
     
+    private const string PROP_START_DATE = "start-date";
+    private const string PROP_END_DATE = "end-date";
+    
+    // DO NOT CHANGE UNLESS YOU KNOW WHAT YOU'RE DOING.  These values are mirrored in the Glade
+    // file's repeats_combobox model.
+    private enum Repeats {
+        DAILY = 0,
+        WEEKLY = 1,
+        DAY_OF_THE_WEEK = 2,
+        DAY_OF_THE_MONTH = 3,
+        YEARLY = 4
+    }
+    
     public string card_id { get { return ID; } }
     
     public string? title { get { return null; } }
     
-    public Gtk.Widget? default_widget { get { return null; } }
+    public Gtk.Widget? default_widget { get { return ok_button; } }
+    
+    public Gtk.Widget? initial_focus { get { return make_recurring_checkbutton; } }
+    
+    public Calendar.Date? start_date { get; private set; default = null; }
+    public Calendar.Date? end_date { get; private set; default = null; }
+    
+    [GtkChild]
+    private Gtk.CheckButton make_recurring_checkbutton;
+    
+    [GtkChild]
+    private Gtk.Grid child_grid;
+    
+    [GtkChild]
+    private Gtk.ComboBoxText repeats_combobox;
+    
+    [GtkChild]
+    private Gtk.Entry every_entry;
+    
+    [GtkChild]
+    private Gtk.Label every_label;
+    
+    [GtkChild]
+    private Gtk.Label on_days_label;
     
-    public Gtk.Widget? initial_focus { get { return null; } }
+    [GtkChild]
+    private Gtk.Box on_days_box;
+    
+    [GtkChild]
+    private Gtk.Button start_date_button;
+    
+    [GtkChild]
+    private Gtk.RadioButton never_radiobutton;
+    
+    [GtkChild]
+    private Gtk.RadioButton after_radiobutton;
+    
+    [GtkChild]
+    private Gtk.Entry after_entry;
+    
+    [GtkChild]
+    private Gtk.Label after_label;
+    
+    [GtkChild]
+    private Gtk.RadioButton ends_on_radiobutton;
+    
+    [GtkChild]
+    private Gtk.Button end_date_button;
+    
+    [GtkChild]
+    private Gtk.Button ok_button;
+    
+    private new Component.Event? event = null;
+    private bool blocking_insert_text_numbers_only_signal = false;
     
     public CreateUpdateRecurring() {
+        // "Repeating event" checkbox activates almost every other control in this dialog
+        make_recurring_checkbutton.bind_property("active", child_grid, "sensitive",
+            BindingFlags.SYNC_CREATE);
+        
+        // On Days and its checkbox are only visible when Repeats is set to Weekly
+        repeats_combobox.bind_property("active", on_days_label, "visible",
+            BindingFlags.SYNC_CREATE, transform_repeats_active_to_on_days_visible);
+        repeats_combobox.bind_property("active", on_days_box, "visible",
+            BindingFlags.SYNC_CREATE, transform_repeats_active_to_on_days_visible);
+        
+        // Ends radio buttons need to make their assoc. controls sensitive when active
+        after_radiobutton.bind_property("active", after_entry, "sensitive",
+            BindingFlags.SYNC_CREATE);
+        ends_on_radiobutton.bind_property("active", end_date_button, "sensitive",
+            BindingFlags.SYNC_CREATE);
+        
+        // use private Date properties to synchronize with date button labels
+        bind_property(PROP_START_DATE, start_date_button, "label", BindingFlags.SYNC_CREATE,
+            transform_date_to_string);
+        bind_property(PROP_END_DATE, end_date_button, "label", BindingFlags.SYNC_CREATE,
+            transform_date_to_string);
+    }
+    
+    private bool transform_repeats_active_to_on_days_visible(Binding binding, Value source_value,
+        ref Value target_value) {
+        target_value = (repeats_combobox.active == Repeats.WEEKLY);
+        
+        return true;
+    }
+    
+    private bool transform_date_to_string(Binding binding, Value source_value, ref Value target_value) {
+        Calendar.Date? date = (Calendar.Date?) source_value;
+        target_value = (date != null) ? date.to_standard_string() : "";
+        
+        return true;
     }
     
     public void jumped_to(Toolkit.Card? from, Toolkit.Card.Jump reason, Value? message) {
+        if (message != null)
+            event = (Component.Event) message;
+        
+        // *must* have an Event by this point, whether from before or due to this jump
+        assert(event != null);
+        update_controls();
+    }
+    
+    private void update_controls() {
+        make_recurring_checkbutton.active = (event.rrule != null);
+        
+        // set to defaults if not a recurring event
+        if (event.rrule == null) {
+            repeats_combobox.active = Repeats.DAILY;
+            every_entry.text = "1";
+            never_radiobutton.active = true;
+            after_entry.text = "1";
+            
+            Calendar.DateSpan event_span = event.get_event_date_span(Calendar.Timezone.local);
+            start_date = event_span.start_date;
+            end_date = event_span.end_date;
+            
+            return;
+        }
+    }
+    
+    [GtkCallback]
+    private void on_repeats_combobox_changed() {
+        on_repeats_combobox_or_every_entry_changed();
+    }
+    
+    [GtkCallback]
+    private void on_every_entry_changed() {
+        on_repeats_combobox_or_every_entry_changed();
+    }
+    
+    private void on_repeats_combobox_or_every_entry_changed() {
+        int every_count = !String.is_empty(every_entry.text) ? int.parse(every_entry.text) : 1;
+        every_count = every_count.clamp(1, int.MAX);
+        
+        unowned string text;
+        switch (repeats_combobox.active) {
+            case Repeats.DAY_OF_THE_MONTH:
+            case Repeats.DAY_OF_THE_WEEK:
+                text = ngettext("month", "months", every_count);
+            break;
+            
+            case Repeats.WEEKLY:
+                text = ngettext("week", "weeks", every_count);
+            break;
+            
+            case Repeats.YEARLY:
+                text = ngettext("year", "years", every_count);
+            break;
+            
+            case Repeats.DAILY:
+            default:
+                text = ngettext("day", "days", every_count);
+            break;
+        }
+        
+        every_label.label = text;
+    }
+    
+    [GtkCallback]
+    private void on_after_entry_changed() {
+        int after_count = !String.is_empty(after_entry.text) ? int.parse(after_entry.text) : 1;
+        after_count = after_count.clamp(1, int.MAX);
+        
+        after_label.label = ngettext("event", "events", after_count);
+    }
+    
+    [GtkCallback]
+    private void on_date_button_clicked(Gtk.Button date_button) {
+        bool is_dtstart = (date_button == start_date_button);
+        
+        Toolkit.CalendarPopup popup = new Toolkit.CalendarPopup(date_button,
+            is_dtstart ? start_date : end_date);
+        
+        popup.date_activated.connect((date) => {
+            if (is_dtstart)
+                start_date = date;
+            else
+                end_date = date;
+        });
+        
+        popup.dismissed.connect(() => {
+            popup.destroy();
+        });
+        
+        popup.show_all();
+    }
+    
+    [GtkCallback]
+    private void on_insert_text_numbers_only(Gtk.Editable editable, string new_text, int new_text_length,
+        ref int position) {
+        // prevent recursion when our modified text is inserted (i.e. allow the base handler to
+        // deal new text directly)
+        if (blocking_insert_text_numbers_only_signal)
+            return;
+        
+        // filter out everything not a number
+        string numbers_only = from_string(new_text)
+            .filter(ch => ch.isdigit())
+            .to_string(ch => ch.to_string());
+        
+        // insert new text into place, ensure this handler doesn't attempt to process this
+        // modified text
+        if (!String.is_empty(numbers_only)) {
+            blocking_insert_text_numbers_only_signal = true;
+            editable.insert_text(numbers_only, numbers_only.length, ref position);
+            blocking_insert_text_numbers_only_signal = false;
+        }
+        
+        // don't let the base handler have at the original text
+        Signal.stop_emission_by_name(editable, "insert-text");
     }
     
     [GtkCallback]
diff --git a/src/rc/create-update-recurring.ui b/src/rc/create-update-recurring.ui
index 3796e4b..eda59b6 100644
--- a/src/rc/create-update-recurring.ui
+++ b/src/rc/create-update-recurring.ui
@@ -12,7 +12,7 @@
     <property name="row_spacing">6</property>
     <child>
       <object class="GtkCheckButton" id="make_recurring_checkbutton">
-        <property name="label" translatable="yes">_Repeating event:</property>
+        <property name="label" translatable="yes">_Repeating event</property>
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <property name="receives_default">False</property>
@@ -40,7 +40,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">1</property>
-            <property name="label" translatable="yes">Re_peats:</property>
+            <property name="label" translatable="yes">Re_peats</property>
             <property name="use_underline">True</property>
             <style>
               <class name="dim-label"/>
@@ -58,7 +58,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">1</property>
-            <property name="label" translatable="yes">_Every:</property>
+            <property name="label" translatable="yes">_Every</property>
             <property name="use_underline">True</property>
             <style>
               <class name="dim-label"/>
@@ -76,7 +76,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">1</property>
-            <property name="label" translatable="yes">En_ds:</property>
+            <property name="label" translatable="yes">En_ds</property>
             <property name="use_underline">True</property>
             <style>
               <class name="dim-label"/>
@@ -94,7 +94,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">1</property>
-            <property name="label" translatable="yes">_Starts:</property>
+            <property name="label" translatable="yes">_Starts</property>
             <property name="use_underline">True</property>
             <style>
               <class name="dim-label"/>
@@ -108,11 +108,11 @@
           </packing>
         </child>
         <child>
-          <object class="GtkLabel" id="label5">
+          <object class="GtkLabel" id="on_days_label">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="xalign">1</property>
-            <property name="label" translatable="yes">_On days:</property>
+            <property name="label" translatable="yes">_On days</property>
             <property name="use_underline">True</property>
             <style>
               <class name="dim-label"/>
@@ -126,19 +126,340 @@
           </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkComboBoxText" id="repeats_combobox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <items>
+              <item id="0" translatable="yes">Daily</item>
+              <item id="1" translatable="yes">Weekly</item>
+              <item id="2" translatable="yes">Day of the week</item>
+              <item id="3" translatable="yes">Day of the month</item>
+              <item id="4" translatable="yes">Yearly</item>
+            </items>
+            <signal name="changed" handler="on_repeats_combobox_changed" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkBox" id="on_days_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">8</property>
+            <child>
+              <object class="GtkCheckButton" id="sunday_checkbutton">
+                <property name="label" translatable="yes">_Sun</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="monday_checkbutton">
+                <property name="label" translatable="yes">_Mon</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="tuesday_checkbutton">
+                <property name="label" translatable="yes">_Tues</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="wednesday_checkbutton">
+                <property name="label" translatable="yes">_Wed</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="thursday_checkbutton">
+                <property name="label" translatable="yes">T_hu</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="friday_checkbutton">
+                <property name="label" translatable="yes">_Fri</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="saturday_checkbutton">
+                <property name="label" translatable="yes">S_at</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">6</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkBox" id="box1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">16</property>
+            <child>
+              <object class="GtkRadioButton" id="never_radiobutton">
+                <property name="label" translatable="yes">_Never</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="on_box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkRadioButton" id="ends_on_radiobutton">
+                    <property name="label" translatable="yes" comments="As in, an event &quot;ends on&quot; 
a date">_On</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="xalign">0</property>
+                    <property name="draw_indicator">True</property>
+                    <property name="group">never_radiobutton</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="end_date_button">
+                    <property name="label">(none)</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <signal name="clicked" handler="on_date_button_clicked" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkRadioButton" id="after_radiobutton">
+                    <property name="label" translatable="yes">Aft_er</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="xalign">0</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                    <property name="group">never_radiobutton</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="after_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="max_length">4</property>
+                    <property name="activates_default">True</property>
+                    <property name="width_chars">5</property>
+                    <property name="input_purpose">number</property>
+                    <signal name="changed" handler="on_after_entry_changed" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+                    <signal name="insert-text" handler="on_insert_text_numbers_only" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="after_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">events</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">4</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkButton" id="start_date_button">
+            <property name="label">(none)</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="halign">start</property>
+            <signal name="clicked" handler="on_date_button_clicked" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
         <child>
-          <placeholder/>
+          <object class="GtkBox" id="every_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">4</property>
+            <child>
+              <object class="GtkEntry" id="every_entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="max_length">4</property>
+                <property name="activates_default">True</property>
+                <property name="width_chars">5</property>
+                <property name="input_purpose">number</property>
+                <signal name="changed" handler="on_every_entry_changed" 
object="CaliforniaHostCreateUpdateRecurring" swapped="no"/>
+                <signal name="insert-text" handler="on_insert_text_numbers_only" 
object="CaliforniaHostCreateUpdateRecurring" 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="every_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label">(none)</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">1</property>
+            <property name="top_attach">1</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
         </child>
       </object>
       <packing>
@@ -204,4 +525,41 @@
       </packing>
     </child>
   </template>
+  <object class="GtkBox" id="ends_on_box">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="spacing">4</property>
+    <child>
+      <object class="GtkRadioButton" id="ends_on_radiobutton1">
+        <property name="label" translatable="yes" comments="As in, an event &quot;ends on&quot; a 
date">_On</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="use_underline">True</property>
+        <property name="xalign">0</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+        <property name="group">never_radiobutton</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="end_date_button1">
+        <property name="label">(none)</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <signal name="clicked" handler="on_date_button_clicked" object="CaliforniaHostCreateUpdateRecurring" 
swapped="no"/>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+  </object>
 </interface>
diff --git a/src/toolkit/toolkit-calendar-popup.vala b/src/toolkit/toolkit-calendar-popup.vala
index 0c0633c..9bfe8a3 100644
--- a/src/toolkit/toolkit-calendar-popup.vala
+++ b/src/toolkit/toolkit-calendar-popup.vala
@@ -25,13 +25,19 @@ public class CalendarPopup : Popup {
     /**
      * Fired when the user selects a day of a month and year.
      *
-     * In current implementation the { link Popup} will be { link dismissed} with any selection.
-     * Future work may allow the user to single-click on a day but require another action to
-     * dismiss the Popup.  Best for users to subscribe to { link dismissed} as well as this signal.
+     * @see date_activated
      */
     public signal void date_selected(Calendar.Date date);
     
     /**
+     * Fired when the user activates (double-clicks) a day of a month and year.
+     *
+     * Note that a double-click will result in { link date_selected} followed by this signal
+     * followed by { link dismissed}.
+     */
+    public signal void date_activated(Calendar.Date date);
+    
+    /**
      * inheritDoc
      */
     public CalendarPopup(Gtk.Widget relative_to, Calendar.Date initial_date) {
@@ -41,16 +47,17 @@ public class CalendarPopup : Popup {
         calendar.month = initial_date.month.value - 1;
         calendar.year = initial_date.year.value;
         
-        calendar.day_selected.connect(on_day_selected);
+        calendar.day_selected.connect(() => {
+            on_day_selected(false);
+        });
         calendar.day_selected_double_click.connect(() => {
-            on_day_selected();
-            dismiss();
+            on_day_selected(true);
         });
         
         add(calendar);
     }
     
-    private void on_day_selected() {
+    private void on_day_selected(bool activated) {
         Calendar.Date date;
         try {
             date = new Calendar.Date(
@@ -65,6 +72,11 @@ public class CalendarPopup : Popup {
         }
         
         date_selected(date);
+        
+        if (activated) {
+            date_activated(date);
+            dismiss();
+        }
     }
 }
 


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