[california/wip/725764-ics] Select calendar and import .ics file into it



commit 388ad6b6d51768e502d473ba9230e3bec778a251
Author: Jim Nelson <jim yorba org>
Date:   Mon Apr 14 18:39:14 2014 -0700

    Select calendar and import .ics file into it

 src/Makefile.am                                    |    5 +-
 src/activator/activator-instance-list.vala         |    2 +-
 .../activator-google-calendar-list-pane.vala       |    4 +-
 src/application/california-application.vala        |   24 +++-
 src/backing/backing-calendar-source.vala           |    6 +
 src/backing/eds/backing-eds-calendar-source.vala   |    8 ++
 src/california-resources.xml                       |    6 +
 src/component/component-event.vala                 |   44 +++++++
 src/host/host-calendar-list-item.vala              |   47 +++++++
 src/host/host-import-calendar.vala                 |   70 +++++++++++
 src/rc/calendar-import.ui                          |  129 ++++++++++++++++++++
 src/rc/calendar-list-item.ui                       |   47 +++++++
 src/toolkit/toolkit-listbox-model.vala             |   64 +++++-----
 src/util/util-interfaces.vala                      |   24 ----
 14 files changed, 415 insertions(+), 65 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index ae21505..da81cca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,7 +80,9 @@ california_VALASOURCES = \
        component/component-vtype.vala \
        \
        host/host.vala \
+       host/host-calendar-list-item.vala \
        host/host-create-update-event.vala \
+       host/host-import-calendar.vala \
        host/host-main-window.vala \
        host/host-show-event.vala \
        \
@@ -98,7 +100,6 @@ california_VALASOURCES = \
        toolkit/toolkit-popup.vala \
        \
        util/util-gfx.vala \
-       util/util-interfaces.vala \
        util/util-memory.vala \
        util/util-string.vala \
        util/util-uri.vala \
@@ -120,6 +121,8 @@ california_SOURCES = \
 california_RC = \
        rc/activator-list.ui \
        rc/app-menu.interface \
+       rc/calendar-import.ui \
+       rc/calendar-list-item.ui \
        rc/calendar-manager-list.ui \
        rc/calendar-manager-list-item.ui \
        rc/create-update-event.ui \
