[california/wip/725783-time] Broke out date/time widgets, cleaned up dialog, getting close
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725783-time] Broke out date/time widgets, cleaned up dialog, getting close
- Date: Wed, 30 Jul 2014 02:01:03 +0000 (UTC)
commit 55cba366b5d1ad8e3e88d2033681226c18dc0e42
Author: Jim Nelson <jim yorba org>
Date: Tue Jul 29 19:00:38 2014 -0700
Broke out date/time widgets, cleaned up dialog, getting close
src/Makefile.am | 4 +-
src/base/base-object.vala | 10 +-
src/calendar/calendar-date-span.vala | 24 ++
src/calendar/calendar-exact-time-span.vala | 60 ++++++
src/california-resources.xml | 3 +
src/component/component-event.vala | 46 +----
src/host/host-create-update-recurring.vala | 31 +---
src/host/host-date-time-widget.vala | 229 ++++++++++++++++++++
src/host/host-event-time-settings.vala | 194 +++++------------
src/host/host-quick-create-event.vala | 3 +-
src/host/host-show-event.vala | 3 +-
src/rc/create-update-recurring.ui | 2 -
src/rc/date-time-widget.ui | 250 ++++++++++++++++++++++
src/rc/event-time-settings.ui | 260 +----------------------
src/toolkit/toolkit-entry-filter-connector.vala | 87 ++++++++
15 files changed, 736 insertions(+), 470 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index dd14329..95d1833 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -93,6 +93,7 @@ california_VALASOURCES = \
host/host-calendar-list-item.vala \
host/host-create-update-event.vala \
host/host-create-update-recurring.vala \
+ host/host-date-time-widget.vala \
host/host-event-time-settings.vala \
host/host-import-calendar.vala \
host/host-main-window.vala \
@@ -122,9 +123,9 @@ california_VALASOURCES = \
toolkit/toolkit-combo-box-text-model.vala \
toolkit/toolkit-deck.vala \
toolkit/toolkit-deck-window.vala \
- toolkit/toolkit-editable-filter.vala \
toolkit/toolkit-editable-label.vala \
toolkit/toolkit-entry-clear-text-connector.vala \
+ toolkit/toolkit-entry-filter-connector.vala \
toolkit/toolkit-event-connector.vala \
toolkit/toolkit-listbox-model.vala \
toolkit/toolkit-motion-connector.vala \
@@ -183,6 +184,7 @@ california_RC = \
rc/calendar-manager-list-item.ui \
rc/create-update-event.ui \
rc/create-update-recurring.ui \
+ rc/date-time-widget.ui \
rc/event-time-settings.ui \
rc/google-authenticating.ui \
rc/google-calendar-list.ui \
diff --git a/src/base/base-object.vala b/src/base/base-object.vala
index 97779dd..b4a391e 100644
--- a/src/base/base-object.vala
+++ b/src/base/base-object.vala
@@ -15,7 +15,15 @@ namespace California {
*/
public abstract class BaseObject : Object {
- public BaseObject() {
+ /**
+ * Returns the base class name as a string.
+ *
+ * This can be used as a dummy to_string() for { link BaseObject}s that don't carry state to
+ * report.
+ */
+ public string classname { get { return get_type().name(); } }
+
+ protected BaseObject() {
}
/**
diff --git a/src/calendar/calendar-date-span.vala b/src/calendar/calendar-date-span.vala
index ac13827..f46f3b8 100644
--- a/src/calendar/calendar-date-span.vala
+++ b/src/calendar/calendar-date-span.vala
@@ -73,6 +73,30 @@ public class DateSpan : UnitSpan<Date> {
}
/**
+ * Returns a prettified string describing the { link Event}'s time span in as concise and
+ * economical manner possible.
+ *
+ * The supplied { link Date} pretty flags are applied to the two Date strings. If either of
+ * the { link DateSpan} crosses a year boundary, the INCLUDE_YEAR flag is automatically added.
+ */
+ public string to_pretty_string(Calendar.Date.PrettyFlag date_flags) {
+ if (!start_date.year.equal_to(Calendar.System.today.year)
+ || !end_date.year.equal_to(Calendar.System.today.year)) {
+ date_flags |= Calendar.Date.PrettyFlag.INCLUDE_YEAR;
+ }
+
+ if (is_same_day) {
+ // One-day event, print that date's "<full date>", including year if not
+ // current year
+ return start_date.to_pretty_string(date_flags);
+ }
+
+ // Prints a span of dates, i.e. "Monday, January 3 to Thursday, January 6"
+ return _("%s to %s").printf(start_date.to_pretty_string(date_flags),
+ end_date.to_pretty_string(date_flags));
+ }
+
+ /**
* @inheritDoc
*/
public override bool contains(Date date) {
diff --git a/src/calendar/calendar-exact-time-span.vala b/src/calendar/calendar-exact-time-span.vala
index 60aa3bd..d4632af 100644
--- a/src/calendar/calendar-exact-time-span.vala
+++ b/src/calendar/calendar-exact-time-span.vala
@@ -17,6 +17,18 @@ namespace California.Calendar {
public class ExactTimeSpan : BaseObject, Gee.Comparable<ExactTimeSpan>, Gee.Hashable<ExactTimeSpan> {
/**
+ * Pretty-printing flags for { link to_pretty_string}.
+ */
+ [Flags]
+ public enum PrettyFlag {
+ NONE = 0,
+ /**
+ * Use multiple lines to format string if lengthy.
+ */
+ ALLOW_MULTILINE
+ }
+
+ /**
* Starting { link ExactTime} of the span.
*
* start_exact_time will always be earlier to or equal to { link end_exact_time}.
@@ -96,6 +108,54 @@ public class ExactTimeSpan : BaseObject, Gee.Comparable<ExactTimeSpan>, Gee.Hash
}
/**
+ * Returns a prettified string describing the { link Event}'s time span in as concise and
+ * economical manner possible.
+ *
+ * The supplied { link Date} pretty flags are applied to the two Date strings. If either of
+ * the { link DateSpan} crosses a year boundary, the INCLUDE_YEAR flag is automatically added.
+ */
+ public string to_pretty_string(Calendar.Date.PrettyFlag date_flags, PrettyFlag time_flags) {
+ bool allow_multiline = (time_flags & PrettyFlag.ALLOW_MULTILINE) != 0;
+
+ if (!start_date.year.equal_to(Calendar.System.today.year)
+ || !end_date.year.equal_to(Calendar.System.today.year)) {
+ date_flags |= Calendar.Date.PrettyFlag.INCLUDE_YEAR;
+ }
+
+ if (is_same_day) {
+ // A span of time, i.e. "3:30pm to 4:30pm"
+ string timespan = _("%s to %s").printf(
+ start_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE),
+ end_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE));
+
+ // Single-day timed event, print "<full date>, <full start time> to <full end time>",
+ // including year if not current year
+ return "%s, %s".printf(start_date.to_pretty_string(date_flags), timespan);
+ }
+
+ if (allow_multiline) {
+ // Multi-day timed event, print "<full time>, <full date>" on both lines,
+ // including year if either not current year
+ // Prints two full time and date strings on separate lines, i.e.:
+ // 12 January 2012, 3:30pm
+ // 13 January 2013, 6:30am
+ return _("%s, %s\n%s, %s").printf(
+ start_exact_time.to_pretty_date_string(date_flags),
+ start_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE),
+ end_exact_time.to_pretty_date_string(date_flags),
+ end_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE));
+ }
+
+ // Prints full time and date strings on a single line, i.e.:
+ // 12 January 2012, 3:30pm to 13 January 2013, 6:30am
+ return _("%s, %s to %s, %s").printf(
+ start_exact_time.to_pretty_date_string(date_flags),
+ start_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE),
+ end_exact_time.to_pretty_date_string(date_flags),
+ end_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE));
+ }
+
+ /**
* Compares the { link start_exact_time} of two { link ExactTimeSpan}s.
*/
public int compare_to(ExactTimeSpan other) {
diff --git a/src/california-resources.xml b/src/california-resources.xml
index 7aac897..6d65154 100644
--- a/src/california-resources.xml
+++ b/src/california-resources.xml
@@ -25,6 +25,9 @@
<file compressed="false">rc/create-update-recurring.ui</file>
</gresource>
<gresource prefix="/org/yorba/california">
+ <file compressed="false">rc/date-time-widget.ui</file>
+ </gresource>
+ <gresource prefix="/org/yorba/california">
<file compressed="false">rc/event-time-settings.ui</file>
</gresource>
<gresource prefix="/org/yorba/california">
diff --git a/src/component/component-event.vala b/src/component/component-event.vala
index b4c2d34..1a0e224 100644
--- a/src/component/component-event.vala
+++ b/src/component/component-event.vala
@@ -350,57 +350,23 @@ public class Event : Instance, Gee.Comparable<Event> {
*
* @return null if no time/date information is specified
*/
- public string? get_event_time_pretty_string(Calendar.Timezone timezone) {
+ public string? get_event_time_pretty_string(Calendar.Date.PrettyFlag date_flags,
+ Calendar.ExactTimeSpan.PrettyFlag time_flags, Calendar.Timezone timezone) {
if (date_span == null && exact_time_span == null)
return null;
// if any dates are not in current year, display year in all dates
- Calendar.Date.PrettyFlag date_flags = Calendar.Date.PrettyFlag.NONE;
Calendar.DateSpan date_span = get_event_date_span(timezone);
if (!date_span.start_date.year.equal_to(Calendar.System.today.year)
|| !date_span.end_date.year.equal_to(Calendar.System.today.year)) {
date_flags |= Calendar.Date.PrettyFlag.INCLUDE_YEAR;
}
- // span string is kinda tricky
- string span;
- if (is_all_day) {
- if (date_span.is_same_day) {
- // All-day one-day event, print that date's "<full date>", including year if not
- // current year
- span = date_span.start_date.to_pretty_string(date_flags);
- } else {
- // Prints a span of dates, i.e. "Monday, January 3 to Thursday, January 6"
- span = _("%s to %s").printf(date_span.start_date.to_pretty_string(date_flags),
- date_span.end_date.to_pretty_string(date_flags));
- }
- } else {
- Calendar.ExactTimeSpan exact_time_span = exact_time_span.to_timezone(timezone);
- if (exact_time_span.is_same_day) {
- // A span of time, i.e. "3:30pm to 4:30pm"
- string timespan = _("%s to %s").printf(
-
exact_time_span.start_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE),
- exact_time_span.end_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE));
-
- // Single-day timed event, print "<full date>, <full start time> to <full end time>",
- // including year if not current year
- span = "%s, %s".printf(exact_time_span.start_date.to_pretty_string(date_flags),
- timespan);
- } else {
- // Multi-day timed event, print "<full time>, <full date>" on both lines,
- // including year if either not current year
- // Prints two full time and date strings on separate lines, i.e.:
- // 12 January 2012, 3:30pm
- // 13 January 2013, 6:30am
- span = _("%s, %s\n%s, %s").printf(
- exact_time_span.start_exact_time.to_pretty_date_string(date_flags),
-
exact_time_span.start_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE),
- exact_time_span.end_exact_time.to_pretty_date_string(date_flags),
- exact_time_span.end_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE));
- }
- }
+ // if all day, just use the DateSpan's pretty string
+ if (is_all_day)
+ return date_span.to_pretty_string(date_flags);
- return span;
+ return exact_time_span.to_timezone(timezone).to_pretty_string(date_flags, time_flags);
}
/**
diff --git a/src/host/host-create-update-recurring.vala b/src/host/host-create-update-recurring.vala
index ce6c4eb..8d9fb7f 100644
--- a/src/host/host-create-update-recurring.vala
+++ b/src/host/host-create-update-recurring.vala
@@ -107,7 +107,7 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
private Component.Event? master = null;
private Gee.HashMap<Calendar.DayOfWeek, Gtk.CheckButton> on_day_checkbuttons = new Gee.HashMap<
Calendar.DayOfWeek, Gtk.CheckButton>();
- private bool blocking_insert_text_numbers_only_signal = false;
+ private Toolkit.EntryFilterConnector numeric_filter = new Toolkit.EntryFilterConnector.only_numeric();
public CreateUpdateRecurring() {
// "Repeating event" checkbox activates almost every other control in this dialog
@@ -141,6 +141,9 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
on_day_checkbuttons[Calendar.DayOfWeek.FRI] = friday_checkbutton;
on_day_checkbuttons[Calendar.DayOfWeek.SAT] = saturday_checkbutton;
+ numeric_filter.connect_to(every_entry);
+ numeric_filter.connect_to(after_entry);
+
// Ok button's sensitivity is tied to a whole-lotta controls here
make_recurring_checkbutton.bind_property("active", ok_button, "sensitive",
BindingFlags.SYNC_CREATE, transform_to_ok_button_sensitive);
@@ -445,32 +448,6 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
}
[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 ... would use SignalHandler.block_by_func() and unblock_by_func(), but
- // the bindings are ungood
- 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]
private void on_cancel_button_clicked() {
jump_back();
}
diff --git a/src/host/host-date-time-widget.vala b/src/host/host-date-time-widget.vala
new file mode 100644
index 0000000..c14475b
--- /dev/null
+++ b/src/host/host-date-time-widget.vala
@@ -0,0 +1,229 @@
+/* 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/date-time-widget.ui")]
+public class DateTimeWidget : Gtk.Box {
+ public const string PROP_ENABLE_TIME = "enable-time";
+ public const string PROP_ENABLE_DATE = "enable-date";
+ public const string PROP_DATE = "date";
+ public const string PROP_WALL_TIME = "wall-time";
+
+ public bool enable_time { get; set; default = true; }
+
+ public bool enable_date { get; set; default = true; }
+
+ public Calendar.Date date { get; set; default = Calendar.System.today; }
+
+ public Calendar.WallTime wall_time { get; set; default = Calendar.System.now.to_wall_time(); }
+
+ [GtkChild]
+ private Gtk.Calendar calendar;
+
+ [GtkChild]
+ private Gtk.Entry hour_entry;
+
+ [GtkChild]
+ private Gtk.Label colon_label;
+
+ [GtkChild]
+ private Gtk.Entry minutes_entry;
+
+ [GtkChild]
+ private Gtk.Label meridiem_label;
+
+ [GtkChild]
+ private Gtk.EventBox hour_up;
+
+ [GtkChild]
+ private Gtk.EventBox hour_down;
+
+ [GtkChild]
+ private Gtk.EventBox minutes_up;
+
+ [GtkChild]
+ private Gtk.EventBox minutes_down;
+
+ [GtkChild]
+ private Gtk.EventBox meridiem_up;
+
+ [GtkChild]
+ private Gtk.EventBox meridiem_down;
+
+ private Toolkit.ButtonConnector button_connector = new Toolkit.ButtonConnector();
+ private Toolkit.EntryFilterConnector numeric_filter = new Toolkit.EntryFilterConnector.only_numeric();
+
+ public DateTimeWidget() {
+ button_connector.connect_to(hour_up);
+ button_connector.connect_to(hour_down);
+ button_connector.connect_to(minutes_up);
+ button_connector.connect_to(minutes_down);
+ button_connector.connect_to(meridiem_up);
+ button_connector.connect_to(meridiem_down);
+
+ numeric_filter.connect_to(hour_entry);
+ numeric_filter.connect_to(minutes_entry);
+
+ // use signal handlers to initialize widgets
+ on_date_changed();
+ on_wall_time_changed();
+
+ connect_property_signals();
+ connect_widget_signals();
+
+ // specifically-enabled sensitivities
+ bind_bool_to_time_controls(PROP_ENABLE_TIME, iterate<Gtk.Widget>(
+ hour_up, hour_down, minutes_up, minutes_down, meridiem_up, meridiem_down,
+ hour_entry, colon_label, minutes_entry, meridiem_label));
+
+ bind_bool_to_time_controls(PROP_ENABLE_DATE, iterate<Gtk.Widget>(calendar));
+ }
+
+ private void bind_bool_to_time_controls(string property, California.Iterable<Gtk.Widget> time_widgets) {
+ foreach (Gtk.Widget time_widget in time_widgets)
+ bind_property(property, time_widget, "sensitive", BindingFlags.SYNC_CREATE);
+ }
+
+ private void connect_property_signals() {
+ notify[PROP_DATE].connect(on_date_changed);
+ notify[PROP_WALL_TIME].connect(on_wall_time_changed);
+ }
+
+ private void disconnect_property_signals() {
+ notify[PROP_DATE].disconnect(on_date_changed);
+ notify[PROP_WALL_TIME].disconnect(on_wall_time_changed);
+ }
+
+ private void connect_widget_signals() {
+ button_connector.clicked.connect(on_time_adjustment_clicked);
+
+ calendar.day_selected.connect(on_calendar_day_selected);
+ calendar.month_changed.connect(on_calendar_month_or_year_changed);
+ calendar.next_year.connect(on_calendar_month_or_year_changed);
+ calendar.prev_year.connect(on_calendar_month_or_year_changed);
+ }
+
+ private void disconnect_widget_signals() {
+ button_connector.clicked.disconnect(on_time_adjustment_clicked);
+
+ calendar.day_selected.disconnect(on_calendar_day_selected);
+ calendar.month_changed.disconnect(on_calendar_month_or_year_changed);
+ calendar.next_year.disconnect(on_calendar_month_or_year_changed);
+ calendar.prev_year.disconnect(on_calendar_month_or_year_changed);
+ }
+
+ private bool on_time_adjustment_clicked(Toolkit.ButtonEvent details) {
+ if (details.button != Toolkit.Button.PRIMARY)
+ return Toolkit.PROPAGATE;
+
+ int amount;
+ Calendar.TimeUnit time_unit;
+ if (!adjust_time_controls(details, out amount, out time_unit))
+ return Toolkit.PROPAGATE;
+
+ // this will update the entry fields, so don't disconnect widget signals
+ wall_time = wall_time.adjust(amount, time_unit, null);
+
+ return Toolkit.STOP;
+ }
+
+ private bool adjust_time_controls(Toolkit.ButtonEvent details, out int amount, out Calendar.TimeUnit
time_unit) {
+ if (details.widget == hour_up) {
+ amount = 1;
+ time_unit = Calendar.TimeUnit.HOUR;
+ } else if (details.widget == hour_down) {
+ amount = -1;
+ time_unit = Calendar.TimeUnit.HOUR;
+ } else if (details.widget == minutes_up) {
+ amount = 1;
+ time_unit = Calendar.TimeUnit.MINUTE;
+ } else if (details.widget == minutes_down) {
+ amount = -1;
+ time_unit = Calendar.TimeUnit.MINUTE;
+ } else if (details.widget == meridiem_up) {
+ amount = 12;
+ time_unit = Calendar.TimeUnit.HOUR;
+ } else if (details.widget == meridiem_down) {
+ amount = -12;
+ time_unit = Calendar.TimeUnit.HOUR;
+ } else {
+ amount = 0;
+ time_unit = Calendar.TimeUnit.HOUR;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private Calendar.Date? get_selected_date() {
+ if (calendar.day == 0)
+ return null;
+
+ try {
+ return new Calendar.Date(
+ Calendar.DayOfMonth.for(calendar.day),
+ Calendar.Month.for(calendar.month + 1),
+ new Calendar.Year(calendar.year)
+ );
+ } catch (CalendarError calerr) {
+ debug("Unable to generate date from Gtk.Calendar: %s", calerr.message);
+
+ return null;
+ }
+ }
+
+ private void on_calendar_day_selected() {
+ disconnect_property_signals();
+
+ Calendar.Date? selected = get_selected_date();
+ if (selected != null && !selected.equal_to(date))
+ date = selected;
+
+ connect_property_signals();
+ }
+
+ private void on_calendar_month_or_year_changed() {
+ // If selected month/year is not for the current date, don't select the day of that month/year
+ // ... if selected month/year is for the current date, ensure that the day is selected ...
+ // and as a fallback, don't select the day of the month/year
+ Calendar.Date? selected = get_selected_date();
+ if (selected != null) {
+ if (selected.month_of_year().equal_to(date.month_of_year()))
+ calendar.day = date.day_of_month.value;
+ else
+ calendar.day = 0;
+ } else if (date.month.value == (calendar.month + 1) && date.year.value == calendar.year) {
+ calendar.day = date.day_of_month.value;
+ } else {
+ calendar.day = 0;
+ }
+ }
+
+ private void on_date_changed() {
+ disconnect_widget_signals();
+
+ calendar.day = date.day_of_month.value;
+ calendar.month = date.month.value - 1;
+ calendar.year = date.year.value;
+
+ connect_widget_signals();
+ }
+
+ private void on_wall_time_changed() {
+ disconnect_widget_signals();
+
+ hour_entry.text = "%d".printf(wall_time.12hour);
+ minutes_entry.text = "%02d".printf(wall_time.minute);
+ meridiem_label.label = wall_time.is_pm ? Calendar.FMT_PM : Calendar.FMT_AM;
+
+ connect_widget_signals();
+ }
+}
+
+}
+
diff --git a/src/host/host-event-time-settings.vala b/src/host/host-event-time-settings.vala
index f6e0e72..2e9da3b 100644
--- a/src/host/host-event-time-settings.vala
+++ b/src/host/host-event-time-settings.vala
@@ -10,53 +10,14 @@ namespace California.Host {
public class EventTimeSettings : Gtk.Box, Toolkit.Card {
public const string ID = "CaliforniaHostEventTimeSettings";
- private class TimeControls {
- public Gtk.EventBox hour_up;
- public Gtk.EventBox hour_down;
- public Gtk.EventBox minutes_up;
- public Gtk.EventBox minutes_down;
- public Gtk.EventBox meridiem_up;
- public Gtk.EventBox meridiem_down;
- public Gtk.Entry hour_entry;
- public Gtk.Entry minutes_entry;
- public Gtk.Label meridiem_label;
- }
-
- [GtkChild]
- private Gtk.Calendar from_calendar;
-
- [GtkChild]
- private Gtk.Calendar to_calendar;
-
- [GtkChild]
- private Gtk.Entry from_hour_entry;
-
- [GtkChild]
- private Gtk.Label from_colon_label;
-
- [GtkChild]
- private Gtk.Entry from_minutes_entry;
-
[GtkChild]
- private Gtk.Label from_meridiem_label;
+ private Gtk.Label summary_label;
[GtkChild]
- private Gtk.EventBox from_hour_up;
+ private Gtk.Box from_box;
[GtkChild]
- private Gtk.EventBox from_hour_down;
-
- [GtkChild]
- private Gtk.EventBox from_minutes_up;
-
- [GtkChild]
- private Gtk.EventBox from_minutes_down;
-
- [GtkChild]
- private Gtk.EventBox from_meridiem_up;
-
- [GtkChild]
- private Gtk.EventBox from_meridiem_down;
+ private Gtk.Box to_box;
[GtkChild]
private Gtk.CheckButton all_day_checkbutton;
@@ -67,129 +28,80 @@ public class EventTimeSettings : Gtk.Box, Toolkit.Card {
public Gtk.Widget? initial_focus { get { return null; } }
private new Component.Event? event = null;
- private Calendar.WallTime? start_time = null;
- private TimeControls from_controls = new TimeControls();
- public Toolkit.ButtonConnector button_connector = new Toolkit.ButtonConnector();
+ private DateTimeWidget from_widget = new DateTimeWidget();
+ private DateTimeWidget to_widget = new DateTimeWidget();
public EventTimeSettings() {
- from_controls.hour_up = from_hour_up;
- from_controls.hour_down = from_hour_down;
- from_controls.minutes_up = from_minutes_up;
- from_controls.minutes_down = from_minutes_down;
- from_controls.meridiem_up = from_meridiem_up;
- from_controls.meridiem_down = from_meridiem_down;
- from_controls.hour_entry = from_hour_entry;
- from_controls.minutes_entry = from_minutes_entry;
- from_controls.meridiem_label = from_meridiem_label;
-
- button_connector.connect_to(from_hour_up);
- button_connector.connect_to(from_hour_down);
- button_connector.connect_to(from_minutes_up);
- button_connector.connect_to(from_minutes_down);
- button_connector.connect_to(from_meridiem_up);
- button_connector.connect_to(from_meridiem_down);
+ // need to manually pack the date/time widgets
+ from_box.pack_start(from_widget);
+ to_box.pack_start(to_widget);
- button_connector.clicked.connect(on_time_adjustment_clicked);
+ from_widget.notify[DateTimeWidget.PROP_DATE].connect(on_update_summary);
+ from_widget.notify[DateTimeWidget.PROP_WALL_TIME].connect(on_update_summary);
+ to_widget.notify[DateTimeWidget.PROP_DATE].connect(on_update_summary);
+ to_widget.notify[DateTimeWidget.PROP_WALL_TIME].connect(on_update_summary);
+ all_day_checkbutton.notify["active"].connect(on_update_summary);
- bind_all_day_to_time_controls(iterate<Gtk.Widget>(
- from_hour_up, from_hour_down,
- from_minutes_up, from_minutes_down,
- from_meridiem_up, from_meridiem_down,
- from_hour_entry, from_colon_label, from_minutes_entry, from_meridiem_label).to_array_list());
- }
-
- private void bind_all_day_to_time_controls(Gee.List<Gtk.Widget> time_widgets) {
- foreach (Gtk.Widget time_widget in time_widgets) {
- all_day_checkbutton.bind_property("active", time_widget, "sensitive",
- BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
- }
+ all_day_checkbutton.bind_property("active", from_widget, DateTimeWidget.PROP_ENABLE_TIME,
+ BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
+ all_day_checkbutton.bind_property("active", to_widget, DateTimeWidget.PROP_ENABLE_TIME,
+ BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
}
public void jumped_to(Toolkit.Card? from, Toolkit.Card.Jump reason, Value? message) {
event = (Component.Event) message;
- start_time = event.is_all_day
- ? Calendar.System.now.to_wall_time()
- : event.exact_time_span.start_exact_time.to_wall_time();
+ // only set wall time if not all day; let old wall times float so user can return to them
+ // later while Deck is active
+ if (!event.is_all_day) {
+ Calendar.ExactTimeSpan time_span = event.exact_time_span.to_timezone(Calendar.Timezone.local);
+ from_widget.wall_time = time_span.start_exact_time.to_wall_time();
+ to_widget.wall_time = time_span.end_exact_time.to_wall_time();
+ }
- init_controls();
- }
-
- private void init_controls() {
Calendar.DateSpan event_span = event.get_event_date_span(Calendar.Timezone.local);
- init_calendar(from_calendar, event_span.start_date);
- init_calendar(to_calendar, event_span.end_date);
+ from_widget.date = event_span.start_date;
+ to_widget.date = event_span.end_date;
all_day_checkbutton.active = event.is_all_day;
- init_time_controls(from_controls, start_time);
- }
-
- private void init_calendar(Gtk.Calendar calendar, Calendar.Date date) {
- calendar.day = date.day_of_month.value;
- calendar.month = date.month.value - 1;
- calendar.year = date.year.value;
}
- private void init_time_controls(TimeControls controls, Calendar.WallTime wall_time) {
- controls.hour_entry.text = "%d".printf(wall_time.12hour);
- controls.minutes_entry.text = "%02d".printf(wall_time.minute);
- controls.meridiem_label.label = wall_time.is_pm ? Calendar.FMT_PM : Calendar.FMT_AM;
+ [GtkCallback]
+ private void on_cancel_button_clicked() {
+ jump_back();
}
- private bool on_time_adjustment_clicked(Toolkit.ButtonEvent details) {
- // ignored late "guaranteed" clicks and clicks from anything but primary button
- if (details.button != Toolkit.Button.PRIMARY)
- return Toolkit.PROPAGATE;
-
- int amount;
- Calendar.TimeUnit time_unit;
- if (!adjust_time_controls(from_controls, details, out amount, out time_unit))
- return Toolkit.PROPAGATE;
-
- start_time = start_time.adjust(amount, time_unit, null);
- init_time_controls(from_controls, start_time);
+ [GtkCallback]
+ private void on_ok_button_clicked() {
+ if (all_day_checkbutton.active)
+ event.set_event_date_span(get_date_span());
+ else
+ event.set_event_exact_time_span(get_exact_time_span());
- return Toolkit.STOP;
+ jump_to_card_by_name(CreateUpdateEvent.ID, event);
}
- private bool adjust_time_controls(TimeControls controls, Toolkit.ButtonEvent details, out int amount,
- out Calendar.TimeUnit time_unit) {
- if (details.widget == controls.hour_up) {
- amount = 1;
- time_unit = Calendar.TimeUnit.HOUR;
- } else if (details.widget == controls.hour_down) {
- amount = -1;
- time_unit = Calendar.TimeUnit.HOUR;
- } else if (details.widget == controls.minutes_up) {
- amount = 1;
- time_unit = Calendar.TimeUnit.MINUTE;
- } else if (details.widget == controls.minutes_down) {
- amount = -1;
- time_unit = Calendar.TimeUnit.MINUTE;
- } else if (details.widget == controls.meridiem_up) {
- amount = 12;
- time_unit = Calendar.TimeUnit.HOUR;
- } else if (details.widget == controls.meridiem_down) {
- amount = -12;
- time_unit = Calendar.TimeUnit.HOUR;
- } else {
- amount = 0;
- time_unit = Calendar.TimeUnit.HOUR;
-
- return false;
- }
-
- return true;
+ // This does not respect the all-day checkbox
+ private Calendar.DateSpan get_date_span() {
+ return new Calendar.DateSpan(from_widget.date, to_widget.date);
}
- [GtkCallback]
- private void on_cancel_button_clicked() {
- jump_back();
+ // This does not respect the all-day checkbox
+ private Calendar.ExactTimeSpan get_exact_time_span() {
+ return new Calendar.ExactTimeSpan(
+ new Calendar.ExactTime(Calendar.System.timezone, from_widget.date, from_widget.wall_time),
+ new Calendar.ExactTime(Calendar.System.timezone, to_widget.date, to_widget.wall_time)
+ );
}
- [GtkCallback]
- private void on_ok_button_clicked() {
- jump_back();
+ private void on_update_summary() {
+ Calendar.Date.PrettyFlag date_flags = Calendar.Date.PrettyFlag.NONE;
+ Calendar.ExactTimeSpan.PrettyFlag time_flags = Calendar.ExactTimeSpan.PrettyFlag.NONE;
+
+ if (all_day_checkbutton.active)
+ summary_label.label = get_date_span().to_pretty_string(date_flags);
+ else
+ summary_label.label = get_exact_time_span().to_pretty_string(date_flags, time_flags);
}
}
diff --git a/src/host/host-quick-create-event.vala b/src/host/host-quick-create-event.vala
index 7fc1dad..33195b0 100644
--- a/src/host/host-quick-create-event.vala
+++ b/src/host/host-quick-create-event.vala
@@ -69,7 +69,8 @@ public class QuickCreateEvent : Gtk.Grid, Toolkit.Card {
string eg;
if (event != null && (event.date_span != null || event.exact_time_span != null)) {
when_box.visible = true;
- when_text_label.label = event.get_event_time_pretty_string(Calendar.Timezone.local);
+ when_text_label.label = event.get_event_time_pretty_string(Calendar.Date.PrettyFlag.NONE,
+ Calendar.ExactTimeSpan.PrettyFlag.ALLOW_MULTILINE, Calendar.Timezone.local);
if (event.date_span != null)
eg = _("Example: Dinner at Tadich Grill 7:30pm");
else
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index 663130a..ea4d5be 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -118,7 +118,8 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
set_label(where_label, where_text, event.location);
// time
- set_label(when_label, when_text, event.get_event_time_pretty_string(Calendar.Timezone.local));
+ set_label(when_label, when_text, event.get_event_time_pretty_string(Calendar.Date.PrettyFlag.NONE,
+ Calendar.ExactTimeSpan.PrettyFlag.NONE, Calendar.Timezone.local));
// description
set_label(null, description_text, Markup.linkify(escape(event.description), linkify_delegate));
diff --git a/src/rc/create-update-recurring.ui b/src/rc/create-update-recurring.ui
index 205cef3..dccd51d 100644
--- a/src/rc/create-update-recurring.ui
+++ b/src/rc/create-update-recurring.ui
@@ -369,7 +369,6 @@
<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>
@@ -434,7 +433,6 @@
<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>
diff --git a/src/rc/date-time-widget.ui b/src/rc/date-time-widget.ui
new file mode 100644
index 0000000..4fbf1d7
--- /dev/null
+++ b/src/rc/date-time-widget.ui
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <template class="CaliforniaHostDateTimeWidget" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkCalendar" id="calendar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">False</property>
+ <property name="year">2014</property>
+ <property name="month">6</property>
+ <property name="day">23</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="time_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">False</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkEntry" id="hour_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">False</property>
+ <property name="vexpand">False</property>
+ <property name="max_length">2</property>
+ <property name="width_chars">2</property>
+ <property name="xalign">1</property>
+ <property name="input_purpose">digits</property>
+ </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="GtkLabel" id="colon_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">False</property>
+ <property name="label" translatable="yes">:</property>
+ </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>
+ <child>
+ <object class="GtkEntry" id="minutes_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="max_length">2</property>
+ <property name="width_chars">2</property>
+ <property name="input_purpose">digits</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="hour_up">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_hour_up_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">up</property>
+ </object>
+ </child>
+ </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="GtkEventBox" id="hour_down">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_hour_down_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">down</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="meridiem_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">am</property>
+ <property name="width_chars">3</property>
+ <property name="max_width_chars">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="minutes_up">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_minutes_up_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">up</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="minutes_down">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_minutes_down_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">down</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="meridiem_up">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_meridiem_up_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">up</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="meridiem_down">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkArrow" id="from_meridiem_down_arrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">False</property>
+ <property name="arrow_type">down</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </template>
+</interface>
diff --git a/src/rc/event-time-settings.ui b/src/rc/event-time-settings.ui
index 0dac5af..41a38cc 100644
--- a/src/rc/event-time-settings.ui
+++ b/src/rc/event-time-settings.ui
@@ -24,254 +24,19 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="box1">
+ <object class="GtkBox" id="date_time_widgets_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="hexpand">True</property>
<property name="spacing">4</property>
<child>
<object class="GtkBox" id="from_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="hexpand">False</property>
<property name="orientation">vertical</property>
- <property name="spacing">4</property>
<child>
- <object class="GtkCalendar" id="from_calendar">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">end</property>
- <property name="hexpand">False</property>
- <property name="year">2014</property>
- <property name="month">6</property>
- <property name="day">23</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkGrid" id="from_time_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="hexpand">False</property>
- <property name="vexpand">False</property>
- <child>
- <object class="GtkEntry" id="from_hour_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="hexpand">False</property>
- <property name="vexpand">False</property>
- <property name="max_length">2</property>
- <property name="width_chars">2</property>
- <property name="xalign">1</property>
- <property name="input_purpose">digits</property>
- </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="GtkLabel" id="from_colon_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="hexpand">False</property>
- <property name="label" translatable="yes">:</property>
- </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>
- <child>
- <object class="GtkEntry" id="from_minutes_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="hexpand">False</property>
- <property name="max_length">2</property>
- <property name="width_chars">2</property>
- <property name="input_purpose">digits</property>
- </object>
- <packing>
- <property name="left_attach">2</property>
- <property name="top_attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="from_hour_up">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_hour_up_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">up</property>
- </object>
- </child>
- </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="GtkEventBox" id="from_hour_down">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_hour_down_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">down</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="from_meridiem_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label">am</property>
- <property name="width_chars">3</property>
- <property name="max_width_chars">2</property>
- </object>
- <packing>
- <property name="left_attach">3</property>
- <property name="top_attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="from_minutes_up">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_minutes_up_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">up</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">2</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="from_minutes_down">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_minutes_down_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">down</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">2</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="from_meridiem_up">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_meridiem_up_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">up</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">3</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="from_meridiem_down">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="visible_window">False</property>
- <child>
- <object class="GtkArrow" id="from_meridiem_down_arrow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="hexpand">False</property>
- <property name="arrow_type">down</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">3</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
@@ -302,23 +67,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
- <property name="spacing">4</property>
- <child>
- <object class="GtkCalendar" id="to_calendar">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="hexpand">False</property>
- <property name="year">2014</property>
- <property name="month">6</property>
- <property name="day">23</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
<child>
<placeholder/>
</child>
diff --git a/src/toolkit/toolkit-entry-filter-connector.vala b/src/toolkit/toolkit-entry-filter-connector.vala
new file mode 100644
index 0000000..a856d2e
--- /dev/null
+++ b/src/toolkit/toolkit-entry-filter-connector.vala
@@ -0,0 +1,87 @@
+/* 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 connector that allows for filtering all text inserted into a Gtk.Entry.
+ */
+
+public class EntryFilterConnector : BaseObject {
+ private Gee.MapFunc<string, string> filter;
+ private Gee.HashSet<Gtk.Entry> entries = new Gee.HashSet<Gtk.Entry>();
+ private Gee.HashSet<Gtk.Entry> in_signal = new Gee.HashSet<Gtk.Entry>();
+
+ /**
+ * A generic filtering mechanism for all connected Gtk.Entry's.
+ */
+ public EntryFilterConnector(Gee.MapFunc<string, string> filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * A specific filter for allowing only numeric input.
+ */
+ public EntryFilterConnector.only_numeric() {
+ this (numeric_filter);
+ }
+
+ ~EntryFilterConnector() {
+ traverse_safely<Gtk.Entry>(entries).iterate(disconnect_from);
+ }
+
+ public void connect_to(Gtk.Entry entry) {
+ if (!entries.add(entry))
+ return;
+
+ entry.insert_text.connect(on_entry_insert);
+ }
+
+ public void disconnect_from(Gtk.Entry entry) {
+ if (!entries.remove(entry))
+ return;
+
+ entry.insert_text.disconnect(on_entry_insert);
+ }
+
+ private static string numeric_filter(owned string str) {
+ return from_string(str)
+ .filter(ch => ch.isdigit())
+ .to_string(ch => ch.to_string());
+ }
+
+ private void on_entry_insert(Gtk.Editable editable, string new_text, int new_text_length,
+ ref int position) {
+ Gtk.Entry entry = (Gtk.Entry) editable;
+
+ // prevent recursion when our modified text is inserted (i.e. allow the base handler to
+ // deal with new text directly)
+ if (entry in in_signal)
+ return;
+
+ // filter
+ string filtered = filter(new_text);
+
+ // insert new text into place, ensure this handler doesn't attempt to process this
+ // modified text ... would use SignalHandler.block_by_func() and unblock_by_func(), but
+ // the bindings are ungood
+ if (!String.is_empty(filtered)) {
+ in_signal.add(entry);
+ editable.insert_text(filtered, filtered.length, ref position);
+ in_signal.remove(entry);
+ }
+
+ // don't let the base handler have at the original text
+ Signal.stop_emission_by_name(editable, "insert-text");
+ }
+
+ public override string to_string() {
+ return classname;
+ }
+}
+
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]