diff options
-rw-r--r-- | calendar/ChangeLog | 45 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.c | 57 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.h | 3 | ||||
-rw-r--r-- | calendar/gui/dialogs/comp-editor-util.c | 248 | ||||
-rw-r--r-- | calendar/gui/dialogs/comp-editor-util.h | 16 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.c | 103 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.glade | 13 | ||||
-rw-r--r-- | calendar/gui/dialogs/meeting-page.c | 4 | ||||
-rw-r--r-- | calendar/gui/dialogs/task-page.c | 105 | ||||
-rw-r--r-- | calendar/gui/dialogs/task-page.glade | 15 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 61 | ||||
-rw-r--r-- | calendar/gui/e-week-view-event-item.c | 33 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 76 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 37 |
14 files changed, 747 insertions, 69 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 49eed5cb01..47f1959557 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,48 @@ +2001-08-14 Damon Chaplin <damon@ximian.com> + + * gui/dialogs/task-page.c: + * gui/dialogs/event-page.c: added support for the Contacts field. + Note that I'm not sure what we should put in the iCalendar CONTACT + properties. Currently we put "name <email>", but it isn't recognized + as a contact when we reopen the dialog, so we may need more info here. + Also we currently use a simple parser to parse the above format, and + we should maybe use some camel function. + + * gui/dialogs/task-page.glade: + * gui/dialogs/event-page.glade: replaced the GtkEntry fields for the + Contacts with a GtkEventBox which we put the BonoboControl in at + runtime. + + * gui/dialogs/meeting-page.c (invite_entry_changed): added FIXMEs + since it doesn't seem to be freeing the EDestination stuff. JP? + + * gui/dialogs/comp-editor-util.c: added bunch of utility functions to + handle the Contacts field in the main Event and Task pages. + + * gui/gnome-cal.c: added visible_start and visible_end fields, so we + only emit the 'dates-shown-changed' signal when really necessary. + Currently changing the folder title bar label results in a complete + redraw of the Evolution window (silly GtkLabel queueing a resize), + so we want to avoid that as much as possible. + (gnome_calendar_new_appointment_for): only move the event's end time + to the end of the day if it is not already 00:00:00. + + * gui/e-week-view-event-item.c: + * gui/e-week-view.c: + * gui/e-day-view.c: added support for double-clicking on an event to + open it, and for double-clicking on the background to create a new + event. There is still a minor problem to sort out, but it basically + works. + + * cal-util/cal-component.c: added support for CONTACT properties, + mainly by copying the code for COMMENT properties which are exactly + the same type. + + * gui/e-day-view.c (e_day_view_realize): use the same color for the + top canvas background as the shortcut bar, to make it look a little + nicer (I think). Although we still have the theme problem with + hard-coded colors. + 2001-08-14 Federico Mena Quintero <federico@ximian.com> * gui/e-calendar-table.etspec: Made the click-to-add message diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c index 7bacfb5432..c7800f0456 100644 --- a/calendar/cal-util/cal-component.c +++ b/calendar/cal-util/cal-component.c @@ -71,6 +71,9 @@ struct _CalComponentPrivate { GSList *comment_list; /* list of struct text */ icalproperty *completed; + + GSList *contact_list; /* list of struct text */ + icalproperty *created; GSList *description_list; /* list of struct text */ @@ -286,6 +289,7 @@ free_icalcomponent (CalComponent *comp) priv->classification = NULL; priv->comment_list = NULL; priv->completed = NULL; + priv->contact_list = NULL; priv->created = NULL; priv->description_list = free_slist (priv->description_list); @@ -599,6 +603,10 @@ scan_property (CalComponent *comp, icalproperty *prop) priv->completed = prop; break; + case ICAL_CONTACT_PROPERTY: + scan_text (comp, &priv->contact_list, prop); + break; + case ICAL_CREATED_PROPERTY: priv->created = prop; break; @@ -1617,6 +1625,55 @@ cal_component_set_comment_list (CalComponent *comp, GSList *text_list) set_text_list (comp, icalproperty_new_comment, &priv->comment_list, text_list); } +/** + * cal_component_get_contact_list: + * @comp: A calendar component object. + * @text_list: Return value for the contact properties and their parameters, as + * a list of #CalComponentText structures. This should be freed using the + * cal_component_free_text_list() function. + * + * Queries the contact of a calendar component object. The contact property can + * appear several times inside a calendar component, and so a list of + * #CalComponentText is returned. + **/ +void +cal_component_get_contact_list (CalComponent *comp, GSList **text_list) +{ + CalComponentPrivate *priv; + + g_return_if_fail (comp != NULL); + g_return_if_fail (IS_CAL_COMPONENT (comp)); + g_return_if_fail (text_list != NULL); + + priv = comp->priv; + g_return_if_fail (priv->icalcomp != NULL); + + get_text_list (priv->contact_list, icalproperty_get_contact, text_list); +} + +/** + * cal_component_set_contact_list: + * @comp: A calendar component object. + * @text_list: List of #CalComponentText structures. + * + * Sets the contact of a calendar component object. The contact property can + * appear several times inside a calendar component, and so a list of + * #CalComponentText structures is used. + **/ +void +cal_component_set_contact_list (CalComponent *comp, GSList *text_list) +{ + CalComponentPrivate *priv; + + g_return_if_fail (comp != NULL); + g_return_if_fail (IS_CAL_COMPONENT (comp)); + + priv = comp->priv; + g_return_if_fail (priv->icalcomp != NULL); + + set_text_list (comp, icalproperty_new_contact, &priv->contact_list, text_list); +} + /* Gets a struct icaltimetype value */ static void get_icaltimetype (icalproperty *prop, diff --git a/calendar/cal-util/cal-component.h b/calendar/cal-util/cal-component.h index e1f4022b91..b0545397b4 100644 --- a/calendar/cal-util/cal-component.h +++ b/calendar/cal-util/cal-component.h @@ -257,6 +257,9 @@ void cal_component_set_comment_list (CalComponent *comp, GSList *text_list); void cal_component_get_completed (CalComponent *comp, struct icaltimetype **t); void cal_component_set_completed (CalComponent *comp, struct icaltimetype *t); +void cal_component_get_contact_list (CalComponent *comp, GSList **text_list); +void cal_component_set_contact_list (CalComponent *comp, GSList *text_list); + void cal_component_get_created (CalComponent *comp, struct icaltimetype **t); void cal_component_set_created (CalComponent *comp, struct icaltimetype *t); diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c index 0e4384dca4..8ef7aebbab 100644 --- a/calendar/gui/dialogs/comp-editor-util.c +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -23,11 +23,16 @@ #include <config.h> #endif +#include <ctype.h> #include <string.h> #include <ical.h> #include <glib.h> #include <libgnome/gnome-defs.h> #include <libgnome/gnome-i18n.h> +#include <liboaf/liboaf.h> +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-widget.h> +#include <e-destination.h> #include <e-util/e-time-utils.h> #include <cal-util/timeutil.h> #include "../calendar-config.h" @@ -224,3 +229,246 @@ comp_editor_get_current_time (GtkObject *object, gpointer data) return tmp_tm; } + + + +/* + * These are utility functions to handle the SelectNames control we use + * for the contacts field, and its related dialog. + */ + +#define SELECT_NAMES_OAFID "OAFIID:GNOME_Evolution_Addressbook_SelectNames" + +GNOME_Evolution_Addressbook_SelectNames +comp_editor_create_contacts_component (void) +{ + GNOME_Evolution_Addressbook_SelectNames corba_select_names; + CORBA_Environment ev; + + CORBA_exception_init (&ev); + corba_select_names = oaf_activate_from_id (SELECT_NAMES_OAFID, 0, + NULL, &ev); + + /* OAF seems to be broken -- it can return a CORBA_OBJECT_NIL without + raising an exception in `ev'. */ + if (ev._major != CORBA_NO_EXCEPTION + || corba_select_names == CORBA_OBJECT_NIL) { + g_warning ("Cannot activate -- %s", SELECT_NAMES_OAFID); + CORBA_exception_free (&ev); + return CORBA_OBJECT_NIL; + } + + CORBA_exception_free (&ev); + + return corba_select_names; +} + + +GtkWidget * +comp_editor_create_contacts_control (GNOME_Evolution_Addressbook_SelectNames corba_select_names) +{ + Bonobo_Control corba_control; + GtkWidget *control_widget; + CORBA_Environment ev; + char *name = _("Contacts"); + + CORBA_exception_init (&ev); + + GNOME_Evolution_Addressbook_SelectNames_addSection ( + corba_select_names, name, name, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + CORBA_exception_free (&ev); + return NULL; + } + + corba_control = + GNOME_Evolution_Addressbook_SelectNames_getEntryBySection ( + corba_select_names, name, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + CORBA_exception_free (&ev); + return NULL; + } + + CORBA_exception_free (&ev); + + control_widget = bonobo_widget_new_control_from_objref ( + corba_control, CORBA_OBJECT_NIL); + + gtk_widget_show (control_widget); + + return control_widget; +} + + +Bonobo_EventSource_ListenerId +comp_editor_connect_contacts_changed (GtkWidget *contacts_entry, + BonoboListenerCallbackFn changed_cb, + gpointer changed_cb_data) +{ + BonoboControlFrame *cf; + Bonobo_PropertyBag pb = CORBA_OBJECT_NIL; + + cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (contacts_entry)); + pb = bonobo_control_frame_get_control_property_bag (cf, NULL); + + return bonobo_event_source_client_add_listener ( + pb, changed_cb, + "Bonobo/Property:change:entry_changed", + NULL, changed_cb_data); +} + + +void +comp_editor_show_contacts_dialog (GNOME_Evolution_Addressbook_SelectNames corba_select_names) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + GNOME_Evolution_Addressbook_SelectNames_activateDialog ( + corba_select_names, _("Contacts"), &ev); + CORBA_exception_free (&ev); +} + + +/* A simple 'name <email>' parser. + FIXME: Should probably use camel functions or something. */ +static void +parse_contact_string (const char *value, char **name, char **email) +{ + char *lbracket, *rbracket, *name_end, *tmp_name, *tmp_email; + + if (!value) { + *name = g_strdup (""); + *email = g_strdup (""); + return; + } + + lbracket = strchr (value, '<'); + rbracket = strchr (value, '>'); + + if (!lbracket || !rbracket || rbracket < lbracket) { + *name = g_strdup (value); + *email = g_strdup (""); + return; + } + + name_end = lbracket - 1; + while (name_end > value && isspace (*name_end)) + name_end--; + + tmp_name = g_malloc (name_end - value + 2); + strncpy (tmp_name, value, name_end - value + 1); + tmp_name[name_end - value + 1] = '\0'; + *name = tmp_name; + + tmp_email = g_malloc (rbracket - lbracket); + strncpy (tmp_email, lbracket + 1, rbracket - lbracket - 1); + tmp_email[rbracket - lbracket - 1] = '\0'; + *email = tmp_email; + + g_print ("Parsed: %s\n Name:'%s'\nEmail:'%s'\n", + value, *name, *email); +} + + +void +comp_editor_contacts_to_widget (GtkWidget *contacts_entry, + CalComponent *comp) +{ + GPtrArray *dest_array; + EDestination *dest; + GSList *contact_list, *elem; + char *contacts_string; + int i; + + cal_component_get_contact_list (comp, &contact_list); + dest_array = g_ptr_array_new (); + for (elem = contact_list; elem; elem = elem->next) { + CalComponentText *t = elem->data; + char *name, *email; + + parse_contact_string (t->value, &name, &email); + + dest = e_destination_new (); + e_destination_set_name (dest, name); + e_destination_set_email (dest, email); + g_ptr_array_add (dest_array, dest); + g_free (name); + g_free (email); + } + cal_component_free_text_list (contact_list); + + /* we need destv to be NULL terminated */ + g_ptr_array_add (dest_array, NULL); + + contacts_string = e_destination_exportv ((EDestination**) dest_array->pdata); + g_print ("Destinations: %s\n", contacts_string); + + bonobo_widget_set_property (BONOBO_WIDGET (contacts_entry), + "destinations", contacts_string, NULL); + + g_free (contacts_string); + + /* We free all dest_array except the last NULL we added. */ + for (i = 0; i < dest_array->len - 1; i++) { + dest = g_ptr_array_index (dest_array, i); + gtk_object_unref (GTK_OBJECT (dest)); + } + g_ptr_array_free (dest_array, TRUE); +} + + +void +comp_editor_contacts_to_component (GtkWidget *contacts_entry, + CalComponent *comp) +{ + EDestination **contact_destv; + GSList *contact_list = NULL, *elem; + char *contacts_string = NULL; + CalComponentText *t; + const char *name, *email; + int i; + + bonobo_widget_get_property (BONOBO_WIDGET (contacts_entry), + "destinations", &contacts_string, NULL); + g_print ("Contacts string: %s\n", contacts_string); + + contact_destv = e_destination_importv (contacts_string); + if (contact_destv) { + for (i = 0; contact_destv[i] != NULL; i++) { + name = e_destination_get_name (contact_destv[i]); + email = e_destination_get_email (contact_destv[i]); + + t = g_new0 (CalComponentText, 1); + t->altrep = NULL; + + /* If both name and email are given, use the standard + 'name <email>' form, otherwise use just the name + or the email address. + FIXME: I'm not sure this is correct syntax etc. */ + if (name && name[0] && email && email[0]) + t->value = g_strdup_printf ("%s <%s>", + name, email); + else if (name && name[0]) + t->value = g_strdup (name); + else + t->value = g_strdup (email); + + contact_list = g_slist_prepend (contact_list, t); + + gtk_object_unref (GTK_OBJECT (contact_destv[i])); + } + } + g_free (contact_destv); + + contact_list = g_slist_reverse (contact_list); + cal_component_set_contact_list (comp, contact_list); + + for (elem = contact_list; elem; elem = elem->next) { + t = elem->data; + g_free ((char*)t->value); + g_free (t); + } + g_slist_free (contact_list); +} diff --git a/calendar/gui/dialogs/comp-editor-util.h b/calendar/gui/dialogs/comp-editor-util.h index 4e8e344731..45c45a72a3 100644 --- a/calendar/gui/dialogs/comp-editor-util.h +++ b/calendar/gui/dialogs/comp-editor-util.h @@ -23,6 +23,8 @@ #define _COMP_EDITOR_UTIL_H_ #include <gtk/gtkwidget.h> +#include <bonobo/bonobo-control.h> +#include "Evolution-Addressbook-SelectNames.h" #include "comp-editor-page.h" void comp_editor_dates (CompEditorPageDates *date, CalComponent *comp); @@ -32,4 +34,18 @@ GtkWidget *comp_editor_new_date_edit (gboolean show_date, gboolean show_time); struct tm comp_editor_get_current_time (GtkObject *object, gpointer data); + +GNOME_Evolution_Addressbook_SelectNames comp_editor_create_contacts_component (void); +GtkWidget * comp_editor_create_contacts_control (GNOME_Evolution_Addressbook_SelectNames corba_select_names); +Bonobo_EventSource_ListenerId comp_editor_connect_contacts_changed (GtkWidget *contacts_entry, + BonoboListenerCallbackFn changed_cb, + gpointer changed_cb_data); +void comp_editor_show_contacts_dialog (GNOME_Evolution_Addressbook_SelectNames corba_select_names); + +void comp_editor_contacts_to_widget (GtkWidget *contacts_entry, + CalComponent *comp); +void comp_editor_contacts_to_component (GtkWidget *contacts_entry, + CalComponent *comp); + + #endif diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index bae084d526..a3947b1cba 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -69,7 +69,7 @@ struct _EventPagePrivate { GtkWidget *show_time_as_busy; GtkWidget *contacts_btn; - GtkWidget *contacts; + GtkWidget *contacts_box; GtkWidget *categories_btn; GtkWidget *categories; @@ -80,6 +80,11 @@ struct _EventPagePrivate { start timezone is then changed, we updated the end timezone to the same value, since 99% of events start and end in one timezone. */ gboolean sync_timezones; + + /* The Corba component for selecting contacts, and the entry field + which we place in the dialog. */ + GNOME_Evolution_Addressbook_SelectNames corba_select_names; + GtkWidget *contacts_entry; }; @@ -178,12 +183,15 @@ event_page_init (EventPage *epage) priv->show_time_as_free = NULL; priv->show_time_as_busy = NULL; priv->contacts_btn = NULL; - priv->contacts = NULL; + priv->contacts_box = NULL; priv->categories_btn = NULL; priv->categories = NULL; priv->updating = FALSE; priv->sync_timezones = FALSE; + + priv->corba_select_names = CORBA_OBJECT_NIL; + priv->contacts_entry = NULL; } /* Destroy handler for the event page */ @@ -199,6 +207,14 @@ event_page_destroy (GtkObject *object) epage = EVENT_PAGE (object); priv = epage->priv; + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + CORBA_Environment ev; + + CORBA_exception_init (&ev); + CORBA_Object_release (priv->corba_select_names, &ev); + CORBA_exception_free (&ev); + } + if (priv->xml) { gtk_object_unref (GTK_OBJECT (priv->xml)); priv->xml = NULL; @@ -324,6 +340,27 @@ clear_widgets (EventPage *epage) e_dialog_editable_set (priv->categories, NULL); } + +static void +contacts_changed_cb (BonoboListener *listener, + char *event_name, + CORBA_any *arg, + CORBA_Environment *ev, + gpointer data) +{ + EventPage *epage; + EventPagePrivate *priv; + + epage = EVENT_PAGE (data); + priv = epage->priv; + + g_print ("In contacts_changed_cb\n"); + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (epage)); +} + + /* fill_widgets handler for the event page */ static void event_page_fill_widgets (CompEditorPage *page, CalComponent *comp) @@ -488,6 +525,17 @@ event_page_fill_widgets (CompEditorPage *page, CalComponent *comp) cal_component_get_categories (comp, &categories); e_dialog_editable_set (priv->categories, categories); + /* Contacts */ + comp_editor_contacts_to_widget (priv->contacts_entry, comp); + + /* We connect the contacts changed signal here, as we have to be a bit + more careful with it due to the use or Corba. The priv->updating + flag won't work as we won't get the changed event immediately. + FIXME: Unfortunately this doesn't work either. We never get the + changed event now. */ + comp_editor_connect_contacts_changed (priv->contacts_entry, + contacts_changed_cb, epage); + priv->updating = FALSE; } @@ -612,6 +660,10 @@ event_page_fill_component (CompEditorPage *page, CalComponent *comp) transparency = e_dialog_radio_get (priv->show_time_as_free, transparency_map); cal_component_set_transparency (comp, transparency); + + /* Contacts */ + + comp_editor_contacts_to_component (priv->contacts_entry, comp); } /* set_summary handler for the event page */ @@ -672,7 +724,7 @@ get_widgets (EventPage *epage) priv->show_time_as_busy = GW ("show-time-as-busy"); priv->contacts_btn = GW ("contacts-button"); - priv->contacts = GW ("contacts"); + priv->contacts_box = GW ("contacts-box"); priv->categories_btn = GW ("categories-button"); priv->categories = GW ("categories"); @@ -692,7 +744,7 @@ get_widgets (EventPage *epage) && priv->show_time_as_free && priv->show_time_as_busy && priv->contacts_btn - && priv->contacts + && priv->contacts_box && priv->categories_btn && priv->categories); } @@ -989,6 +1041,22 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) &dates); } +/* Callback used when the contacts button is clicked; we must bring up the + * contact list dialog. + */ +static void +contacts_clicked_cb (GtkWidget *button, gpointer data) +{ + EventPage *epage; + EventPagePrivate *priv; + + epage = EVENT_PAGE (data); + priv = epage->priv; + + g_print ("In contacts_clicked_cb\n"); + comp_editor_show_contacts_dialog (priv->corba_select_names); +} + /* Callback used when the categories button is clicked; we must bring up the * category list dialog. */ @@ -1021,7 +1089,7 @@ field_changed_cb (GtkWidget *widget, gpointer data) } /* Hooks the widget signals */ -static void +static gboolean init_widgets (EventPage *epage) { EventPagePrivate *priv; @@ -1058,6 +1126,10 @@ init_widgets (EventPage *epage) gtk_signal_connect (GTK_OBJECT (priv->all_day_event), "toggled", GTK_SIGNAL_FUNC (all_day_event_toggled_cb), epage); + /* Contacts button */ + gtk_signal_connect (GTK_OBJECT (priv->contacts_btn), "clicked", + GTK_SIGNAL_FUNC (contacts_clicked_cb), epage); + /* Categories button */ gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", GTK_SIGNAL_FUNC (categories_clicked_cb), epage); @@ -1098,10 +1170,19 @@ init_widgets (EventPage *epage) gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", GTK_SIGNAL_FUNC (field_changed_cb), epage); - /* FIXME: we do not support these fields yet, so we disable them */ + /* Create the contacts entry, a corba control from the address book. */ + priv->corba_select_names = comp_editor_create_contacts_component (); + if (priv->corba_select_names == CORBA_OBJECT_NIL) + return FALSE; - gtk_widget_set_sensitive (priv->contacts_btn, FALSE); - gtk_widget_set_sensitive (priv->contacts, FALSE); + priv->contacts_entry = comp_editor_create_contacts_control (priv->corba_select_names); + if (priv->contacts_entry == NULL) + return FALSE; + + gtk_container_add (GTK_CONTAINER (priv->contacts_box), + priv->contacts_entry); + + return TRUE; } @@ -1136,7 +1217,11 @@ event_page_construct (EventPage *epage) return NULL; } - init_widgets (epage); + if (!init_widgets (epage)) { + g_message ("event_page_construct(): " + "Could not initialize the widgets!"); + return NULL; + } return epage; } diff --git a/calendar/gui/dialogs/event-page.glade b/calendar/gui/dialogs/event-page.glade index 380b99302f..0c3abcfc5f 100644 --- a/calendar/gui/dialogs/event-page.glade +++ b/calendar/gui/dialogs/event-page.glade @@ -487,18 +487,17 @@ </widget> <widget> - <class>GtkEntry</class> - <name>contacts</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> + <class>GtkEventBox</class> + <name>contacts-box</name> <child> <padding>0</padding> <expand>True</expand> <fill>True</fill> </child> + + <widget> + <class>Placeholder</class> + </widget> </widget> <widget> diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c index 161ae07255..529ea63c6e 100644 --- a/calendar/gui/dialogs/meeting-page.c +++ b/calendar/gui/dialogs/meeting-page.c @@ -810,8 +810,12 @@ invite_entry_changed (BonoboListener *listener, row_cnt = row_count (priv->model, mpage) - 1; e_table_model_row_inserted (priv->model, row_cnt); } + + /* FIXME: Should you unref destv[i], JP?? - Damon */ + } + /* FIXME: Should you g_free() destv, JP?? - Damon */ } static void diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c index d2f4a557c2..f6ad6da413 100644 --- a/calendar/gui/dialogs/task-page.c +++ b/calendar/gui/dialogs/task-page.c @@ -66,12 +66,17 @@ struct _TaskPagePrivate { GtkWidget *classification_confidential; GtkWidget *contacts_btn; - GtkWidget *contacts; + GtkWidget *contacts_box; GtkWidget *categories_btn; GtkWidget *categories; gboolean updating; + + /* The Corba component for selecting contacts, and the entry field + which we place in the dialog. */ + GNOME_Evolution_Addressbook_SelectNames corba_select_names; + GtkWidget *contacts_entry; }; static const int classification_map[] = { @@ -174,11 +179,14 @@ task_page_init (TaskPage *tpage) priv->classification_private = NULL; priv->classification_confidential = NULL; priv->contacts_btn = NULL; - priv->contacts = NULL; + priv->contacts_box = NULL; priv->categories_btn = NULL; priv->categories = NULL; priv->updating = FALSE; + + priv->corba_select_names = CORBA_OBJECT_NIL; + priv->contacts_entry = NULL; } /* Destroy handler for the task page */ @@ -194,6 +202,14 @@ task_page_destroy (GtkObject *object) tpage = TASK_PAGE (object); priv = tpage->priv; + if (priv->corba_select_names != CORBA_OBJECT_NIL) { + CORBA_Environment ev; + + CORBA_exception_init (&ev); + CORBA_Object_release (priv->corba_select_names, &ev); + CORBA_exception_free (&ev); + } + if (priv->xml) { gtk_object_unref (GTK_OBJECT (priv->xml)); priv->xml = NULL; @@ -265,6 +281,23 @@ classification_get (GtkWidget *widget) return e_dialog_radio_get (widget, classification_map); } +static void +contacts_changed_cb (BonoboListener *listener, + char *event_name, + CORBA_any *arg, + CORBA_Environment *ev, + gpointer data) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (data); + priv = tpage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tpage)); +} + /* fill_widgets handler for the task page */ static void task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) @@ -384,6 +417,19 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) cal_component_get_categories (comp, &categories); e_dialog_editable_set (priv->categories, categories); + + /* Contacts */ + comp_editor_contacts_to_widget (priv->contacts_entry, comp); + + /* We connect the contacts changed signal here, as we have to be a bit + more careful with it due to the use or Corba. The priv->updating + flag won't work as we won't get the changed event immediately. + FIXME: Unfortunately this doesn't work either. We never get the + changed event now. */ + comp_editor_connect_contacts_changed (priv->contacts_entry, + contacts_changed_cb, tpage); + + priv->updating = FALSE; } @@ -491,6 +537,9 @@ task_page_fill_component (CompEditorPage *page, CalComponent *comp) if (cat) g_free (cat); + + /* Contacts */ + comp_editor_contacts_to_component (priv->contacts_entry, comp); } /* set_summary handler for the task page */ @@ -558,7 +607,7 @@ get_widgets (TaskPage *tpage) priv->classification_confidential = GW ("classification-confidential"); priv->contacts_btn = GW ("contacts-button"); - priv->contacts = GW ("contacts"); + priv->contacts_box = GW ("contacts-box"); priv->categories_btn = GW ("categories-button"); priv->categories = GW ("categories"); @@ -575,7 +624,7 @@ get_widgets (TaskPage *tpage) && priv->classification_confidential && priv->description && priv->contacts_btn - && priv->contacts + && priv->contacts_box && priv->categories_btn && priv->categories); } @@ -649,6 +698,22 @@ date_changed_cb (EDateEdit *dedit, gpointer data) &dates); } +/* Callback used when the contacts button is clicked; we must bring up the + * contact list dialog. + */ +static void +contacts_clicked_cb (GtkWidget *button, gpointer data) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (data); + priv = tpage->priv; + + g_print ("In contacts_clicked_cb\n"); + comp_editor_show_contacts_dialog (priv->corba_select_names); +} + /* Callback used when the categories button is clicked; we must bring up the * category list dialog. */ @@ -681,7 +746,7 @@ field_changed_cb (GtkWidget *widget, gpointer data) } /* Hooks the widget signals */ -static void +static gboolean init_widgets (TaskPage *tpage) { TaskPagePrivate *priv; @@ -732,19 +797,31 @@ init_widgets (TaskPage *tpage) field gets set whenever a field is changed. */ gtk_signal_connect (GTK_OBJECT (priv->description), "changed", GTK_SIGNAL_FUNC (field_changed_cb), tpage); - gtk_signal_connect (GTK_OBJECT (priv->contacts), "changed", - GTK_SIGNAL_FUNC (field_changed_cb), tpage); gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", GTK_SIGNAL_FUNC (field_changed_cb), tpage); - /* Button clicks */ + /* Contacts button */ + gtk_signal_connect (GTK_OBJECT (priv->contacts_btn), "clicked", + GTK_SIGNAL_FUNC (contacts_clicked_cb), tpage); + + /* Categories button */ gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", GTK_SIGNAL_FUNC (categories_clicked_cb), tpage); - /* FIXME: we do not support these fields yet, so we disable them */ - gtk_widget_set_sensitive (priv->contacts_btn, FALSE); - gtk_widget_set_sensitive (priv->contacts, FALSE); + /* Create the contacts entry, a corba control from the address book. */ + priv->corba_select_names = comp_editor_create_contacts_component (); + if (priv->corba_select_names == CORBA_OBJECT_NIL) + return FALSE; + + priv->contacts_entry = comp_editor_create_contacts_control (priv->corba_select_names); + if (priv->contacts_entry == NULL) + return FALSE; + + gtk_container_add (GTK_CONTAINER (priv->contacts_box), + priv->contacts_entry); + + return TRUE; } @@ -779,7 +856,11 @@ task_page_construct (TaskPage *tpage) return NULL; } - init_widgets (tpage); + if (!init_widgets (tpage)) { + g_message ("event_page_construct(): " + "Could not initialize the widgets!"); + return NULL; + } return tpage; } diff --git a/calendar/gui/dialogs/task-page.glade b/calendar/gui/dialogs/task-page.glade index 7c4a53c098..10e0180eff 100644 --- a/calendar/gui/dialogs/task-page.glade +++ b/calendar/gui/dialogs/task-page.glade @@ -410,7 +410,6 @@ <class>GtkButton</class> <name>contacts-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -431,25 +430,23 @@ </widget> <widget> - <class>GtkEntry</class> - <name>contacts</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> + <class>GtkEventBox</class> + <name>contacts-box</name> <child> <padding>0</padding> <expand>True</expand> <fill>True</fill> </child> + + <widget> + <class>Placeholder</class> + </widget> </widget> <widget> <class>GtkButton</class> <name>categories-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 7fbe482772..ca5be3bd6f 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -971,13 +971,13 @@ e_day_view_realize (GtkWidget *widget) day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED].green = 0 * 257; day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED].blue = 156 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].red = 148 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].green = 149 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].blue = 148 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].red = 32512; + day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].green = 32512; + day_view->colors[E_DAY_VIEW_COLOR_BG_GRID].blue = 32512; - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].red = 148 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].green = 149 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].blue = 148 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].red = 32512; + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].green = 32512; + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS].blue = 32512; day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED].red = 65535; day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED].green = 65535; @@ -2869,6 +2869,17 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget, e_day_view_stop_editing_event (day_view); if (event->button == 1) { + if (event->type == GDK_2BUTTON_PRESS) { + time_t dtstart, dtend; + + e_day_view_get_selected_time_range (day_view, &dtstart, + &dtend); + gnome_calendar_new_appointment_for (day_view->calendar, + dtstart, dtend, + TRUE); + return TRUE; + } + if (!GTK_WIDGET_HAS_FOCUS (day_view)) gtk_widget_grab_focus (GTK_WIDGET (day_view)); @@ -2946,6 +2957,8 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, gint event_x, event_y, scroll_x, scroll_y, row, day, event_num; EDayViewPosition pos; + g_print ("In e_day_view_on_main_canvas_button_press\n"); + /* Handle scroll wheel events */ if (event->button == 4) { /* The wheel has been moved up, so scroll the canvas down. */ @@ -2988,6 +3001,17 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, /* Start the selection drag. */ if (event->button == 1) { + if (event->type == GDK_2BUTTON_PRESS) { + time_t dtstart, dtend; + + e_day_view_get_selected_time_range (day_view, &dtstart, + &dtend); + gnome_calendar_new_appointment_for (day_view->calendar, + dtstart, dtend, + FALSE); + return TRUE; + } + if (!GTK_WIDGET_HAS_FOCUS (day_view)) gtk_widget_grab_focus (GTK_WIDGET (day_view)); @@ -3048,6 +3072,8 @@ e_day_view_on_long_event_button_press (EDayView *day_view, } else if (event->type == GDK_2BUTTON_PRESS) { e_day_view_on_event_double_click (day_view, -1, event_num); + gtk_signal_emit_stop_by_name (GTK_OBJECT (day_view->top_canvas), + "button_press_event"); return TRUE; } } else if (event->button == 3) { @@ -3081,6 +3107,8 @@ e_day_view_on_event_button_press (EDayView *day_view, } else if (event->type == GDK_2BUTTON_PRESS) { e_day_view_on_event_double_click (day_view, day, event_num); + gtk_signal_emit_stop_by_name (GTK_OBJECT (day_view->main_canvas), + "button_press_event"); return TRUE; } } else if (event->button == 3) { @@ -3327,6 +3355,21 @@ e_day_view_on_event_double_click (EDayView *day_view, gint day, gint event_num) { + EDayViewEvent *event; + + if (day == -1) + event = &g_array_index (day_view->long_events, EDayViewEvent, + event_num); + else + event = &g_array_index (day_view->events[day], EDayViewEvent, + event_num); + + e_day_view_stop_editing_event (day_view); + + if (day_view->calendar) + gnome_calendar_edit_object (day_view->calendar, event->comp); + else + g_warning ("Calendar not set"); } enum { @@ -3727,6 +3770,8 @@ e_day_view_on_main_canvas_button_release (GtkWidget *widget, GdkEventButton *event, EDayView *day_view) { + g_print ("In e_day_view_on_main_canvas_button_release\n"); + if (day_view->selection_is_being_dragged) { gdk_pointer_ungrab (event->time); e_day_view_finish_selection (day_view); @@ -5389,6 +5434,10 @@ e_day_view_on_text_item_event (GnomeCanvasItem *item, return TRUE; } break; + case GDK_2BUTTON_PRESS: + g_print ("Item got double-click\n"); + break; + case GDK_BUTTON_PRESS: case GDK_BUTTON_RELEASE: /* Only let the EText handle the event while editing. */ diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c index f0b4a167b3..bf321b2bf3 100644 --- a/calendar/gui/e-week-view-event-item.c +++ b/calendar/gui/e-week-view-event-item.c @@ -83,6 +83,8 @@ static gboolean e_week_view_event_item_button_press (EWeekViewEventItem *wveitem GdkEvent *event); static gboolean e_week_view_event_item_button_release (EWeekViewEventItem *wveitem, GdkEvent *event); +static gboolean e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, + GdkEvent *bevent); static EWeekViewPosition e_week_view_event_item_get_position (EWeekViewEventItem *wveitem, gdouble x, gdouble y); @@ -724,6 +726,8 @@ e_week_view_event_item_event (GnomeCanvasItem *item, GdkEvent *event) wveitem = E_WEEK_VIEW_EVENT_ITEM (item); switch (event->type) { + case GDK_2BUTTON_PRESS: + return e_week_view_event_item_double_click (wveitem, event); case GDK_BUTTON_PRESS: return e_week_view_event_item_button_press (wveitem, event); case GDK_BUTTON_RELEASE: @@ -812,7 +816,7 @@ e_week_view_event_item_button_release (EWeekViewEventItem *wveitem, week_view = E_WEEK_VIEW (GTK_WIDGET (item->canvas)->parent); g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), FALSE); -#if 0 +#if 1 g_print ("In e_week_view_event_item_button_release\n"); #endif @@ -833,6 +837,33 @@ e_week_view_event_item_button_release (EWeekViewEventItem *wveitem, } +static gboolean +e_week_view_event_item_double_click (EWeekViewEventItem *wveitem, + GdkEvent *bevent) +{ + EWeekView *week_view; + EWeekViewEvent *event; + GnomeCanvasItem *item; + + item = GNOME_CANVAS_ITEM (wveitem); + + week_view = E_WEEK_VIEW (GTK_WIDGET (item->canvas)->parent); + g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), FALSE); + + event = &g_array_index (week_view->events, EWeekViewEvent, + wveitem->event_num); + + e_week_view_stop_editing_event (week_view); + + if (week_view->calendar) + gnome_calendar_edit_object (week_view->calendar, event->comp); + else + g_warning ("Calendar not set"); + + return TRUE; +} + + static EWeekViewPosition e_week_view_event_item_get_position (EWeekViewEventItem *wveitem, gdouble x, diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index 094e0b4776..dfb03802b8 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -522,17 +522,17 @@ e_week_view_realize (GtkWidget *widget) colormap = gtk_widget_get_colormap (widget); /* Allocate the colors. */ - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].red = 0xeded; - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].green = 0xeded; - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].blue = 0xeded; + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].red = 0xe0e0; + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].green = 0xe0e0; + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].blue = 0xe0e0; week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].red = 65535; week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].green = 65535; week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].blue = 65535; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red = 0xd6d6; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green = 0xd6d6; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue = 0xd6d6; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red = 213 * 257; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green = 213 * 257; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue = 213 * 257; week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].red = 0; week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].green = 0; @@ -2041,8 +2041,12 @@ e_week_view_on_button_press (GtkWidget *widget, { gint x, y, day; -#if 0 +#if 1 g_print ("In e_week_view_on_button_press\n"); + if (event->type == GDK_2BUTTON_PRESS) + g_print (" is a double-click\n"); + if (week_view->pressed_event_num != -1) + g_print (" item is pressed\n"); #endif /* Handle scroll wheel events */ @@ -2059,10 +2063,6 @@ e_week_view_on_button_press (GtkWidget *widget, return TRUE; } - /* If an event is pressed just return. */ - if (week_view->pressed_event_num != -1) - return FALSE; - /* Convert the mouse position to a week & day. */ x = event->x; y = event->y; @@ -2070,8 +2070,25 @@ e_week_view_on_button_press (GtkWidget *widget, if (day == -1) return FALSE; - /* Start the selection drag. */ + /* If an event is pressed just return. */ + if (week_view->pressed_event_num != -1) + return FALSE; + + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { + time_t dtstart, dtend; + + g_print (" got double-click\n"); + + dtstart = week_view->day_starts[day]; + dtend = week_view->day_starts[day + 1]; + gnome_calendar_new_appointment_for (week_view->calendar, + dtstart, dtend, + TRUE); + return TRUE; + } + if (event->button == 1) { + /* Start the selection drag. */ if (!GTK_WIDGET_HAS_FOCUS (week_view)) gtk_widget_grab_focus (GTK_WIDGET (week_view)); @@ -2823,18 +2840,19 @@ e_week_view_stop_editing_event (EWeekView *week_view) static gboolean e_week_view_on_text_item_event (GnomeCanvasItem *item, - GdkEvent *event, + GdkEvent *gdkevent, EWeekView *week_view) { + EWeekViewEvent *event; gint event_num, span_num; #if 0 g_print ("In e_week_view_on_text_item_event\n"); #endif - switch (event->type) { + switch (gdkevent->type) { case GDK_KEY_PRESS: - if (event && event->key.keyval == GDK_Return) { + if (gdkevent && gdkevent->key.keyval == GDK_Return) { /* We set the keyboard focus to the EDayView, so the EText item loses it and stops the edit. */ gtk_widget_grab_focus (GTK_WIDGET (week_view)); @@ -2846,16 +2864,32 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, return TRUE; } break; + case GDK_2BUTTON_PRESS: + if (!e_week_view_find_event_from_item (week_view, item, + &event_num, &span_num)) + return FALSE; + + event = &g_array_index (week_view->events, EWeekViewEvent, + event_num); + + if (week_view->calendar) + gnome_calendar_edit_object (week_view->calendar, + event->comp); + else + g_warning ("Calendar not set"); + + gtk_signal_emit_stop_by_name (GTK_OBJECT (item), "event"); + return TRUE; case GDK_BUTTON_PRESS: if (!e_week_view_find_event_from_item (week_view, item, &event_num, &span_num)) return FALSE; - if (event->button.button == 3) { + if (gdkevent->button.button == 3) { if (!GTK_WIDGET_HAS_FOCUS (week_view)) gtk_widget_grab_focus (GTK_WIDGET (week_view)); e_week_view_show_popup_menu (week_view, - (GdkEventButton*) event, + (GdkEventButton*) gdkevent, event_num); gtk_signal_emit_stop_by_name (GTK_OBJECT (item->canvas), "button_press_event"); @@ -2870,9 +2904,9 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, gtk_signal_emit_stop_by_name (GTK_OBJECT (item), "event"); - if (event) { - week_view->drag_event_x = event->button.x; - week_view->drag_event_y = event->button.y; + if (gdkevent) { + week_view->drag_event_x = gdkevent->button.x; + week_view->drag_event_y = gdkevent->button.y; } else g_warning ("No GdkEvent"); @@ -2910,7 +2944,7 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item, week_view->pressed_event_num = -1; break; case GDK_FOCUS_CHANGE: - if (event->focus_change.in) { + if (gdkevent->focus_change.in) { e_week_view_on_editing_started (week_view, item); } else { e_week_view_on_editing_stopped (week_view, item); diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 2af032b184..e26150a86f 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -139,6 +139,12 @@ struct _GnomeCalendarPrivate { /* Our current timezone. */ icaltimezone *zone; + + /* The dates currently shown. If they are -1 then we have no dates + shown. We only use these to check if we need to emit a + 'dates-shown-changed' signal.*/ + time_t visible_start; + time_t visible_end; }; /* Signal IDs */ @@ -677,6 +683,9 @@ gnome_calendar_init (GnomeCalendar *gcal) priv->view_collection = NULL; priv->view_menus = NULL; + + priv->visible_start = -1; + priv->visible_end = -1; } /* Frees a set of categories */ @@ -1902,8 +1911,12 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); if (all_day) { - itt.hour = itt.minute = itt.second = 0; - icaltime_adjust (&itt, 1, 0, 0, 0); + /* If we want an all-day event and the end time isn't on a + day boundary, we move it to the end of the day it is in. */ + if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) { + itt.hour = itt.minute = itt.second = 0; + icaltime_adjust (&itt, 1, 0, 0, 0); + } } cal_component_set_dtend (comp, &dt); @@ -2374,8 +2387,24 @@ gnome_calendar_get_timezone (GnomeCalendar *gcal) static void gnome_calendar_notify_dates_shown_changed (GnomeCalendar *gcal) { + GnomeCalendarPrivate *priv; + time_t start_time, end_time; + g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - gtk_signal_emit (GTK_OBJECT (gcal), - gnome_calendar_signals[DATES_SHOWN_CHANGED]); + priv = gcal->priv; + + gnome_calendar_get_visible_time_range (gcal, &start_time, &end_time); + + /* We check if the visible date range has changed, and only emit the + signal if it has. (This makes sure we only change the folder title + bar label in the shell when we need to.) */ + if (priv->visible_start != start_time + || priv->visible_end != end_time) { + priv->visible_start = start_time; + priv->visible_end = end_time; + + gtk_signal_emit (GTK_OBJECT (gcal), + gnome_calendar_signals[DATES_SHOWN_CHANGED]); + } } |