[gnome-calendar] edit-dialog: add 'Repeat' options for simple recurrences
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calendar] edit-dialog: add 'Repeat' options for simple recurrences
- Date: Thu, 13 Jul 2017 16:34:40 +0000 (UTC)
commit 067e8ae765927211a9c49514f947523cde6cf721
Author: Yash Singh <yashdev10p gmail com>
Date: Wed Jul 12 02:04:15 2017 +0530
edit-dialog: add 'Repeat' options for simple recurrences
Currently, creating recurring events is not supported
in gnome-calendar.
This patch adds a Repeat combobox with a list of
simple recurrences such as:
* Monday - Friday events
* Daily events
* Weekly events
* Monthly events
* Yearly events
and also a list of recurrence-duration-types such as:
* If an event should repeat forever
* A date until which the event should repeat
* Number of times an event should repeat
It enables the user to create simple recurring events and
even modify the recurrence-property of an already
recurring event.
https://bugzilla.gnome.org/show_bug.cgi?id=782755
data/ui/edit-dialog.ui | 109 ++++++++++++++++++++++++--
src/gcal-edit-dialog.c | 208 +++++++++++++++++++++++++++++++++++++++++++-----
src/gcal-edit-dialog.h | 2 +
3 files changed, 291 insertions(+), 28 deletions(-)
---
diff --git a/data/ui/edit-dialog.ui b/data/ui/edit-dialog.ui
index 5bdf828..e51ef19 100644
--- a/data/ui/edit-dialog.ui
+++ b/data/ui/edit-dialog.ui
@@ -165,6 +165,22 @@
</packing>
</child>
<child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ <property name="label" translatable="yes">Repeat</property>
+ <property name="ellipsize">end</property>
+ <property name="sensitive" bind-source="GcalEditDialog" bind-property="writable"
bind-flags="default" />
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="reminders_label">
<property name="visible">True</property>
<property name="xalign">1.0</property>
@@ -178,7 +194,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">4</property>
+ <property name="top_attach">6</property>
</packing>
</child>
<child>
@@ -194,7 +210,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">6</property>
+ <property name="top_attach">8</property>
</packing>
</child>
<child>
@@ -209,7 +225,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">5</property>
+ <property name="top_attach">7</property>
</packing>
</child>
<child>
@@ -397,11 +413,92 @@
</object>
<packing>
<property name="left_attach">1</property>
+ <property name="top_attach">6</property>
+ <property name="width">4</property>
+ </packing>
+ </child>
+ <!-- combo-box with options to define the recurrence-rules !-->
+ <child>
+ <object class="GtkComboBoxText" id="repeat_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <signal name="changed" handler="repeat_type_changed" object="GcalEditDialog" swapped="no"/>
+ <items>
+ <item translatable="yes" id="no_repeat">No Repeat</item>
+ <item translatable="yes" id="daily">Daily</item>
+ <item translatable="yes" id="mon_fri">Monday - Friday</item>
+ <item translatable="yes" id="weekly">Weekly</item>
+ <item translatable="yes" id="monthly">Monthly</item>
+ <item translatable="yes" id="yearly">Yearly</item>
+ </items>
+ <property name="active_id">no_repeat</property>
+ <style>
+ <class name="background" />
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
<property name="top_attach">4</property>
<property name="width">4</property>
</packing>
</child>
<child>
+ <object class="GtkBox" id="repeat_limits_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="sensitive" bind-source="GcalEditDialog" bind-property="writable"
bind-flags="default" />
+ <child>
+ <object class="GtkComboBoxText" id="repeat_duration_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <signal name="changed" handler="repeat_duration_changed" object="GcalEditDialog"
swapped="no"/>
+ <items>
+ <item translatable="yes" id="forever">Forever</item>
+ <item translatable="yes" id="number_of_occurrences_spin">No. of occurrences</item>
+ <item translatable="yes" id="until_date">Until Date</item>
+ </items>
+ <property name="active_id">forever</property>
+ <style>
+ <class name="background" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="repeat_duration_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+
+ <child>
+ <object class = "GtkSpinButton" id="number_of_occurrences_spin">
+ <property name="visible">True</property>
+ <property name="input_purpose">number</property>
+ </object>
+ </child>
+
+ <child>
+ <object class = "GcalDateSelector" id="until_date_selector">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <style>
+ <class name="background" />
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="width">4</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkEntry" id="location_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -412,7 +509,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">5</property>
+ <property name="top_attach">7</property>
<property name="width">4</property>
</packing>
</child>
@@ -441,7 +538,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">6</property>
+ <property name="top_attach">8</property>
<property name="width">4</property>
</packing>
</child>
@@ -463,7 +560,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">7</property>
+ <property name="top_attach">9</property>
</packing>
</child>
</object>
diff --git a/src/gcal-edit-dialog.c b/src/gcal-edit-dialog.c
index 85d0435..156e970 100644
--- a/src/gcal-edit-dialog.c
+++ b/src/gcal-edit-dialog.c
@@ -25,9 +25,12 @@
#include "gcal-edit-dialog.h"
#include "gcal-time-selector.h"
#include "gcal-utils.h"
+#include "gcal-event.h"
+#include "gcal-recurrence.h"
#include <libecal/libecal.h>
#include <glib/gi18n.h>
+#include <gtk/gtk.h>
/**
* SECTION:gcal-edit-dialog
@@ -75,6 +78,15 @@ struct _GcalEditDialog
GtkWidget *alarms_listbox;
+ GtkWidget *repeat_combo;
+ GtkWidget *repeat_duration_combo;
+ GtkWidget *repeat_limits_box;
+
+ /* Recurrence widgets */
+ GtkWidget *number_of_occurrences_spin;
+ GtkWidget *repeat_duration_stack;
+ GtkWidget *until_date_selector;
+
/* Add Alarms popover buttons */
GtkWidget *five_minutes_button;
GtkWidget *ten_minutes_button;
@@ -96,40 +108,41 @@ struct _GcalEditDialog
/* flags */
gboolean format_24h;
gboolean event_is_new;
+ gboolean recurrence_changed;
gboolean setting_event;
};
-static void fill_sources_menu (GcalEditDialog *dialog);
+static void fill_sources_menu (GcalEditDialog *dialog);
-static void on_calendar_selected (GSimpleAction *menu_item,
- GVariant *value,
- gpointer user_data);
+static void on_calendar_selected (GSimpleAction *menu_item,
+ GVariant *value,
+ gpointer user_data);
-static void update_location (GtkEntry *entry,
- GParamSpec *pspec,
- gpointer user_data);
+static void update_location (GtkEntry *entry,
+ GParamSpec *pspec,
+ gpointer user_data);
-static void update_summary (GtkEntry *entry,
- GParamSpec *pspec,
- gpointer user_data);
+static void update_summary (GtkEntry *entry,
+ GParamSpec *pspec,
+ gpointer user_data);
-static void gcal_edit_dialog_constructed (GObject *object);
+static void gcal_edit_dialog_constructed (GObject *object);
-static void gcal_edit_dialog_finalize (GObject *object);
+static void gcal_edit_dialog_finalize (GObject *object);
-static void gcal_edit_dialog_set_writable (GcalEditDialog *dialog,
- gboolean writable);
+static void gcal_edit_dialog_set_writable (GcalEditDialog *dialog,
+ gboolean writable);
-static void gcal_edit_dialog_clear_data (GcalEditDialog *dialog);
+static void gcal_edit_dialog_clear_data (GcalEditDialog *dialog);
-static void gcal_edit_dialog_action_button_clicked (GtkWidget *widget,
- gpointer user_data);
+static void gcal_edit_dialog_action_button_clicked (GtkWidget *widget,
+ gpointer user_data);
-static void gcal_edit_dialog_all_day_changed (GtkWidget *widget,
- gpointer user_data);
+static void gcal_edit_dialog_all_day_changed (GtkWidget *widget,
+ gpointer user_data);
-static void add_alarm_button_clicked (GtkWidget *button,
- GcalEditDialog *self);
+static void add_alarm_button_clicked (GtkWidget *button,
+ GcalEditDialog *self);
G_DEFINE_TYPE (GcalEditDialog, gcal_edit_dialog, GTK_TYPE_DIALOG)
@@ -269,6 +282,29 @@ on_calendar_selected (GSimpleAction *action,
}
static void
+remove_recurrence_properties (GcalEvent *event)
+{
+ ECalComponent *comp;
+ icalcomponent *icalcomp;
+ icalproperty *prop;
+
+ comp = gcal_event_get_component (event);
+ icalcomp = e_cal_component_get_icalcomponent (comp);
+
+ e_cal_component_set_recurid (comp, NULL);
+
+ prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
+
+ if (prop)
+ {
+ icalcomponent_remove_property (icalcomp, prop);
+ icalproperty_free (prop);
+ }
+
+ e_cal_component_rescan (comp);
+}
+
+static void
update_location (GtkEntry *entry,
GParamSpec *pspec,
gpointer user_data)
@@ -443,6 +479,50 @@ gcal_edit_dialog_set_property (GObject *object,
}
static void
+repeat_duration_changed (GtkComboBox *widget,
+ GcalEditDialog *self)
+{
+ switch (gtk_combo_box_get_active (widget))
+ {
+ case 0:
+ gtk_widget_hide (self->repeat_duration_stack);
+ break;
+
+ case 1:
+ gtk_widget_show (self->repeat_duration_stack);
+ gtk_stack_set_visible_child (GTK_STACK (self->repeat_duration_stack),
self->number_of_occurrences_spin);
+ break;
+
+ case 2:
+ gtk_widget_show (self->repeat_duration_stack);
+ gtk_stack_set_visible_child (GTK_STACK (self->repeat_duration_stack), self->until_date_selector);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+repeat_type_changed (GtkComboBox *combobox,
+ GcalEditDialog *self)
+{
+ GcalRecurrenceFrequency frequency;
+ gboolean has_recurrence;
+
+ frequency = gtk_combo_box_get_active (combobox);
+ has_recurrence = frequency != GCAL_RECURRENCE_NO_REPEAT;
+
+ gtk_widget_set_visible (self->repeat_limits_box, has_recurrence);
+
+ if (has_recurrence)
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->repeat_duration_combo), GCAL_RECURRENCE_FOREVER);
+ gtk_widget_hide (self->repeat_duration_stack);
+ }
+}
+
+static void
gcal_edit_dialog_class_init (GcalEditDialogClass *klass)
{
GObjectClass *object_class;
@@ -525,18 +605,27 @@ gcal_edit_dialog_class_init (GcalEditDialogClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, title_label);
gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, subtitle_label);
gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, lock);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, number_of_occurrences_spin);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, repeat_combo);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, repeat_duration_combo);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, repeat_duration_stack);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, repeat_limits_box);
gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, source_image);
gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, sources_popover);
+ gtk_widget_class_bind_template_child (widget_class, GcalEditDialog, until_date_selector);
+
/* callbacks */
gtk_widget_class_bind_template_callback (widget_class, add_alarm_button_clicked);
gtk_widget_class_bind_template_callback (widget_class, fix_reminders_label_height_cb);
gtk_widget_class_bind_template_callback (widget_class, gcal_edit_dialog_action_button_clicked);
gtk_widget_class_bind_template_callback (widget_class, gcal_edit_dialog_all_day_changed);
+ gtk_widget_class_bind_template_callback (widget_class, repeat_duration_changed);
+ gtk_widget_class_bind_template_callback (widget_class, repeat_type_changed);
+ gtk_widget_class_bind_template_callback (widget_class, sync_datetimes);
gtk_widget_class_bind_template_callback (widget_class, update_summary);
gtk_widget_class_bind_template_callback (widget_class, update_location);
gtk_widget_class_bind_template_callback (widget_class, update_revealer_visibility_cb);
- gtk_widget_class_bind_template_callback (widget_class, sync_datetimes);
}
static void
@@ -659,6 +748,8 @@ gcal_edit_dialog_action_button_clicked (GtkWidget *widget,
}
else
{
+ GcalRecurrenceFrequency freq;
+ GcalRecurrence *old_recur;
GDateTime *start_date, *end_date;
gboolean all_day;
gchar *note_text;
@@ -715,6 +806,34 @@ gcal_edit_dialog_action_button_clicked (GtkWidget *widget,
g_clear_pointer (&start_date, g_date_time_unref);
g_clear_pointer (&end_date, g_date_time_unref);
+ /* Check Repeat popover and set recurrence-rules accordingly */
+ old_recur = gcal_event_get_recurrence (dialog->event);
+ freq = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->repeat_combo));
+
+ remove_recurrence_properties (dialog->event);
+
+ if ((!old_recur && freq != GCAL_RECURRENCE_NO_REPEAT) || old_recur->frequency != freq)
+ dialog->recurrence_changed = TRUE;
+
+ if (freq != GCAL_RECURRENCE_NO_REPEAT)
+ {
+ GcalRecurrence *recur;
+
+ recur = gcal_recurrence_new ();
+ recur->frequency = freq;
+ recur->limit_type = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->repeat_duration_combo));
+
+ if (recur->limit_type == GCAL_RECURRENCE_UNTIL)
+ recur->limit.until = gcal_date_selector_get_date (GCAL_DATE_SELECTOR
(dialog->until_date_selector));
+ else if (recur->limit_type == GCAL_RECURRENCE_COUNT)
+ recur->limit.count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
(dialog->number_of_occurrences_spin));
+
+ if (!gcal_recurrence_is_equal (old_recur, recur))
+ gcal_event_set_recurrence (dialog->event, recur);
+
+ g_clear_pointer (&recur, gcal_recurrence_free);
+ }
+
/* Update the source if needed */
if (dialog->selected_source &&
gcal_event_get_source (dialog->event) != dialog->selected_source)
@@ -1123,6 +1242,10 @@ void
gcal_edit_dialog_set_event (GcalEditDialog *dialog,
GcalEvent *event)
{
+ GcalRecurrenceLimitType limit_type;
+ GcalRecurrenceFrequency frequency;
+ GcalRecurrence *recur;
+ GtkAdjustment *count_adjustment;
GDateTime *date_start;
GDateTime *date_end;
cairo_surface_t *surface;
@@ -1138,10 +1261,37 @@ gcal_edit_dialog_set_event (GcalEditDialog *dialog,
dialog->setting_event = TRUE;
+ count_adjustment = gtk_adjustment_new (0, 0, 1000, 1, 1, 10);
+
+ gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (dialog->number_of_occurrences_spin), count_adjustment);
+
/* If we just set the event to NULL, simply send a property notify */
if (!event)
GCAL_GOTO (out);
+ /* Recurrences */
+ recur = gcal_event_get_recurrence (event);
+ frequency = recur ? recur->frequency : GCAL_RECURRENCE_NO_REPEAT;
+ limit_type = recur ? recur->limit_type : GCAL_RECURRENCE_FOREVER;
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->repeat_duration_combo), limit_type);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->repeat_combo), frequency);
+
+ switch (limit_type)
+ {
+ case GCAL_RECURRENCE_COUNT:
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->number_of_occurrences_spin), recur->limit.count);
+ break;
+
+ case GCAL_RECURRENCE_UNTIL:
+ gcal_date_selector_set_date (GCAL_DATE_SELECTOR (dialog->until_date_selector), recur->limit.until);
+ break;
+
+ case GCAL_RECURRENCE_FOREVER:
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->number_of_occurrences_spin), 0);
+ break;
+ }
+
all_day = gcal_event_get_all_day (event);
source = gcal_event_get_source (event);
@@ -1204,6 +1354,11 @@ gcal_edit_dialog_set_event (GcalEditDialog *dialog,
/* all_day */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->all_day_check), all_day);
+ /* recurrence_changed */
+ dialog->recurrence_changed = FALSE;
+
+ gtk_adjustment_set_value (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON
(dialog->number_of_occurrences_spin)), 0);
+
/* location */
gtk_entry_set_text (GTK_ENTRY (dialog->location_entry), gcal_event_get_location (event));
@@ -1327,3 +1482,12 @@ gcal_edit_dialog_get_date_end (GcalEditDialog *dialog)
GCAL_DATE_SELECTOR (dialog->end_date_selector),
GCAL_TIME_SELECTOR (dialog->end_time_selector));
}
+
+
+gboolean
+gcal_edit_dialog_get_recurrence_changed (GcalEditDialog *self)
+{
+ g_return_val_if_fail (GCAL_IS_EDIT_DIALOG (self), FALSE);
+
+ return self->recurrence_changed;
+}
diff --git a/src/gcal-edit-dialog.h b/src/gcal-edit-dialog.h
index 1dff9a1..17b5253 100644
--- a/src/gcal-edit-dialog.h
+++ b/src/gcal-edit-dialog.h
@@ -55,6 +55,8 @@ GDateTime* gcal_edit_dialog_get_date_end (GcalEditDialog *d
GDateTime* gcal_edit_dialog_get_date_start (GcalEditDialog *dialog);
+gboolean gcal_edit_dialog_get_recurrence_changed (GcalEditDialog *self);
+
G_END_DECLS
#endif /* __GCAL_EDIT_DIALOG_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]