[california/wip/740088-invite] Organizer can now be added/edited, UI tweaks
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/740088-invite] Organizer can now be added/edited, UI tweaks
- Date: Thu, 20 Nov 2014 03:31:50 +0000 (UTC)
commit a0e7670e11ca9d40ba64ae2d9609f103ee21965a
Author: Jim Nelson <jim yorba org>
Date: Wed Nov 19 16:27:00 2014 -0800
Organizer can now be added/edited, UI tweaks
src/backing/backing-source.vala | 12 ++
src/component/component-instance.vala | 22 ++++
src/host/host-attendees-editor.vala | 63 ++++++++++--
src/host/host-create-update-event.vala | 54 ++++++++--
src/host/host-show-event.vala | 11 +--
src/rc/attendees-editor.ui | 175 ++++++++++++++++++++++----------
src/rc/create-update-event.ui | 43 +++++++--
src/toolkit/toolkit-listbox-model.vala | 11 ++-
vapi/libecal-1.2.vapi | 6 +-
9 files changed, 302 insertions(+), 95 deletions(-)
---
diff --git a/src/backing/backing-source.vala b/src/backing/backing-source.vala
index 26a889f..286e848 100644
--- a/src/backing/backing-source.vala
+++ b/src/backing/backing-source.vala
@@ -22,6 +22,8 @@ public abstract class Source : BaseObject, Gee.Comparable<Source> {
public const string PROP_VISIBLE = "visible";
public const string PROP_READONLY = "read-only";
public const string PROP_COLOR = "color";
+ public const string PROP_MAILBOX_NAME = "mailbox-name";
+ public const string PROP_MAILBOX = "mailbox";
/**
* A unique identifier for the { link Source}.
@@ -96,6 +98,16 @@ public abstract class Source : BaseObject, Gee.Comparable<Source> {
*/
public string color { get; set; }
+ /**
+ * The user name associated with the { link mailbox}.
+ */
+ public string mailbox_name { get; protected set; default = null; }
+
+ /**
+ * The mailbox (email address) associated with this { link Source}.
+ */
+ public string? mailbox { get; protected set; default = null; }
+
protected Source(Store store, string id, string title) {
this.store = store;
this.id = id;
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index 1334ddc..45f8ee4 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -562,6 +562,28 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
}
/**
+ * Export this { link Instance} as an iCalendar.
+ *
+ * @see export_master
+ * @see is_generated_instance
+ */
+ public iCalendar export(iCal.icalproperty_method method) {
+ return new iCalendar(method, ICAL_PRODID, ICAL_VERSION, null,
+ iterate<Instance>(this).to_array_list());
+ }
+
+ /**
+ * Export this { link Instance}'s master as an iCalendar.
+ *
+ * @see export
+ * @see is_master
+ */
+ public iCalendar export_master(iCal.icalproperty_method method) {
+ return new iCalendar(method, ICAL_PRODID, ICAL_VERSION, null,
+ iterate<Instance>(master).to_array_list());
+ }
+
+ /**
* Returns an appropriate { link Component} instance for the iCalendar component.
*
* VCALENDARs should use { link Component.iCalendar}.
diff --git a/src/host/host-attendees-editor.vala b/src/host/host-attendees-editor.vala
index 74d465b..f52e827 100644
--- a/src/host/host-attendees-editor.vala
+++ b/src/host/host-attendees-editor.vala
@@ -16,7 +16,10 @@ public class AttendeesEditor : Gtk.Box, Toolkit.Card {
public Gtk.Widget? default_widget { get { return accept_button; } }
- public Gtk.Widget? initial_focus { get { return add_guest_entry; } }
+ public Gtk.Widget? initial_focus { get { return organizer_entry; } }
+
+ [GtkChild]
+ private Gtk.Entry organizer_entry;
[GtkChild]
private Gtk.Entry add_guest_entry;
@@ -35,14 +38,33 @@ public class AttendeesEditor : Gtk.Box, Toolkit.Card {
private new Component.Event? event = null;
private Toolkit.ListBoxModel<Component.Person> guest_model;
+ private Toolkit.EntryClearTextConnector entry_clear_connector = new Toolkit.EntryClearTextConnector();
public AttendeesEditor() {
guest_model = new Toolkit.ListBoxModel<Component.Person>(guest_listbox, model_presentation);
+ organizer_entry.bind_property("text", accept_button, "sensitive", BindingFlags.SYNC_CREATE,
+ transform_to_accept_sensitive);
+ guest_model.bind_property(Toolkit.ListBoxModel.PROP_SIZE, accept_button, "sensitive",
+ BindingFlags.SYNC_CREATE, transform_to_accept_sensitive);
+
add_guest_entry.bind_property("text", add_guest_button, "sensitive", BindingFlags.SYNC_CREATE,
transform_add_guest_text_to_button);
+
guest_model.bind_property(Toolkit.ListBoxModel.PROP_SELECTED, remove_guest_button, "sensitive",
BindingFlags.SYNC_CREATE, transform_list_selected_to_button);
+
+ entry_clear_connector.connect_to(organizer_entry);
+ entry_clear_connector.connect_to(add_guest_entry);
+ }
+
+ private bool transform_to_accept_sensitive(Binding binding, Value source_value, ref Value target_value) {
+ if (guest_model.size > 0 || !String.is_empty(organizer_entry.text))
+ target_value = Email.is_valid_mailbox(organizer_entry.text);
+ else
+ target_value = true;
+
+ return true;
}
private bool transform_add_guest_text_to_button(Binding binding, Value source_value,
@@ -70,6 +92,10 @@ public class AttendeesEditor : Gtk.Box, Toolkit.Card {
.filter(attendee => !event.organizers.contains(attendee))
.to_array_list()
);
+
+ // we only support one organizer, so use first one in form
+ if (!event.organizers.is_empty)
+ organizer_entry.text = traverse<Component.Person>(event.organizers).first().mailbox;
}
[GtkCallback]
@@ -88,23 +114,31 @@ public class AttendeesEditor : Gtk.Box, Toolkit.Card {
return false;
}
- [GtkCallback]
- private void on_add_guest_button_clicked() {
- string mailbox = add_guest_entry.text.strip();
+ private Component.Person? make_person(string text, Component.Person.Relationship relationship) {
+ string mailbox = text.strip();
if (!Email.is_valid_mailbox(mailbox))
- return;
+ return null;
try {
- // add to model (which adds to listbox) and clear entry
- guest_model.add(new Component.Person(Component.Person.Relationship.ATTENDEE,
- Email.generate_mailto_uri(mailbox)));
- add_guest_entry.text = "";
+ return new Component.Person(relationship, Email.generate_mailto_uri(mailbox));
} catch (Error err) {
debug("Unable to generate mailto from \"%s\": %s", mailbox, err.message);
+
+ return null;
}
}
[GtkCallback]
+ private void on_add_guest_button_clicked() {
+ // add to model (which adds to listbox) and clear entry
+ Component.Person? attendee = make_person(add_guest_entry.text,
Component.Person.Relationship.ATTENDEE);
+ if (attendee != null)
+ guest_model.add(attendee);
+
+ add_guest_entry.text = "";
+ }
+
+ [GtkCallback]
private void on_remove_guest_button_clicked() {
if (guest_model.selected != null)
guest_model.remove(guest_model.selected);
@@ -112,6 +146,17 @@ public class AttendeesEditor : Gtk.Box, Toolkit.Card {
[GtkCallback]
private void on_accept_button_clicked() {
+ Component.Person? organizer = null;
+ if (guest_model.size > 0) {
+ organizer = make_person(organizer_entry.text, Component.Person.Relationship.ORGANIZER);
+ if (organizer == null)
+ return;
+ }
+
+ event.clear_organizers();
+ if (organizer != null)
+ event.add_organizers(iterate<Component.Person>(organizer).to_array_list());
+
event.clear_attendees();
event.add_attendees(guest_model.all());
diff --git a/src/host/host-create-update-event.vala b/src/host/host-create-update-event.vala
index 516c411..0203f00 100644
--- a/src/host/host-create-update-event.vala
+++ b/src/host/host-create-update-event.vala
@@ -42,6 +42,12 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
private Gtk.Entry location_entry;
[GtkChild]
+ private Gtk.Label organizer_label;
+
+ [GtkChild]
+ private Gtk.Label organizer_text;
+
+ [GtkChild]
private Gtk.Label attendees_text;
[GtkChild]
@@ -93,6 +99,9 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
update_this_button.clicked.connect(on_update_this_button_clicked);
cancel_recurring_button.clicked.connect(on_cancel_recurring_button_clicked);
+ organizer_text.query_tooltip.connect(on_organizer_text_query_tooltip);
+ organizer_text.has_tooltip = true;
+
attendees_text.query_tooltip.connect(on_attendees_text_query_tooltip);
attendees_text.has_tooltip = true;
@@ -160,10 +169,20 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
location_entry.text = event.location ?? "";
description_textview.buffer.text = event.description ?? "";
+
+ // Only show "Organizer" and associated text if something to show
+ organizer_text.label = traverse<Component.Person>(event.organizers)
+ .sort()
+ .to_string(stringify_persons);
+ bool has_organizer = !String.is_empty(organizer_text.label);
+ organizer_label.visible = organizer_text.visible = has_organizer;
+ organizer_label.no_show_all = organizer_text.no_show_all = !has_organizer;
+
+ // Don't count organizers as attendees
attendees_text.label = traverse<Component.Person>(event.attendees)
.filter(attendee => !event.organizers.contains(attendee))
.sort()
- .to_string(stringify_attendees);
+ .to_string(stringify_persons);
if (String.is_empty(attendees_text.label)) {
// "None" as in "no people"
attendees_text.label = _("None");
@@ -188,6 +207,18 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
rotating_button_box.family = FAMILY_NORMAL;
}
+ private bool on_organizer_text_query_tooltip(Gtk.Widget widget, int x, int y, bool keyboard,
+ Gtk.Tooltip tooltip) {
+ if (!organizer_text.get_layout().is_ellipsized())
+ return false;
+
+ tooltip.set_text(traverse<Component.Person>(event.organizers)
+ .sort()
+ .to_string(stringify_persons_tooltip));
+
+ return true;
+ }
+
private bool on_attendees_text_query_tooltip(Gtk.Widget widget, int x, int y, bool keyboard,
Gtk.Tooltip tooltip) {
if (!attendees_text.get_layout().is_ellipsized())
@@ -196,17 +227,17 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
tooltip.set_text(traverse<Component.Person>(event.attendees)
.filter(attendee => !event.organizers.contains(attendee))
.sort()
- .to_string(stringify_attendees_tooltip));
+ .to_string(stringify_persons_tooltip));
return true;
}
- private string? stringify_attendees(Component.Person person, bool is_first, bool is_last) {
+ private string? stringify_persons(Component.Person person, bool is_first, bool is_last) {
// Email address followed by common separator, i.e. "alice example com, bob example com"
return !is_last ? _("%s, ").printf(person.full_mailbox) : person.full_mailbox;
}
- private string? stringify_attendees_tooltip(Component.Person person, bool is_first, bool is_last) {
+ private string? stringify_persons_tooltip(Component.Person person, bool is_first, bool is_last) {
return !is_last ? "%s\n".printf(person.full_mailbox) : person.full_mailbox;
}
@@ -338,7 +369,8 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
Toolkit.set_unbusy(this, cursor);
- invite_attendees(target);
+ // TODO: PUBLISH or REQUEST?
+ invite_attendees(target, iCal.icalproperty_method.REQUEST);
if (create_err == null)
notify_success();
@@ -391,7 +423,8 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
Toolkit.set_unbusy(this, cursor);
- invite_attendees(target);
+ // PUBLISH is used to update an existing event
+ invite_attendees(target, iCal.icalproperty_method.PUBLISH);
if (update_err == null)
notify_success();
@@ -399,9 +432,12 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
report_error(_("Unable to update event: %s").printf(update_err.message));
}
- private void invite_attendees(Component.Event event) {
- Component.iCalendar ics = new Component.iCalendar(iCal.icalproperty_method.REQUEST,
- Component.ICAL_PRODID, Component.ICAL_VERSION, null, event.attendees);
+ private void invite_attendees(Component.Event event, iCal.icalproperty_method method) {
+ // no attendees, no invites
+ if (event.attendees.size == 0)
+ return;
+
+ Component.iCalendar ics = event.export_master(method);
// export .ics to temporary directory so the filename is a pristine "invite.ics"
string temporary_filename;
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index f5cd1d0..c826247 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -322,14 +322,9 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
return;
// if switch available and active, export master not the generated instance
- Component.Instance to_export = (export_master_checkbutton != null &&
export_master_checkbutton.active)
- ? event.master
- : event;
-
- // Export as a self-contained iCalendar
- Component.iCalendar icalendar = new Component.iCalendar(iCal.icalproperty_method.PUBLISH,
- Component.ICAL_PRODID, Component.ICAL_VERSION, null,
- iterate<Component.Instance>(to_export).to_array_list());
+ Component.iCalendar icalendar = (export_master_checkbutton != null &&
export_master_checkbutton.active)
+ ? event.export_master(iCal.icalproperty_method.PUBLISH)
+ : event.export(iCal.icalproperty_method.PUBLISH);
try {
FileUtils.set_contents(filename, icalendar.source);
diff --git a/src/rc/attendees-editor.ui b/src/rc/attendees-editor.ui
index cfb058c..5ee9186 100644
--- a/src/rc/attendees-editor.ui
+++ b/src/rc/attendees-editor.ui
@@ -24,94 +24,157 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="box2">
+ <object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="spacing">4</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">6</property>
<child>
- <object class="GtkEntry" id="add_guest_entry">
+ <object class="GtkLabel" id="organizer_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">4</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Organizer</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="guest_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Guests</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="organizer_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="tooltip_text" translatable="yes">For example, bob example com</property>
+ <property name="tooltip_text" translatable="yes">For example, alice example com</property>
+ <property name="margin_bottom">4</property>
+ <property name="hexpand">True</property>
<property name="activates_default">True</property>
- <property name="placeholder_text" translatable="yes">Email address</property>
+ <property name="placeholder_text" translatable="yes">Email address (required if guests are
invited)</property>
<property name="input_purpose">email</property>
- <signal name="focus-in-event" handler="on_add_guest_entry_focus_in_event"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
- <signal name="focus-out-event" handler="on_add_guest_entry_focus_out_event"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="add_guest_button">
- <property name="label" translatable="yes">A_dd Guest</property>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkEntry" id="add_guest_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">For example, bob example com</property>
+ <property name="activates_default">True</property>
+ <property name="placeholder_text" translatable="yes">Email address</property>
+ <property name="input_purpose">email</property>
+ <signal name="focus-in-event" handler="on_add_guest_entry_focus_in_event"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
+ <signal name="focus-out-event" handler="on_add_guest_entry_focus_out_event"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="add_guest_button">
+ <property name="label" translatable="yes">A_dd Guest</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>
+ <property name="xalign">0.60000002384185791</property>
+ <signal name="clicked" handler="on_add_guest_button_clicked"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="remove_guest_button">
+ <property name="label" translatable="yes">_Remove Guest</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="halign">end</property>
<property name="use_underline">True</property>
- <property name="xalign">0.60000002384185791</property>
- <signal name="clicked" handler="on_add_guest_button_clicked"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
+ <signal name="clicked" handler="on_remove_guest_button_clicked"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">1</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</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="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">in</property>
<child>
- <object class="GtkViewport" id="viewport1">
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
<child>
- <object class="GtkListBox" id="guest_listbox">
+ <object class="GtkViewport" id="viewport1">
<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>
+ <child>
+ <object class="GtkListBox" id="guest_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">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
</child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="remove_guest_button">
- <property name="label" translatable="yes">_Remove Guest</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="halign">end</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_remove_guest_button_clicked"
object="CaliforniaHostAttendeesEditor" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">3</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
@@ -161,7 +224,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">4</property>
+ <property name="position">5</property>
</packing>
</child>
</template>
diff --git a/src/rc/create-update-event.ui b/src/rc/create-update-event.ui
index 43fb9d0..0761f72 100644
--- a/src/rc/create-update-event.ui
+++ b/src/rc/create-update-event.ui
@@ -175,7 +175,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">7</property>
+ <property name="top_attach">8</property>
<property name="width">2</property>
</packing>
</child>
@@ -191,7 +191,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">6</property>
+ <property name="top_attach">7</property>
</packing>
</child>
<child>
@@ -202,7 +202,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">6</property>
+ <property name="top_attach">7</property>
</packing>
</child>
<child>
@@ -221,7 +221,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">5</property>
+ <property name="top_attach">6</property>
</packing>
</child>
<child>
@@ -248,7 +248,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">5</property>
+ <property name="top_attach">6</property>
</packing>
</child>
<child>
@@ -265,7 +265,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">4</property>
+ <property name="top_attach">5</property>
</packing>
</child>
<child>
@@ -276,7 +276,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">4</property>
+ <property name="top_attach">5</property>
</packing>
</child>
<child>
@@ -293,7 +293,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">3</property>
+ <property name="top_attach">4</property>
</packing>
</child>
<child>
@@ -341,6 +341,33 @@
</object>
<packing>
<property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="organizer_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Organizer</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="organizer_text">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">(none)</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
diff --git a/src/toolkit/toolkit-listbox-model.vala b/src/toolkit/toolkit-listbox-model.vala
index efe3e95..92ef654 100644
--- a/src/toolkit/toolkit-listbox-model.vala
+++ b/src/toolkit/toolkit-listbox-model.vala
@@ -19,6 +19,7 @@ namespace California.Toolkit {
public class ListBoxModel<G> : BaseObject {
public const string PROP_SELECTED = "selected";
+ public const string PROP_SIZE = "size";
private const string KEY = "org.yorba.california.listbox-model.model";
@@ -35,9 +36,9 @@ public class ListBoxModel<G> : BaseObject {
public Gtk.ListBox listbox { get; private set; }
/**
- * The number if items in the { link ListBoxModel}.
+ * The number of items in the { link ListBoxModel}.
*/
- public int size { get { return items.size; } }
+ public int size { get; private set; default = 0; }
/**
* The item currently selected by the { link listbox}, null if no selection has been made.
@@ -126,6 +127,9 @@ public class ListBoxModel<G> : BaseObject {
listbox.add(row);
row.show_all();
+ // adjust size before signalling
+ size = size + 1;
+
added(item);
return true;
@@ -184,6 +188,9 @@ public class ListBoxModel<G> : BaseObject {
if (remove_from_listbox)
row.destroy();
+ // adjust before signalling
+ size = (size - 1).clamp(0, int.MAX);
+
removed(item);
return true;
diff --git a/vapi/libecal-1.2.vapi b/vapi/libecal-1.2.vapi
index d692d2e..6ead3ec 100644
--- a/vapi/libecal-1.2.vapi
+++ b/vapi/libecal-1.2.vapi
@@ -560,11 +560,11 @@ namespace E {
public delegate bool CalRecurInstanceFn (E.CalComponent comp, time_t instance_start, time_t
instance_end);
[CCode (cheader_filename = "libecal/libecal.h")]
public delegate iCal.icaltimezone CalRecurResolveTimezoneFn (string tzid);
- [CCode (cheader_filename = "libecal/libecal.h")]
+ [CCode (cheader_filename = "libecal/libecal.h", cname = "CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS")]
public const string CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
- [CCode (cheader_filename = "libecal/libecal.h")]
+ [CCode (cheader_filename = "libecal/libecal.h", cname = "CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS")]
public const string CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
- [CCode (cheader_filename = "libecal/libecal.h")]
+ [CCode (cheader_filename = "libecal/libecal.h", cname = "CAL_BACKEND_PROPERTY_DEFAULT_OBJECT")]
public const string CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
[CCode (cheader_filename = "libecal/libecal.h")]
public const string CAL_STATIC_CAPABILITY_ALARM_DESCRIPTION;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]