diff --git a/src/activator/activator-instance-list.vala b/src/activator/activator-instance-list.vala
index e8583e1..b24736b 100644
--- a/src/activator/activator-instance-list.vala
+++ b/src/activator/activator-instance-list.vala
@@ -27,7 +27,7 @@ public class InstanceList : Gtk.Grid, Toolkit.Card {
     private Toolkit.ListBoxModel<Instance> model;
     
     public InstanceList() {
-        model = new Toolkit.ListBoxModel<Instance>(listbox, model_presentation, activator_comparator);
+        model = new Toolkit.ListBoxModel<Instance>(listbox, model_presentation, null, activator_comparator);
         model.add_many(activators);
         
         model.activated.connect(on_item_activated);
diff --git a/src/activator/google/activator-google-calendar-list-pane.vala 
b/src/activator/google/activator-google-calendar-list-pane.vala
index 31643e4..5dacd1a 100644
--- a/src/activator/google/activator-google-calendar-list-pane.vala
+++ b/src/activator/google/activator-google-calendar-list-pane.vala
@@ -55,9 +55,9 @@ public class GoogleCalendarListPane : Gtk.Grid, Toolkit.Card {
         unowned_calendars_listbox.set_placeholder(create_placeholder());
         
         own_calendars_model = new Toolkit.ListBoxModel<GData.CalendarCalendar>(own_calendars_listbox,
-            entry_to_widget, entry_comparator);
+            entry_to_widget, null, entry_comparator);
         unowned_calendars_model = new Toolkit.ListBoxModel<GData.CalendarCalendar>(unowned_calendars_listbox,
-            entry_to_widget, entry_comparator);
+            entry_to_widget, null, entry_comparator);
     }
     
     private static Gtk.Widget create_placeholder() {
diff --git a/src/application/california-application.vala b/src/application/california-application.vala
index bcf82d6..e6d3e18 100644
--- a/src/application/california-application.vala
+++ b/src/application/california-application.vala
@@ -85,10 +85,8 @@ public class Application : Gtk.Application {
         // tell the primary instance (which this instance may not be) about the command-line options
         // it should act upon
         if (Commandline.files != null) {
-            foreach (string file in Commandline.files) {
-                debug("send %s", file);
+            foreach (string file in Commandline.files)
                 activate_action(ACTION_PROCESS_FILE, file);
-            }
         }
         
         exit_status = 0;
@@ -182,7 +180,25 @@ public class Application : Gtk.Application {
             return;
         }
         
-        debug("Loaded %s", ical.to_string());
+        debug("Parsed %s", ical.to_string());
+        
+        Host.ImportCalendar importer = new Host.ImportCalendar(main_window, ical);
+        Gtk.ResponseType response_type = (Gtk.ResponseType) importer.run();
+        importer.destroy();
+        
+        if (response_type != Gtk.ResponseType.OK || importer.chosen == null)
+            return;
+        
+        importer.chosen.import_icalendar_async.begin(ical, null, on_import_completed);
+    }
+    
+    private void on_import_completed(Object? object, AsyncResult result) {
+        Backing.CalendarSource calendar_source = (Backing.CalendarSource) object;
+        try {
+            calendar_source.import_icalendar_async.end(result);
+        } catch (Error err) {
+            debug("Unable to import iCalendar: %s", err.message);
+        }
     }
     
     private void on_about() {
diff --git a/src/backing/backing-calendar-source.vala b/src/backing/backing-calendar-source.vala
index 7f97a9b..1cd6cde 100644
--- a/src/backing/backing-calendar-source.vala
+++ b/src/backing/backing-calendar-source.vala
@@ -52,6 +52,12 @@ public abstract class CalendarSource : Source {
      */
     public abstract async void remove_component_async(Component.UID uid,
         Cancellable? cancellable = null) throws Error;
+    
+    /**
+     * Imports a { link Component.iCalendar} into the { link CalendarSource}.
+     */
+    public abstract async void import_icalendar_async(Component.iCalendar ical, Cancellable? cancellable = 
null)
+        throws Error;
 }
 
 }
diff --git a/src/backing/eds/backing-eds-calendar-source.vala 
b/src/backing/eds/backing-eds-calendar-source.vala
index 35a2966..9888257 100644
--- a/src/backing/eds/backing-eds-calendar-source.vala
+++ b/src/backing/eds/backing-eds-calendar-source.vala
@@ -167,6 +167,14 @@ internal class EdsCalendarSource : CalendarSource {
         // TODO: Fix remove_object() bindings so async is possible
         client.remove_object_sync(uid.value, null, E.CalObjModType.THIS, cancellable);
     }
+    
+    public override async void import_icalendar_async(Component.iCalendar ical, Cancellable? cancellable = 
null)
+        throws Error {
+        check_open();
+        
+        // TODO: Fix receive_objects() bindings so async is possible
+        client.receive_objects_sync(ical.ical_component, cancellable);
+    }
 }
 
 }
diff --git a/src/california-resources.xml b/src/california-resources.xml
index f544e1b..03bb412 100644
--- a/src/california-resources.xml
+++ b/src/california-resources.xml
@@ -7,6 +7,12 @@
         <file compressed="true">rc/app-menu.interface</file>
     </gresource>
     <gresource prefix="/org/yorba/california">
+        <file compressed="true">rc/calendar-import.ui</file>
+    </gresource>
+    <gresource prefix="/org/yorba/california">
+        <file compressed="false">rc/calendar-list-item.ui</file>
+    </gresource>
+    <gresource prefix="/org/yorba/california">
         <file compressed="false">rc/calendar-manager-list.ui</file>
     </gresource>
     <gresource prefix="/org/yorba/california">
