diff options
Diffstat (limited to 'calendar')
-rw-r--r-- | calendar/ChangeLog | 5 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/alarm-notify-dialog.c | 308 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/alarm-notify-dialog.h | 18 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/alarm-notify.c | 2 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/alarm-notify.glade | 696 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/alarm-queue.c | 100 |
6 files changed, 662 insertions, 467 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 063cf79045..d97bfd8e14 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,8 @@ +2005-05-11 Philip Van Hoof <pvanhoof@gnome.org> + + * gui/alarm-notify/*: Made the alarm-notify dialog + multi-alarm aware + 2005-05-09 Rodrigo Moya <rodrigo@novell.com> * gui/migration.c (migrate_ical_folder_to_source): cover the case when diff --git a/calendar/gui/alarm-notify/alarm-notify-dialog.c b/calendar/gui/alarm-notify/alarm-notify-dialog.c index ee625c96f9..3b81bad8f1 100644 --- a/calendar/gui/alarm-notify/alarm-notify-dialog.c +++ b/calendar/gui/alarm-notify/alarm-notify-dialog.c @@ -22,6 +22,8 @@ #include <config.h> #include <stdio.h> #include <string.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtkcellrenderertext.h> #include <gtk/gtkdialog.h> #include <gtk/gtkimage.h> #include <gtk/gtklabel.h> @@ -42,31 +44,65 @@ #include <e-util/e-icon-factory.h> + +enum { + ALARM_DISPLAY_COLUMN, + ALARM_SUMMARY_COLUMN, + ALARM_DESCRIPTION_COLUMN, + ALARM_LOCATION_COLUMN, + + ALARM_START_COLUMN, + ALARM_END_COLUMN, + + ALARM_FUNCINFO_COLUMN, + + N_ALARM_COLUMNS +}; + /* The useful contents of the alarm notify dialog */ + +typedef struct { + AlarmNotifyFunc func; + gpointer func_data; +} AlarmFuncInfo; + typedef struct { GladeXML *xml; GtkWidget *dialog; - GtkWidget *title; GtkWidget *snooze_time; GtkWidget *minutes_label; GtkWidget *description; GtkWidget *location; - GtkWidget *start; - GtkWidget *end; - - AlarmNotifyFunc func; - gpointer func_data; + GtkWidget *treeview; + GtkWidget *scrolledwindow; + + AlarmFuncInfo *cur_funcinfo; + } AlarmNotify; enum { - AN_RESPONSE_EDIT = 0, + AN_RESPONSE_EDIT = 0, AN_RESPONSE_SNOOZE = 1 }; static void +tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data); + +static void +fill_in_labels (AlarmNotify *an, const gchar *summary, const gchar *description, + const gchar *location, time_t occur_start, time_t occur_end); + + + +AlarmNotify *an = NULL; +gboolean have_one = FALSE; + + + +static void an_update_minutes_label (GtkSpinButton *sb, gpointer data) { AlarmNotify *an; @@ -86,20 +122,31 @@ dialog_response_cb (GtkDialog *dialog, guint response_id, gpointer user_data) { int snooze_timeout; AlarmNotify *an = user_data; + GtkTreeIter iter; + GtkTreeModel *model = NULL; + AlarmFuncInfo *funcinfo = NULL; + GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &funcinfo, -1); + + g_return_if_fail (funcinfo); switch (response_id) { case AN_RESPONSE_EDIT: - (* an->func) (ALARM_NOTIFY_EDIT, -1, an->func_data); + (* funcinfo->func) (ALARM_NOTIFY_EDIT, -1, funcinfo->func_data); break; case AN_RESPONSE_SNOOZE: snooze_timeout = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (an->snooze_time)); - (* an->func) (ALARM_NOTIFY_SNOOZE, snooze_timeout, an->func_data); + (* funcinfo->func) (ALARM_NOTIFY_SNOOZE, snooze_timeout, funcinfo->func_data); break; case GTK_RESPONSE_CLOSE: case GTK_RESPONSE_DELETE_EVENT: - (* an->func) (ALARM_NOTIFY_CLOSE, -1, an->func_data); + (* funcinfo->func) (ALARM_NOTIFY_CLOSE, -1, funcinfo->func_data); break; } + + return; } static void @@ -112,124 +159,203 @@ dialog_destroyed_cb (GtkWidget *dialog, gpointer user_data) } /** - * alarm_notify_dialog: - * @trigger: Trigger time for the alarm. - * @occur_start: Start of occurrence time for the event. - * @occur_end: End of occurrence time for the event. - * @vtype: Type of the component which corresponds to the alarm. - * @summary: Short summary of the appointment - * @description: Long description of the appointment - * @location: Location of the appointment - * @func: Function to be called when a dialog action is invoked. - * @func_data: Closure data for @func. - * - * Runs the alarm notification dialog. The specified @func will be used to - * notify the client about result of the actions in the dialog. + * notified_alarms_dialog_new: * - * Return value: a pointer to the dialog widget created or NULL if there is an error. + * Return value: a new dialog in which you can add alarm notifications **/ -GtkWidget * -alarm_notify_dialog (time_t trigger, time_t occur_start, time_t occur_end, - ECalComponentVType vtype, const char *summary, - const char *description, const char *location, - AlarmNotifyFunc func, gpointer func_data) +AlarmNotificationsDialog * +notified_alarms_dialog_new (void) { - AlarmNotify *an; GtkWidget *image; - icaltimezone *current_zone; - char *title; - char *start, *end; char *icon_path; GList *icon_list; - - g_return_val_if_fail (trigger != -1, NULL); - - /* Only VEVENTs or VTODOs can have alarms */ - g_return_val_if_fail (vtype == E_CAL_COMPONENT_EVENT || vtype == E_CAL_COMPONENT_TODO, NULL); - g_return_val_if_fail (summary != NULL, NULL); - g_return_val_if_fail (description != NULL, NULL); - g_return_val_if_fail (location != NULL, NULL); - g_return_val_if_fail (func != NULL, NULL); - - an = g_new0 (AlarmNotify, 1); - - an->func = func; - an->func_data = func_data; - + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + AlarmNotificationsDialog *na = NULL; + AlarmNotify *an = g_new0 (AlarmNotify, 1); + GtkTreeViewColumn *column = NULL; + GtkTreeSelection *selection = NULL; + GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new ( + N_ALARM_COLUMNS, + + G_TYPE_STRING, /* Display */ + G_TYPE_STRING, /* Summary */ + G_TYPE_STRING, /* Description */ + G_TYPE_STRING, /* Location */ + + G_TYPE_POINTER, /* Start */ + G_TYPE_POINTER, /* End */ + + G_TYPE_POINTER /* FuncInfo*/)); + an->xml = glade_xml_new (EVOLUTION_GLADEDIR "/alarm-notify.glade", NULL, NULL); if (!an->xml) { g_message ("alarm_notify_dialog(): Could not load the Glade XML file!"); g_free (an); return NULL; } - + an->dialog = glade_xml_get_widget (an->xml, "alarm-notify"); - an->title = glade_xml_get_widget (an->xml, "title-label"); an->snooze_time = glade_xml_get_widget (an->xml, "snooze-time"); an->minutes_label = glade_xml_get_widget (an->xml, "minutes-label"); an->description = glade_xml_get_widget (an->xml, "description-label"); an->location = glade_xml_get_widget (an->xml, "location-label"); - an->start = glade_xml_get_widget (an->xml, "start-label"); - an->end = glade_xml_get_widget (an->xml, "end-label"); + an->treeview = glade_xml_get_widget (an->xml, "appointments-treeview"); + an->scrolledwindow = glade_xml_get_widget (an->xml, "treeview-scrolledwindow"); - if (!(an->dialog && an->title && an->snooze_time - && an->description && an->location && an->start && an->end)) { + if (!(an->dialog && an->scrolledwindow && an->treeview && an->snooze_time + && an->description && an->location)) { g_message ("alarm_notify_dialog(): Could not find all widgets in Glade file!"); g_object_unref (an->xml); g_free (an); return NULL; } + gtk_tree_view_set_model (GTK_TREE_VIEW(an->treeview), model); + + column = gtk_tree_view_column_new_with_attributes (_("Start time"), + renderer, "text", ALARM_DISPLAY_COLUMN, NULL); + + gtk_tree_view_column_set_attributes (column, renderer, + "markup", ALARM_DISPLAY_COLUMN, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (an->treeview), column); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (an->treeview)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (tree_selection_changed_cb), an); + gtk_widget_realize (an->dialog); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (an->dialog)->vbox), 0); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (an->dialog)->action_area), 12); - - image = glade_xml_get_widget (an->xml, "alarm-image"); + image = glade_xml_get_widget (an->xml, "alarm-image"); icon_path = e_icon_factory_get_icon_filename ("stock_alarm", E_ICON_SIZE_DIALOG); gtk_image_set_from_file (GTK_IMAGE (image), icon_path); g_free (icon_path); + + g_signal_connect (G_OBJECT (an->dialog), "response", G_CALLBACK (dialog_response_cb), an); + g_signal_connect (G_OBJECT (an->dialog), "destroy", G_CALLBACK (dialog_destroyed_cb), an); + + if (!GTK_WIDGET_REALIZED (an->dialog)) + gtk_widget_realize (an->dialog); + icon_list = e_icon_factory_get_icon_list ("stock_alarm"); + if (icon_list) { + gtk_window_set_icon_list (GTK_WINDOW (an->dialog), icon_list); + g_list_foreach (icon_list, (GFunc) g_object_unref, NULL); + g_list_free (icon_list); + } + + /* Set callback for updating the snooze "minutes" label */ + g_signal_connect (G_OBJECT (an->snooze_time), "value_changed", + G_CALLBACK (an_update_minutes_label), an); + + + na = g_new0 (AlarmNotificationsDialog, 1); + + na->treeview = an->treeview; + na->dialog = an->dialog; + + return na; +} + + +/** + * add_alarm_to_notified_alarms_dialog: + * @na: Pointer to the dialog-info + * @trigger: Trigger time for the alarm. + * @occur_start: Start of occurrence time for the event. + * @occur_end: End of occurrence time for the event. + * @vtype: Type of the component which corresponds to the alarm. + * @summary: Short summary of the appointment + * @description: Long description of the appointment + * @location: Location of the appointment + * @func: Function to be called when a dialog action is invoked. + * @func_data: Closure data for @func. + * + * The specified @func will be used to notify the client about result of + * the actions in the dialog. + * + * Return value: the iter in the treeview of the dialog + **/ + +GtkTreeIter +add_alarm_to_notified_alarms_dialog (AlarmNotificationsDialog *na, time_t trigger, + time_t occur_start, time_t occur_end, + ECalComponentVType vtype, const char *summary, + const char *description, const char *location, + AlarmNotifyFunc func, gpointer func_data) +{ + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (na->treeview)); + AlarmFuncInfo *funcinfo = NULL; + gchar *to_display = NULL, *start, *end; + icaltimezone *current_zone; + + g_return_val_if_fail (trigger != -1, iter); - /* Title */ - - gtk_window_set_title (GTK_WINDOW (an->dialog), summary); - - /* Set the widget contents */ - - title = g_strdup_printf ("<big><b>%s</b></big>", summary); - gtk_label_set_markup (GTK_LABEL (an->title), title); - g_free (title); - - gtk_label_set_text (GTK_LABEL (an->description), description); - gtk_label_set_text (GTK_LABEL (an->location), location); - - /* Stringize the times */ + /* Only VEVENTs or VTODOs can have alarms */ + g_return_val_if_fail (vtype == E_CAL_COMPONENT_EVENT || vtype == E_CAL_COMPONENT_TODO, iter); + g_return_val_if_fail (summary != NULL, iter); + g_return_val_if_fail (description != NULL, iter); + g_return_val_if_fail (location != NULL, iter); + g_return_val_if_fail (func != NULL, iter); + + funcinfo = g_new0 (AlarmFuncInfo, 1); + funcinfo->func = func; + funcinfo->func_data = func_data; + + gtk_list_store_append (GTK_LIST_STORE(model), &iter); current_zone = config_data_get_timezone (); - start = timet_to_str_with_zone (occur_start, current_zone); - gtk_label_set_text (GTK_LABEL (an->start), start); - end = timet_to_str_with_zone (occur_end, current_zone); - gtk_label_set_text (GTK_LABEL (an->end), end); - - /* Set callback for updating the snooze "minutes" label */ - g_signal_connect (G_OBJECT (an->snooze_time), "value_changed", - G_CALLBACK (an_update_minutes_label), an); - /* Run! */ - - if (!GTK_WIDGET_REALIZED (an->dialog)) - gtk_widget_realize (an->dialog); + to_display = g_strdup_printf (_("<big><b>%s</b></big>\n%s until %s"), + summary, start, end); + g_free (start); + g_free (end); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, + ALARM_DISPLAY_COLUMN, to_display, -1); + g_free (to_display); + + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_SUMMARY_COLUMN, summary, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_DESCRIPTION_COLUMN, description, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_LOCATION_COLUMN, location, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_START_COLUMN, occur_start, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_END_COLUMN, occur_end, -1); + gtk_list_store_set (GTK_LIST_STORE(model), &iter, ALARM_FUNCINFO_COLUMN, funcinfo, -1); + + return iter; +} - icon_list = e_icon_factory_get_icon_list ("stock_alarm"); - if (icon_list) { - gtk_window_set_icon_list (GTK_WINDOW (an->dialog), icon_list); - g_list_foreach (icon_list, (GFunc) g_object_unref, NULL); - g_list_free (icon_list); +static void +tree_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + AlarmNotify *an = user_data; + gchar *summary, *description, *location; + time_t occur_start, occur_end; + + gtk_tree_model_get (model, &iter, ALARM_SUMMARY_COLUMN, &summary, -1); + gtk_tree_model_get (model, &iter, ALARM_DESCRIPTION_COLUMN, &description, -1); + gtk_tree_model_get (model, &iter, ALARM_LOCATION_COLUMN, &location, -1); + gtk_tree_model_get (model, &iter, ALARM_START_COLUMN, &occur_start, -1); + gtk_tree_model_get (model, &iter, ALARM_END_COLUMN, &occur_end, -1);\ + gtk_tree_model_get (model, &iter, ALARM_FUNCINFO_COLUMN, &an->cur_funcinfo, -1); + + fill_in_labels (an, summary, description, location, occur_start, occur_end); } +} - g_signal_connect (G_OBJECT (an->dialog), "response", G_CALLBACK (dialog_response_cb), an); - g_signal_connect (G_OBJECT (an->dialog), "destroy", G_CALLBACK (dialog_destroyed_cb), an); - gtk_widget_show (an->dialog); - return an->dialog; + +static void +fill_in_labels (AlarmNotify *an, const gchar *summary, const gchar *description, + const gchar *location, time_t occur_start, time_t occur_end) +{ + gtk_label_set_text (GTK_LABEL (an->description), description); + gtk_label_set_text (GTK_LABEL (an->location), location); } diff --git a/calendar/gui/alarm-notify/alarm-notify-dialog.h b/calendar/gui/alarm-notify/alarm-notify-dialog.h index cf01f76af9..7c6b65870f 100644 --- a/calendar/gui/alarm-notify/alarm-notify-dialog.h +++ b/calendar/gui/alarm-notify/alarm-notify-dialog.h @@ -25,6 +25,9 @@ #include <glib.h> #include <libecal/e-cal-component.h> #include <gtk/gtkwidget.h> +#include <gtk/gtktreemodel.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtkliststore.h> @@ -34,12 +37,25 @@ typedef enum { ALARM_NOTIFY_EDIT } AlarmNotifyResult; +typedef struct _AlarmNotificationsDialog AlarmNotificationsDialog; +struct _AlarmNotificationsDialog +{ + GtkWidget *dialog; + GtkWidget *treeview; +}; + typedef void (* AlarmNotifyFunc) (AlarmNotifyResult result, int snooze_mins, gpointer data); -GtkWidget *alarm_notify_dialog (time_t trigger, time_t occur_start, time_t occur_end, +AlarmNotificationsDialog * +notified_alarms_dialog_new (void); + +GtkTreeIter +add_alarm_to_notified_alarms_dialog (AlarmNotificationsDialog *na, time_t trigger, + time_t occur_start, time_t occur_end, ECalComponentVType vtype, const char *summary, const char *description, const char *location, AlarmNotifyFunc func, gpointer func_data); + #endif diff --git a/calendar/gui/alarm-notify/alarm-notify.c b/calendar/gui/alarm-notify/alarm-notify.c index 60f9c3fded..51aac05cdd 100644 --- a/calendar/gui/alarm-notify/alarm-notify.c +++ b/calendar/gui/alarm-notify/alarm-notify.c @@ -285,7 +285,7 @@ AlarmNotify * alarm_notify_new (void) { AlarmNotify *an; - + an = g_object_new (TYPE_ALARM_NOTIFY, "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL), NULL); diff --git a/calendar/gui/alarm-notify/alarm-notify.glade b/calendar/gui/alarm-notify/alarm-notify.glade index 0302458aa3..c459f789e1 100644 --- a/calendar/gui/alarm-notify/alarm-notify.glade +++ b/calendar/gui/alarm-notify/alarm-notify.glade @@ -5,7 +5,7 @@ <widget class="GtkDialog" id="alarm-notify"> <property name="visible">True</property> - <property name="title" translatable="yes">Appointment</property> + <property name="title" translatable="yes">Appointments</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> <property name="modal">False</property> @@ -18,6 +18,7 @@ <property name="skip_pager_hint">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> <property name="has_separator">False</property> <child internal-child="vbox"> @@ -32,148 +33,6 @@ <property name="layout_style">GTK_BUTTONBOX_END</property> <child> - <widget class="GtkButton" id="button3"> - <property name="visible">True</property> - <property name="can_default">True</property> - <property name="can_focus">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="response_id">0</property> - - <child> - <widget class="GtkAlignment" id="alignment2"> - <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</property> - - <child> - <widget class="GtkHBox" id="hbox6"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> - - <child> - <widget class="GtkImage" id="image4"> - <property name="visible">True</property> - <property name="stock">gtk-properties</property> - <property name="icon_size">4</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label16"> - <property name="visible">True</property> - <property name="label" translatable="yes">_Edit</property> - <property name="use_underline">True</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - </widget> - </child> - - <child> - <widget class="GtkButton" id="button4"> - <property name="visible">True</property> - <property name="can_default">True</property> - <property name="can_focus">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="response_id">1</property> - - <child> - <widget class="GtkAlignment" id="alignment3"> - <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</property> - - <child> - <widget class="GtkHBox" id="hbox7"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> - - <child> - <widget class="GtkImage" id="image5"> - <property name="visible">True</property> - <property name="stock">gtk-refresh</property> - <property name="icon_size">4</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label17"> - <property name="visible">True</property> - <property name="label" translatable="yes">_Snooze</property> - <property name="use_underline">True</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - </widget> - </child> - - <child> <widget class="GtkButton" id="button5"> <property name="visible">True</property> <property name="can_default">True</property> @@ -214,7 +73,7 @@ <packing> <property name="padding">0</property> <property name="expand">False</property> - <property name="fill">False</property> + <property name="fill">True</property> </packing> </child> @@ -225,293 +84,408 @@ <property name="spacing">12</property> <child> - <widget class="GtkLabel" id="title-label"> + <widget class="GtkScrolledWindow" id="treeview-scrolledwindow"> + <property name="width_request">375</property> <property name="visible">True</property> - <property name="label" translatable="yes">Appointment Title</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="appointments-treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> </widget> <packing> <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> <child> - <widget class="GtkVBox" id="vbox2"> + <widget class="GtkHBox" id="hbox8"> <property name="visible">True</property> <property name="homogeneous">False</property> - <property name="spacing">12</property> - - <child> - <widget class="GtkLabel" id="description-label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">description of appointment</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">True</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> + <property name="spacing">0</property> <child> - <widget class="GtkTable" id="table1"> + <widget class="GtkVBox" id="vbox2"> <property name="visible">True</property> - <property name="n_rows">4</property> - <property name="n_columns">2</property> <property name="homogeneous">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">6</property> - - <child> - <widget class="GtkLabel" id="label5"> - <property name="visible">True</property> - <property name="label" translatable="yes">Location:</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label6"> - <property name="visible">True</property> - <property name="label" translatable="yes">Start time:</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> + <property name="spacing">12</property> <child> - <widget class="GtkLabel" id="label7"> - <property name="visible">True</property> - <property name="label" translatable="yes">End time:</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="location-label"> - <property name="visible">True</property> - <property name="label" translatable="yes">location</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="start-label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">start-time</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="end-label"> + <widget class="GtkLabel" id="description-label"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="label" translatable="yes">end-time</property> + <property name="label" translatable="yes">description of appointment</property> <property name="use_underline">False</property> - <property name="use_markup">False</property> + <property name="use_markup">True</property> <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> + <property name="wrap">True</property> <property name="selectable">True</property> <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">fill</property> - <property name="y_options"></property> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> </packing> </child> <child> - <widget class="GtkHBox" id="hbox5"> + <widget class="GtkTable" id="table1"> <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> <property name="homogeneous">False</property> - <property name="spacing">6</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + + <child> + <widget class="GtkLabel" id="label11"> + <property name="visible">True</property> + <property name="label" translatable="yes">Snooze _time:</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="mnemonic_widget">snooze-time</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkSpinButton" id="snooze-time"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">5 1 60 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="minutes-label"> + <property name="visible">True</property> + <property name="label" translatable="yes">minutes</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">fill</property> + </packing> + </child> <child> - <widget class="GtkSpinButton" id="snooze-time"> + <widget class="GtkLabel" id="location-label"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="climb_rate">1</property> - <property name="digits">0</property> - <property name="numeric">False</property> - <property name="update_policy">GTK_UPDATE_ALWAYS</property> - <property name="snap_to_ticks">False</property> + <property name="label" translatable="yes">location of appointment</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> - <property name="adjustment">5 1 60 1 10 10</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> </widget> <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="minutes-label"> + <widget class="GtkLabel" id="label18"> <property name="visible">True</property> - <property name="label" translatable="yes">minutes</property> + <property name="label" translatable="yes">Location:</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> - <property name="xalign">0.5</property> + <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> </widget> <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> </packing> </child> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">fill</property> - <property name="y_options">fill</property> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> <child> - <widget class="GtkLabel" id="label11"> + <widget class="GtkButton" id="button4"> <property name="visible">True</property> - <property name="label" translatable="yes">Snooze _time:</property> - <property name="use_underline">True</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="mnemonic_widget">snooze-time</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image5"> + <property name="visible">True</property> + <property name="stock">gtk-refresh</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label17"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Snooze</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="button3"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox6"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-properties</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label16"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Edit</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> </widget> <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">fill</property> - <property name="y_options"></property> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> </packing> </child> </widget> <packing> <property name="padding">0</property> - <property name="expand">True</property> + <property name="expand">False</property> <property name="fill">True</property> </packing> </child> diff --git a/calendar/gui/alarm-notify/alarm-queue.c b/calendar/gui/alarm-notify/alarm-queue.c index 9fc55e5869..9d2c57db26 100644 --- a/calendar/gui/alarm-notify/alarm-queue.c +++ b/calendar/gui/alarm-notify/alarm-queue.c @@ -56,6 +56,9 @@ +/* The dialog with alarm nofications */ +static AlarmNotificationsDialog *alarm_notifications_dialog = NULL; + /* Whether the queueing system has been initialized */ static gboolean alarm_queue_inited; @@ -123,6 +126,8 @@ typedef struct { /* Alarm ID for the midnight refresh function */ static gpointer midnight_refresh_id = NULL; +static void +remove_client_alarms (ClientAlarms *ca); static void display_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id, gboolean use_description); static void audio_notification (time_t trigger, CompQueuedAlarms *cqa, gpointer alarm_id); @@ -723,7 +728,7 @@ typedef struct { ECalView *query; GtkWidget *tray_icon; GtkWidget *image; - GtkWidget *alarm_dialog; + GtkTreeIter iter; } TrayIconData; static void @@ -756,7 +761,7 @@ static void notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) { TrayIconData *tray_data = data; - + g_signal_handlers_disconnect_matched (tray_data->query, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, on_dialog_objs_removed_cb, NULL); @@ -764,39 +769,86 @@ notify_dialog_cb (AlarmNotifyResult result, int snooze_mins, gpointer data) case ALARM_NOTIFY_SNOOZE: create_snooze (tray_data->cqa, tray_data->alarm_id, snooze_mins); tray_data->cqa = NULL; + + if (alarm_notifications_dialog) { + GtkTreeSelection *selection = + gtk_tree_view_get_selection ( + GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + GtkTreeIter iter; + GtkTreeModel *model = NULL; + + /* We can also use tray_data->iter */ + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + if (!gtk_tree_model_get_iter_first (model, &iter)) { + /* We removed the last one */ + gtk_widget_destroy (alarm_notifications_dialog->dialog); + g_free (alarm_notifications_dialog); + alarm_notifications_dialog = NULL; + } else { + /* Select the first */ + gtk_tree_selection_select_iter (selection, &iter); + } + } + + } + break; case ALARM_NOTIFY_EDIT: edit_component (tray_data->client, tray_data->comp); + + gtk_widget_destroy (alarm_notifications_dialog->dialog); + g_free (alarm_notifications_dialog); + alarm_notifications_dialog = NULL; + + gtk_widget_destroy (tray_data->tray_icon); + break; case ALARM_NOTIFY_CLOSE: - /* Do nothing */ + + + if (alarm_notifications_dialog) { + GtkTreeIter iter; + GtkTreeModel *model = + gtk_tree_view_get_model ( + GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + gboolean valid = gtk_tree_model_get_iter_first (model, &iter); + + /* Maybe we should warn about this first? */ + while (valid) { + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + valid = gtk_tree_model_iter_next (model, &iter); + } + + gtk_widget_destroy (alarm_notifications_dialog->dialog); + g_free (alarm_notifications_dialog); + alarm_notifications_dialog = NULL; + } + + gtk_widget_destroy (tray_data->tray_icon); + break; default: g_assert_not_reached (); } - gtk_widget_destroy (tray_data->tray_icon); + return; } static gint tray_icon_destroyed_cb (GtkWidget *tray, gpointer user_data) { TrayIconData *tray_data = user_data; - + g_signal_handlers_disconnect_matched (tray_data->query, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, on_dialog_objs_removed_cb, NULL); if (tray_data->cqa != NULL) remove_queued_alarm (tray_data->cqa, tray_data->alarm_id, TRUE, TRUE); - if (tray_data->alarm_dialog != NULL) { - gtk_widget_destroy (tray_data->alarm_dialog); - tray_data->alarm_dialog = NULL; - } - if (tray_data->summary != NULL) { g_free (tray_data->summary); tray_data->summary = NULL; @@ -830,11 +882,28 @@ static gboolean open_alarm_dialog (TrayIconData *tray_data) { QueuedAlarm *qa; - + qa = lookup_queued_alarm (tray_data->cqa, tray_data->alarm_id); if (qa) { + gtk_widget_hide (tray_data->tray_icon); - tray_data->alarm_dialog = alarm_notify_dialog (tray_data->trigger, + + if (!alarm_notifications_dialog) + alarm_notifications_dialog = notified_alarms_dialog_new (); + + if (alarm_notifications_dialog) { + + GtkTreeSelection *selection = NULL; + GtkTreeModel *model = NULL; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (alarm_notifications_dialog->treeview)); + model = gtk_tree_view_get_model ( + GTK_TREE_VIEW(alarm_notifications_dialog->treeview)); + + tray_data->iter = add_alarm_to_notified_alarms_dialog ( + alarm_notifications_dialog, + tray_data->trigger, qa->instance->occur_start, qa->instance->occur_end, e_cal_component_get_vtype (tray_data->comp), @@ -842,6 +911,11 @@ open_alarm_dialog (TrayIconData *tray_data) tray_data->description, tray_data->location, notify_dialog_cb, tray_data); + + gtk_tree_selection_select_iter (selection, &tray_data->iter); + + } + } return TRUE; @@ -1037,7 +1111,7 @@ display_notification (time_t trigger, CompQueuedAlarms *cqa, if (!config_data_get_notify_with_tray ()) { tray_data->blink_id = -1; open_alarm_dialog (tray_data); - gtk_window_stick (GTK_WINDOW (tray_data->alarm_dialog)); + gtk_window_stick (GTK_WINDOW (alarm_notifications_dialog->dialog)); } else { tray_data->blink_id = g_timeout_add (500, tray_icon_blink_cb, tray_data); gtk_widget_show (tray_icon); |