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
This commit is contained in:
committed by
Georges Basile Stavracas Neto
parent
2c75e72582
commit
067e8ae765
+103
-6
@@ -164,6 +164,22 @@
|
||||
<property name="top_attach">1</property>
|
||||
</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>
|
||||
@@ -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>
|
||||
@@ -395,12 +411,93 @@
|
||||
</object>
|
||||
</child>
|
||||
</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>
|
||||
@@ -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>
|
||||
|
||||
+186
-22
@@ -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)
|
||||
|
||||
@@ -268,6 +281,29 @@ on_calendar_selected (GSimpleAction *action,
|
||||
GCAL_EXIT;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -442,6 +478,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)
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
Reference in New Issue
Block a user