diff --git a/src/component/component-event.vala b/src/component/component-event.vala
index af2ce4f..08f0e69 100644
--- a/src/component/component-event.vala
+++ b/src/component/component-event.vala
@@ -18,6 +18,13 @@ public class Event : Instance, Gee.Comparable<Event> {
     public const string PROP_EXACT_TIME_SPAN = "exact-time-span";
     public const string PROP_DATE_SPAN = "date-span";
     public const string PROP_IS_ALL_DAY = "is-all-day";
+    public const string PROP_STATUS = "status";
+    
+    public enum Status {
+        TENTATIVE,
+        CONFIRMED,
+        CANCELLED
+    }
     
     /**
      * Summary (title) of { link Event}.
@@ -55,6 +62,11 @@ public class Event : Instance, Gee.Comparable<Event> {
     public bool is_all_day { get; private set; }
     
     /**
+     * Status (confirmation) of an { link Event}.
+     */
+    public Status status { get; set; default = Status.CONFIRMED; }
+    
+    /**
      * Create an { link Event} { link Component} from an EDS CalComponent object.
      *
      * Throws a BackingError if the E.CalComponent's VTYPE is not VEVENT.
@@ -105,6 +117,21 @@ public class Event : Instance, Gee.Comparable<Event> {
         
         // need to set this here because on_notify() doesn't update inside full update
         is_all_day = (date_span != null);
+        
+        switch (ical_component.get_status()) {
+            case iCal.icalproperty_status.TENTATIVE:
+                status = Status.TENTATIVE;
+            break;
+            
+            case iCal.icalproperty_status.CANCELLED:
+                status = Status.CANCELLED;
+            break;
+            
+            case iCal.icalproperty_status.CONFIRMED:
+            default:
+                status = Status.CONFIRMED;
+            break;
+        }
     }
     
     private void on_notify(ParamSpec pspec) {
@@ -148,6 +175,23 @@ public class Event : Instance, Gee.Comparable<Event> {
                 is_all_day = (date_span != null);
             break;
             
+            case PROP_STATUS:
+                switch(status) {
+                    case Status.TENTATIVE:
+                        ical_component.set_status(iCal.icalproperty_status.TENTATIVE);
+                    break;
+                    
+                    case Status.CANCELLED:
+                        ical_component.set_status(iCal.icalproperty_status.CANCELLED);
+                    break;
+                    
+                    case Status.CONFIRMED:
+                    default:
+                        ical_component.set_status(iCal.icalproperty_status.CONFIRMED);
+                    break;
+                }
+            break;
+            
             default:
                 altered = false;
             break;
diff --git a/src/host/host-calendar-list-item.vala b/src/host/host-calendar-list-item.vala
new file mode 100644
index 0000000..6e19fb4
--- /dev/null
+++ b/src/host/host-calendar-list-item.vala
@@ -0,0 +1,47 @@
+/* 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.Host {
+
+[GtkTemplate (ui = "/org/yorba/california/rc/calendar-list-item.ui")]
+public class CalendarListItem : Gtk.Grid {
+    public Backing.CalendarSource calendar_source { get; private set; }
+    
+    [GtkChild]
+    private Gtk.Image color_image;
+    
+    [GtkChild]
+    private Gtk.Label title_label;
+    
+    public CalendarListItem(Backing.CalendarSource calendar_source) {
+        this.calendar_source = calendar_source;
+        
+        set_title();
+        set_color();
+        
+        calendar_source.notify[Backing.Source.PROP_TITLE].connect(set_title);
+        calendar_source.notify[Backing.Source.PROP_COLOR].connect(set_color);
+    }
+    
+    ~CalendarListItem() {
+        calendar_source.notify[Backing.Source.PROP_TITLE].disconnect(set_title);
+        calendar_source.notify[Backing.Source.PROP_COLOR].disconnect(set_color);
+    }
+    
+    private void set_title() {
+        title_label.label = calendar_source.title;
+    }
+    
+    private void set_color() {
+        Gdk.Pixbuf pixbuf = new Gdk.Pixbuf(Gdk.Colorspace.RGB, false, 8, color_image.width_request,
+            color_image.height_request);
+        pixbuf.fill(Gfx.rgba_to_pixel(calendar_source.color_as_rgba()));
+        color_image.set_from_pixbuf(pixbuf);
+    }
+}
+
+}
+
diff --git a/src/host/host-import-calendar.vala b/src/host/host-import-calendar.vala
new file mode 100644
index 0000000..5c58bac
--- /dev/null
+++ b/src/host/host-import-calendar.vala
@@ -0,0 +1,70 @@
+/* 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.Host {
+
+[GtkTemplate (ui = "/org/yorba/california/rc/calendar-import.ui")]
+public class ImportCalendar : Gtk.Dialog {
+    public Component.iCalendar ical { get; private set;}
+    
+    public Backing.CalendarSource? chosen { get; private set; default = null; }
+    
+    [GtkChild]
+    private Gtk.Label title_label;
+    
+    [GtkChild]
+    private Gtk.ListBox calendar_listbox;
+    
+    [GtkChild]
+    private Gtk.Button import_button;
+    
+    private Toolkit.ListBoxModel<Backing.CalendarSource> model;
+    
+    public ImportCalendar(Gtk.Window parent, Component.iCalendar ical) {
+        this.ical = ical;
+        
+        transient_for = parent;
+        modal = true;
+        resizable = false;
+        
+        title_label.label = ngettext("Select calendar to import event into:",
+            "Select calendar to import events into:", ical.events.size);
+        
+        model = new Toolkit.ListBoxModel<Backing.CalendarSource>(calendar_listbox, model_presentation,
+            model_filter);
+        model.add_many(Backing.Manager.instance.get_sources_of_type<Backing.CalendarSource>());
+        
+        on_row_selected();
+        calendar_listbox.row_selected.connect(on_row_selected);
+    }
+    
+    private Gtk.Widget model_presentation(Backing.CalendarSource calendar_source) {
+        return new CalendarListItem(calendar_source);
+    }
+    
+    private bool model_filter(Backing.CalendarSource calendar_source) {
+        return calendar_source.visible;
+    }
+    
+    private void on_row_selected() {
+        import_button.sensitive = (calendar_listbox.get_selected_row() != null);
+    }
+    
+    [GtkCallback]
+    private void on_cancel_button_clicked() {
+        response(Gtk.ResponseType.CANCEL);
+    }
+    
+    [GtkCallback]
+    private void on_import_button_clicked() {
+        chosen = model.selected;
+        
+        response(Gtk.ResponseType.OK);
+    }
+}
+
+}
+
diff --git a/src/rc/calendar-import.ui b/src/rc/calendar-import.ui
new file mode 100644
index 0000000..7e7bb60
--- /dev/null
+++ b/src/rc/calendar-import.ui
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="CaliforniaHostImportCalendar" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="valign">center</property>
+            <property name="homogeneous">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel_button">
+                <property name="label" translatable="yes">_Cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+                <signal name="clicked" handler="on_cancel_button_clicked" 
object="CaliforniaHostImportCalendar" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="import_button">
+                <property name="label" translatable="yes">_Import</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+                <signal name="clicked" handler="on_import_button_clicked" 
object="CaliforniaHostImportCalendar" swapped="no"/>
+                <style>
+                  <class name="suggested-action"/>
+                </style>
+              </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">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">8</property>
+            <property name="margin_right">8</property>
+            <property name="margin_top">8</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="row_spacing">8</property>
+            <child>
+              <object class="GtkLabel" id="title_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label">(label)</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="shadow_type">in</property>
+                <property name="min_content_width">200</property>
+                <property name="min_content_height">300</property>
+                <child>
+                  <object class="GtkViewport" id="viewport1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkListBox" id="calendar_listbox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="activate_on_single_click">False</property>
+                      </object>
+                    </child>
+                  </object>
+                </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>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/rc/calendar-list-item.ui b/src/rc/calendar-list-item.ui
new file mode 100644
index 0000000..7009559
--- /dev/null
+++ b/src/rc/calendar-list-item.ui
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="CaliforniaHostCalendarListItem" parent="GtkGrid">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="margin_left">4</property>
+    <property name="margin_right">4</property>
+    <property name="margin_top">4</property>
+    <property name="margin_bottom">4</property>
+    <property name="column_spacing">8</property>
+    <child>
+      <object class="GtkLabel" id="title_label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label">(dummy title)</property>
+      </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>
+      <object class="GtkImage" id="color_image">
+        <property name="width_request">20</property>
+        <property name="height_request">20</property>
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="valign">center</property>
+        <property name="xalign">0</property>
+        <property name="yalign">0</property>
+        <property name="stock">gtk-missing-image</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/src/toolkit/toolkit-listbox-model.vala b/src/toolkit/toolkit-listbox-model.vala
index ebbd947..d20b28f 100644
--- a/src/toolkit/toolkit-listbox-model.vala
+++ b/src/toolkit/toolkit-listbox-model.vala
@@ -11,9 +11,6 @@ namespace California.Toolkit {
  *
  * 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 {
@@ -26,6 +23,11 @@ public class ListBoxModel<G> : BaseObject {
      */
     public delegate Gtk.Widget ModelPresentation<G>(G item);
     
+    /**
+     * Returns true if the item should be considered "visible" by the Gtk.ListBox.
+     */
+    public delegate bool ModelFilter<G>(G item);
+    
     public Gtk.ListBox listbox { get; private set; }
     
     /**
@@ -39,6 +41,7 @@ public class ListBoxModel<G> : BaseObject {
     public G? selected { get; private set; default = null; }
     
     private unowned ModelPresentation model_presentation;
+    private unowned ModelFilter? model_filter;
     private unowned CompareDataFunc<G>? comparator;
     private Gee.HashMap<G, Gtk.ListBoxRow> items;
     
@@ -70,37 +73,32 @@ public class ListBoxModel<G> : BaseObject {
      * 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) {
+        ModelFilter<G>? model_filter = null, CompareDataFunc<G>? comparator = null,
+        owned Gee.HashDataFunc<G>? hash_func = null, owned Gee.EqualDataFunc<G>? equal_func = null) {
         this.listbox = listbox;
         this.model_presentation = model_presentation;
+        this.model_filter = model_filter;
         this.comparator = comparator;
         
         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);
+        if (model_filter != null)
+            listbox.set_filter_func(listbox_filter_func);
         listbox.row_activated.connect(on_row_activated);
         listbox.row_selected.connect(on_row_selected);
     }
     
     ~ListBoxModel() {
+        listbox.remove.disconnect(on_listbox_removed);
         listbox.row_activated.disconnect(on_row_activated);
         listbox.row_selected.disconnect(on_row_selected);
-        
-        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
@@ -109,10 +107,6 @@ public class ListBoxModel<G> : BaseObject {
         if (items.has_key(item))
             return false;
         
-        Mutable? mutable = item as Mutable;
-        if (mutable != null)
-            mutable.mutated.connect(on_mutated);
-        
         // item -> Gtk.ListBoxRow
         Gtk.ListBoxRow row = new Gtk.ListBoxRow();
         row.add(model_presentation(item));
@@ -179,10 +173,6 @@ public class ListBoxModel<G> : BaseObject {
         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);
         
@@ -199,6 +189,21 @@ public class ListBoxModel<G> : BaseObject {
     }
     
     /**
+     * Call to indicate that the contents of the item has mutated, i.e. changed or been altered,
+     * in such a way to affect sorting or filtering.
+     */
+    public void mutated(G item) {
+        Gtk.ListBoxRow? row = items.get(item);
+        if (row == null) {
+            message("Mutable not found in ListBoxRow");
+            
+            return;
+        }
+        
+        row.changed();
+    }
+    
+    /**
      * Clears all items from the { link ListBoxModel}.
      *
      * Each removed item generates a { link removed} signal.
@@ -231,6 +236,10 @@ public class ListBoxModel<G> : BaseObject {
         return Gee.Functions.get_compare_func_for(typeof(G))(item_a, item_b);
     }
     
+    private bool listbox_filter_func(Gtk.ListBoxRow row) {
+        return model_filter(row.get_data<G>(KEY));
+    }
+    
     private void on_row_activated(Gtk.ListBoxRow row) {
         activated(row.get_data<G>(KEY));
     }
@@ -239,17 +248,6 @@ public class ListBoxModel<G> : BaseObject {
         selected = (row != null) ? row.get_data<G>(KEY) : null;
     }
     
-    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() {
         return "ListboxModel";
     }


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