2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
20 #include <glib/gi18n-lib.h>
23 #include <libedataserver/libedataserver.h>
24 #include <libecal/libecal.h>
25 #include <e-util/e-util.h>
27 #include "calendar-config.h"
28 #include "comp-util.h"
29 #include "e-cal-dialogs.h"
30 #include "itip-utils.h"
33 #include "e-comp-editor-page-general.h"
34 #include "e-comp-editor-page-attachments.h"
35 #include "e-comp-editor-event.h"
36 #include "e-comp-editor-memo.h"
37 #include "e-comp-editor-task.h"
39 #include "e-comp-editor.h"
41 struct _ECompEditorPrivate
{
42 EAlertBar
*alert_bar
; /* not referenced */
43 EActivityBar
*activity_bar
; /* not referenced */
44 GtkNotebook
*content
; /* not referenced */
46 EAlert
*validation_alert
;
49 GSettings
*calendar_settings
;
50 ESource
*origin_source
;
51 icalcomponent
*component
;
54 EFocusTracker
*focus_tracker
;
55 GtkUIManager
*ui_manager
;
57 GSList
*pages
; /* ECompEditorPage * */
58 gulong show_attendees_handler_id
;
60 ECompEditorPageGeneral
*page_general
; /* special page, can be added only once; not referenced */
62 EActivity
*target_client_opening
;
64 ECalClient
*source_client
;
65 ECalClient
*target_client
;
66 gchar
*cal_email_address
;
67 gchar
*alarm_email_address
;
72 ECompEditorPropertyPart
*dtstart_part
;
73 ECompEditorPropertyPart
*dtend_part
;
75 GtkWidget
*restore_focus
;
80 PROP_ALARM_EMAIL_ADDRESS
,
81 PROP_CAL_EMAIL_ADDRESS
,
99 static guint signals
[LAST_SIGNAL
];
101 static GSList
*opened_editors
= NULL
;
103 static void e_comp_editor_alert_sink_iface_init (EAlertSinkInterface
*iface
);
105 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ECompEditor
, e_comp_editor
, GTK_TYPE_WINDOW
,
106 G_IMPLEMENT_INTERFACE (E_TYPE_ALERT_SINK
, e_comp_editor_alert_sink_iface_init
)
107 G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE
, NULL
))
110 ece_restore_focus (ECompEditor
*comp_editor
)
112 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
114 if (comp_editor
->priv
->restore_focus
) {
115 gtk_widget_grab_focus (comp_editor
->priv
->restore_focus
);
117 if (GTK_IS_ENTRY (comp_editor
->priv
->restore_focus
))
118 gtk_editable_set_position (GTK_EDITABLE (comp_editor
->priv
->restore_focus
), 0);
120 comp_editor
->priv
->restore_focus
= NULL
;
125 e_comp_editor_enable (ECompEditor
*comp_editor
,
128 GtkActionGroup
*group
;
129 GtkWidget
*current_focus
;
131 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
133 current_focus
= gtk_window_get_focus (GTK_WINDOW (comp_editor
));
135 gtk_widget_set_sensitive (GTK_WIDGET (comp_editor
->priv
->content
), enable
);
137 group
= e_comp_editor_get_action_group (comp_editor
, "individual");
138 gtk_action_group_set_sensitive (group
, enable
);
140 group
= e_comp_editor_get_action_group (comp_editor
, "core");
141 gtk_action_group_set_sensitive (group
, enable
);
143 group
= e_comp_editor_get_action_group (comp_editor
, "editable");
144 gtk_action_group_set_sensitive (group
, enable
);
147 e_comp_editor_sensitize_widgets (comp_editor
);
148 ece_restore_focus (comp_editor
);
150 comp_editor
->priv
->restore_focus
= current_focus
;
155 ece_set_attendees_for_delegation (ECalComponent
*comp
,
156 const gchar
*address
)
159 icalparameter
*param
;
160 icalcomponent
*icalcomp
;
163 icalcomp
= e_cal_component_get_icalcomponent (comp
);
165 for (prop
= icalcomponent_get_first_property (icalcomp
, ICAL_ATTENDEE_PROPERTY
);
167 prop
= again
? icalcomponent_get_first_property (icalcomp
, ICAL_ATTENDEE_PROPERTY
) :
168 icalcomponent_get_next_property (icalcomp
, ICAL_ATTENDEE_PROPERTY
)) {
169 const gchar
*attendee
= icalproperty_get_attendee (prop
);
170 const gchar
*delfrom
= NULL
;
173 param
= icalproperty_get_first_parameter (prop
, ICAL_DELEGATEDFROM_PARAMETER
);
175 delfrom
= icalparameter_get_delegatedfrom (param
);
176 if (!(g_str_equal (itip_strip_mailto (attendee
), address
) ||
177 ((delfrom
&& *delfrom
) && g_str_equal (itip_strip_mailto (delfrom
), address
)))) {
178 icalcomponent_remove_property (icalcomp
, prop
);
179 icalproperty_free (prop
);
186 /* Utility function to get the mime-attachment list from the attachment
187 * bar for sending the comp via itip. The list and its contents must
188 * be freed by the caller.
191 ece_get_mime_attach_list (ECompEditor
*comp_editor
)
193 ECompEditorPage
*page_attachments
;
194 EAttachmentStore
*store
;
197 struct CalMimeAttach
*cal_mime_attach
;
198 GSList
*attach_list
= NULL
;
201 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
203 page_attachments
= e_comp_editor_get_page (comp_editor
, E_TYPE_COMP_EDITOR_PAGE_ATTACHMENTS
);
204 if (!page_attachments
)
207 store
= e_comp_editor_page_attachments_get_store (E_COMP_EDITOR_PAGE_ATTACHMENTS (page_attachments
));
211 model
= GTK_TREE_MODEL (store
);
212 valid
= gtk_tree_model_get_iter_first (model
, &iter
);
215 EAttachment
*attachment
;
216 CamelDataWrapper
*wrapper
;
217 CamelMimePart
*mime_part
;
219 GByteArray
*byte_array
;
220 guchar
*buffer
= NULL
;
221 const gchar
*description
;
222 const gchar
*disposition
;
225 column_id
= E_ATTACHMENT_STORE_COLUMN_ATTACHMENT
;
226 gtk_tree_model_get (model
, &iter
, column_id
, &attachment
, -1);
227 mime_part
= e_attachment_ref_mime_part (attachment
);
228 g_object_unref (attachment
);
230 valid
= gtk_tree_model_iter_next (model
, &iter
);
232 if (mime_part
== NULL
)
235 cal_mime_attach
= g_malloc0 (sizeof (struct CalMimeAttach
));
236 wrapper
= camel_medium_get_content (CAMEL_MEDIUM (mime_part
));
238 byte_array
= g_byte_array_new ();
239 stream
= camel_stream_mem_new_with_byte_array (byte_array
);
241 camel_data_wrapper_decode_to_stream_sync (
242 wrapper
, stream
, NULL
, NULL
);
243 buffer
= g_memdup (byte_array
->data
, byte_array
->len
);
245 camel_mime_part_set_content_id (mime_part
, NULL
);
247 cal_mime_attach
->encoded_data
= (gchar
*) buffer
;
248 cal_mime_attach
->length
= byte_array
->len
;
249 cal_mime_attach
->filename
=
250 g_strdup (camel_mime_part_get_filename (mime_part
));
251 description
= camel_mime_part_get_description (mime_part
);
252 if (description
== NULL
|| *description
== '\0')
253 description
= _("attachment");
254 cal_mime_attach
->description
= g_strdup (description
);
255 cal_mime_attach
->content_type
= g_strdup (
256 camel_data_wrapper_get_mime_type (wrapper
));
257 cal_mime_attach
->content_id
= g_strdup (
258 camel_mime_part_get_content_id (mime_part
));
260 disposition
= camel_mime_part_get_disposition (mime_part
);
261 cal_mime_attach
->disposition
=
262 (disposition
!= NULL
) &&
263 (g_ascii_strcasecmp (disposition
, "inline") == 0);
265 attach_list
= g_slist_append (attach_list
, cal_mime_attach
);
267 g_object_unref (mime_part
);
268 g_object_unref (stream
);
276 e_comp_editor_set_component (ECompEditor
*comp_editor
,
277 const icalcomponent
*component
)
279 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
280 g_return_if_fail (component
!= NULL
);
282 if (comp_editor
->priv
->component
)
283 icalcomponent_free (comp_editor
->priv
->component
);
284 comp_editor
->priv
->component
= icalcomponent_new_clone ((icalcomponent
*) component
);
286 g_warn_if_fail (comp_editor
->priv
->component
!= NULL
);
289 typedef struct _SaveData
{
290 ECompEditor
*comp_editor
;
291 ECalClient
*source_client
;
292 ECalClient
*target_client
;
293 icalcomponent
*component
;
295 gboolean close_after_save
;
296 ECalObjModType recur_mod
;
302 gboolean object_created
;
303 ECalComponentItipMethod first_send
;
304 ECalComponentItipMethod second_send
;
305 ECalComponent
*send_comp
;
306 EActivity
*send_activity
;
307 gboolean strip_alarms
;
308 gboolean only_new_attendees
;
309 GSList
*mime_attach_list
;
313 save_data_free (SaveData
*sd
)
316 e_comp_editor_enable (sd
->comp_editor
, TRUE
);
319 if (sd
->close_after_save
) {
320 g_signal_emit (sd
->comp_editor
, signals
[EDITOR_CLOSED
], 0, TRUE
, NULL
);
321 gtk_widget_destroy (GTK_WIDGET (sd
->comp_editor
));
323 e_comp_editor_set_component (sd
->comp_editor
, sd
->component
);
325 e_comp_editor_fill_widgets (sd
->comp_editor
, sd
->component
);
327 g_clear_object (&sd
->comp_editor
->priv
->source_client
);
328 sd
->comp_editor
->priv
->source_client
= g_object_ref (sd
->target_client
);
330 sd
->comp_editor
->priv
->flags
= sd
->comp_editor
->priv
->flags
& (~E_COMP_EDITOR_FLAG_IS_NEW
);
332 e_comp_editor_sensitize_widgets (sd
->comp_editor
);
333 e_comp_editor_set_changed (sd
->comp_editor
, FALSE
);
335 } else if (sd
->alert_ident
) {
337 E_ALERT_SINK (sd
->comp_editor
), sd
->alert_ident
, sd
->alert_arg_0
,
338 sd
->error
? sd
->error
->message
: _("Unknown error"), NULL
);
341 if (sd
->send_activity
&& e_activity_get_state (sd
->send_activity
) != E_ACTIVITY_CANCELLED
)
342 e_activity_set_state (sd
->send_activity
, E_ACTIVITY_COMPLETED
);
344 g_clear_object (&sd
->comp_editor
);
345 g_clear_object (&sd
->source_client
);
346 g_clear_object (&sd
->target_client
);
347 g_clear_object (&sd
->send_comp
);
348 g_clear_object (&sd
->send_activity
);
349 g_clear_error (&sd
->error
);
351 icalcomponent_free (sd
->component
);
352 g_slist_free_full (sd
->mime_attach_list
, itip_cal_mime_attach_free
);
353 g_free (sd
->alert_ident
);
354 g_free (sd
->alert_arg_0
);
360 ece_send_process_method (SaveData
*sd
,
361 ECalComponentItipMethod send_method
,
362 ECalComponent
*send_comp
,
363 ESourceRegistry
*registry
,
364 GCancellable
*cancellable
,
365 GAsyncReadyCallback callback
,
368 GSList
*mime_attach_list
= NULL
;
370 g_return_val_if_fail (sd
!= NULL
, FALSE
);
371 g_return_val_if_fail (E_IS_CAL_COMPONENT (send_comp
), FALSE
);
372 g_return_val_if_fail (send_method
!= E_CAL_COMPONENT_METHOD_NONE
, FALSE
);
374 if (e_cal_component_has_attachments (send_comp
) &&
375 e_client_check_capability (E_CLIENT (sd
->target_client
), CAL_STATIC_CAPABILITY_CREATE_MESSAGES
)) {
376 /* Clone the component with attachments set to CID:... */
377 GSList
*attach_list
= NULL
;
380 /* mime_attach_list is freed by itip_send_component() */
381 mime_attach_list
= sd
->mime_attach_list
;
382 sd
->mime_attach_list
= NULL
;
384 for (attach
= mime_attach_list
; attach
; attach
= attach
->next
) {
385 struct CalMimeAttach
*cma
= (struct CalMimeAttach
*) attach
->data
;
387 attach_list
= g_slist_append (
388 attach_list
, g_strconcat (
389 "cid:", cma
->content_id
, NULL
));
393 e_cal_component_set_attachment_list (send_comp
, attach_list
);
395 g_slist_free_full (attach_list
, g_free
);
399 itip_send_component (
400 registry
, send_method
, send_comp
, sd
->target_client
,
401 NULL
, mime_attach_list
, NULL
, sd
->strip_alarms
,
402 sd
->only_new_attendees
, FALSE
,
403 cancellable
, callback
, user_data
);
409 ecep_second_send_processed_cb (GObject
*source_object
,
410 GAsyncResult
*result
,
413 SaveData
*sd
= user_data
;
415 g_return_if_fail (sd
!= NULL
);
417 sd
->success
= itip_send_component_finish (result
, &sd
->error
);
423 ecep_first_send_processed_cb (GObject
*source_object
,
424 GAsyncResult
*result
,
427 SaveData
*sd
= user_data
;
429 g_return_if_fail (sd
!= NULL
);
431 sd
->success
= itip_send_component_finish (result
, &sd
->error
);
432 if (!sd
->success
|| sd
->second_send
== E_CAL_COMPONENT_METHOD_NONE
) {
435 sd
->success
= ece_send_process_method (sd
, sd
->second_send
, sd
->send_comp
,
436 e_shell_get_registry (sd
->comp_editor
->priv
->shell
),
437 e_activity_get_cancellable (sd
->send_activity
),
438 ecep_second_send_processed_cb
, sd
);
445 ece_prepare_send_component_done (gpointer ptr
)
449 g_return_if_fail (sd
!= NULL
);
450 g_return_if_fail (E_IS_COMP_EDITOR (sd
->comp_editor
));
451 g_return_if_fail (sd
->send_activity
!= NULL
);
453 sd
->success
= ece_send_process_method (sd
, sd
->first_send
, sd
->send_comp
,
454 e_shell_get_registry (sd
->comp_editor
->priv
->shell
),
455 e_activity_get_cancellable (sd
->send_activity
),
456 ecep_first_send_processed_cb
, sd
);
462 ece_prepare_send_component_thread (EAlertSinkThreadJobData
*job_data
,
464 GCancellable
*cancellable
,
467 SaveData
*sd
= user_data
;
468 const gchar
*alert_ident
;
469 ECalComponent
*send_comp
= NULL
;
471 ESourceRegistry
*registry
;
473 g_return_if_fail (sd
!= NULL
);
474 g_return_if_fail (E_IS_CAL_CLIENT (sd
->target_client
));
475 g_return_if_fail (sd
->component
!= NULL
);
477 while (!sd
->send_activity
) {
478 /* Give the main thread a chance to set this object
479 and give it a 50 milliseconds delay too */
484 switch (icalcomponent_isa (sd
->component
)) {
485 case ICAL_VEVENT_COMPONENT
:
486 alert_ident
= "calendar:failed-send-event";
488 case ICAL_VJOURNAL_COMPONENT
:
489 alert_ident
= "calendar:failed-send-memo";
491 case ICAL_VTODO_COMPONENT
:
492 alert_ident
= "calendar:failed-send-task";
495 g_warning ("%s: Cannot send component of kind %d", G_STRFUNC
, icalcomponent_isa (sd
->component
));
497 sd
->alert_ident
= g_strdup ("calendar:failed-send-event");
501 g_free (sd
->alert_ident
);
502 sd
->alert_ident
= g_strdup (alert_ident
);
504 e_alert_sink_thread_job_set_alert_ident (job_data
, alert_ident
);
506 flags
= e_comp_editor_get_flags (sd
->comp_editor
);
507 registry
= e_shell_get_registry (sd
->comp_editor
->priv
->shell
);
509 if (sd
->recur_mod
== E_CAL_OBJ_MOD_ALL
&& e_cal_component_is_instance (sd
->send_comp
)) {
510 /* Ensure we send the master object, not the instance only */
511 icalcomponent
*icalcomp
= NULL
;
512 const gchar
*uid
= NULL
;
514 e_cal_component_get_uid (sd
->send_comp
, &uid
);
515 if (e_cal_client_get_object_sync (sd
->target_client
, uid
, NULL
, &icalcomp
, cancellable
, NULL
) &&
517 send_comp
= e_cal_component_new_from_icalcomponent (icalcomp
);
522 send_comp
= e_cal_component_clone (sd
->send_comp
);
524 cal_comp_util_copy_new_attendees (send_comp
, sd
->send_comp
);
526 /* The user updates the delegated status to the Organizer,
527 * so remove all other attendees. */
528 if ((flags
& E_COMP_EDITOR_FLAG_DELEGATE
) != 0) {
531 address
= itip_get_comp_attendee (registry
, send_comp
, sd
->target_client
);
534 ece_set_attendees_for_delegation (send_comp
, address
);
539 g_clear_object (&sd
->send_comp
);
540 sd
->send_comp
= send_comp
;
544 ece_save_component_done (gpointer ptr
)
548 g_return_if_fail (sd
!= NULL
);
549 g_return_if_fail (E_IS_COMP_EDITOR (sd
->comp_editor
));
553 gboolean delegated
, is_new_meeting
;
554 gboolean only_new_attendees
= FALSE
;
555 gboolean strip_alarms
= TRUE
;
558 if (sd
->object_created
)
559 g_signal_emit (sd
->comp_editor
, signals
[OBJECT_CREATED
], 0, NULL
);
561 comp
= e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (sd
->component
));
562 if (sd
->comp_editor
->priv
->page_general
) {
563 GSList
*added_attendees
;
565 added_attendees
= e_comp_editor_page_general_get_added_attendees (sd
->comp_editor
->priv
->page_general
);
566 cal_comp_util_set_added_attendees_mails (comp
, added_attendees
);
569 flags
= e_comp_editor_get_flags (sd
->comp_editor
);
570 is_new_meeting
= (flags
& E_COMP_EDITOR_FLAG_WITH_ATTENDEES
) == 0 ||
571 (flags
& E_COMP_EDITOR_FLAG_IS_NEW
) != 0;
572 delegated
= (flags
& E_COMP_EDITOR_FLAG_DELEGATE
) != 0 &&
573 e_cal_client_check_save_schedules (sd
->target_client
);
575 if (delegated
|| (sd
->with_send
&& e_cal_dialogs_send_component (
576 GTK_WINDOW (sd
->comp_editor
), sd
->target_client
, comp
,
577 is_new_meeting
, &strip_alarms
, &only_new_attendees
))) {
578 ESourceRegistry
*registry
;
581 registry
= e_shell_get_registry (sd
->comp_editor
->priv
->shell
);
584 only_new_attendees
= FALSE
;
586 if ((itip_organizer_is_user (registry
, comp
, sd
->target_client
) ||
587 itip_sentby_is_user (registry
, comp
, sd
->target_client
))) {
588 if (e_cal_component_get_vtype (comp
) == E_CAL_COMPONENT_JOURNAL
)
589 sd
->first_send
= E_CAL_COMPONENT_METHOD_PUBLISH
;
591 sd
->first_send
= E_CAL_COMPONENT_METHOD_REQUEST
;
593 sd
->first_send
= E_CAL_COMPONENT_METHOD_REQUEST
;
595 if ((flags
& E_COMP_EDITOR_FLAG_DELEGATE
) != 0)
596 sd
->second_send
= E_CAL_COMPONENT_METHOD_REPLY
;
599 sd
->mime_attach_list
= ece_get_mime_attach_list (sd
->comp_editor
);
600 sd
->strip_alarms
= strip_alarms
;
601 sd
->only_new_attendees
= only_new_attendees
;
602 sd
->send_comp
= comp
;
604 sd
->alert_ident
= g_strdup ("calendar:failed-send-event");
605 sd
->alert_arg_0
= e_util_get_source_full_name (registry
, e_client_get_source (E_CLIENT (sd
->target_client
)));
607 activity
= e_alert_sink_submit_thread_job (E_ALERT_SINK (sd
->comp_editor
),
608 _("Sending notifications to attendees..."), sd
->alert_ident
, sd
->alert_arg_0
,
609 ece_prepare_send_component_thread
, sd
, ece_prepare_send_component_done
);
612 e_activity_bar_set_activity (sd
->comp_editor
->priv
->activity_bar
, activity
);
614 /* The thread is waiting for this to be set first */
615 sd
->send_activity
= activity
;
620 g_clear_object (&comp
);
627 ece_save_component_attachments_sync (ECalClient
*cal_client
,
628 icalcomponent
*component
,
629 GCancellable
*cancellable
,
633 const gchar
*local_store
;
634 gchar
*target_filename_prefix
, *filename_prefix
, *tmp
;
635 gboolean success
= TRUE
;
637 g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client
), FALSE
);
638 g_return_val_if_fail (component
!= NULL
, FALSE
);
640 tmp
= g_strdup (icalcomponent_get_uid (component
));
641 e_filename_make_safe (tmp
);
642 filename_prefix
= g_strconcat (tmp
, "-", NULL
);
645 local_store
= e_cal_client_get_local_attachment_store (cal_client
);
646 if (local_store
&& *local_store
&&
647 g_mkdir_with_parents (local_store
, 0700) < 0) {
648 g_debug ("%s: Failed to create local store directory '%s'", G_STRFUNC
, local_store
);
651 target_filename_prefix
= g_build_filename (local_store
, filename_prefix
, NULL
);
653 g_free (filename_prefix
);
655 for (prop
= icalcomponent_get_first_property (component
, ICAL_ATTACH_PROPERTY
);
657 prop
= icalcomponent_get_next_property (component
, ICAL_ATTACH_PROPERTY
)) {
661 attach
= icalproperty_get_attach (prop
);
665 if (icalattach_get_is_url (attach
)) {
669 data
= icalattach_get_url (attach
);
670 buf_size
= strlen (data
);
671 uri
= g_malloc0 (buf_size
+ 1);
673 icalvalue_decode_ical_string (data
, uri
, buf_size
);
677 if (g_ascii_strncasecmp (uri
, "file://", 7) == 0 &&
678 !g_str_has_prefix (uri
+ 7, target_filename_prefix
)) {
679 GFile
*source
, *destination
;
680 gchar
*decoded_filename
;
681 gchar
*target_filename
;
683 decoded_filename
= g_uri_unescape_string (strrchr (uri
, '/') + 1, NULL
);
684 target_filename
= g_strconcat (target_filename_prefix
, decoded_filename
, NULL
);
685 g_free (decoded_filename
);
687 source
= g_file_new_for_uri (uri
);
688 destination
= g_file_new_for_path (target_filename
);
690 if (source
&& destination
) {
691 success
= g_file_copy (source
, destination
, G_FILE_COPY_OVERWRITE
, cancellable
, NULL
, NULL
, error
);
694 uri
= g_file_get_uri (destination
);
697 icalattach
*new_attach
;
701 buf_size
= 2 * strlen (uri
) + 1;
702 buf
= g_malloc0 (buf_size
);
704 icalvalue_encode_ical_string (uri
, buf
, buf_size
);
705 new_attach
= icalattach_new_from_url (buf
);
707 icalproperty_set_attach (prop
, new_attach
);
709 icalattach_unref (new_attach
);
715 g_clear_object (&source
);
716 g_clear_object (&destination
);
717 g_free (target_filename
);
723 success
= success
& !g_cancellable_set_error_if_cancelled (cancellable
, error
);
726 g_free (target_filename_prefix
);
732 ece_gather_tzids_cb (icalparameter
*param
,
735 GHashTable
*tzids
= user_data
;
738 g_return_if_fail (param
!= NULL
);
739 g_return_if_fail (tzids
!= NULL
);
741 tzid
= icalparameter_get_tzid (param
);
742 if (tzid
&& *tzid
&& g_ascii_strcasecmp (tzid
, "UTC") != 0)
743 g_hash_table_insert (tzids
, g_strdup (tzid
), NULL
);
747 ece_save_component_add_timezones_sync (SaveData
*sd
,
748 GCancellable
*cancellable
,
754 gboolean source_is_target
;
756 g_return_val_if_fail (sd
!= NULL
, FALSE
);
757 g_return_val_if_fail (sd
->component
!= NULL
, FALSE
);
758 g_return_val_if_fail (sd
->target_client
!= NULL
, FALSE
);
762 tzids
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
763 source_is_target
= !sd
->source_client
||
764 e_source_equal (e_client_get_source (E_CLIENT (sd
->target_client
)),
765 e_client_get_source (E_CLIENT (sd
->source_client
)));
767 icalcomponent_foreach_tzid (sd
->component
, ece_gather_tzids_cb
, tzids
);
769 g_hash_table_iter_init (&iter
, tzids
);
770 while (sd
->success
&& g_hash_table_iter_next (&iter
, &key
, &value
)) {
771 const gchar
*tzid
= key
;
772 icaltimezone
*zone
= NULL
;
773 GError
*local_error
= NULL
;
775 if (!e_cal_client_get_timezone_sync (source_is_target
? sd
->target_client
: sd
->source_client
,
776 tzid
, &zone
, cancellable
, &local_error
)) {
777 zone
= icaltimezone_get_builtin_timezone_from_tzid (tzid
);
779 zone
= icaltimezone_get_builtin_timezone (tzid
);
781 g_propagate_error (error
, local_error
);
788 sd
->success
= e_cal_client_add_timezone_sync (sd
->target_client
, zone
, cancellable
, error
);
790 g_clear_error (&local_error
);
793 g_hash_table_destroy (tzids
);
799 ece_save_component_thread (EAlertSinkThreadJobData
*job_data
,
801 GCancellable
*cancellable
,
804 SaveData
*sd
= user_data
;
805 const gchar
*create_alert_ident
, *modify_alert_ident
, *remove_alert_ident
, *get_alert_ident
;
806 gchar
*orig_uid
, *new_uid
= NULL
;
808 g_return_if_fail (sd
!= NULL
);
809 g_return_if_fail (E_IS_CAL_CLIENT (sd
->target_client
));
810 g_return_if_fail (sd
->component
!= NULL
);
812 switch (icalcomponent_isa (sd
->component
)) {
813 case ICAL_VEVENT_COMPONENT
:
814 create_alert_ident
= "calendar:failed-create-event";
815 modify_alert_ident
= "calendar:failed-modify-event";
816 remove_alert_ident
= "calendar:failed-remove-event";
817 get_alert_ident
= "calendar:failed-get-event";
819 case ICAL_VJOURNAL_COMPONENT
:
820 create_alert_ident
= "calendar:failed-create-memo";
821 modify_alert_ident
= "calendar:failed-modify-memo";
822 remove_alert_ident
= "calendar:failed-remove-memo";
823 get_alert_ident
= "calendar:failed-get-memo";
825 case ICAL_VTODO_COMPONENT
:
826 create_alert_ident
= "calendar:failed-create-task";
827 modify_alert_ident
= "calendar:failed-modify-task";
828 remove_alert_ident
= "calendar:failed-remove-task";
829 get_alert_ident
= "calendar:failed-get-task";
832 g_warning ("%s: Cannot save component of kind %d", G_STRFUNC
, icalcomponent_isa (sd
->component
));
836 sd
->success
= ece_save_component_add_timezones_sync (sd
, cancellable
, error
);
838 e_alert_sink_thread_job_set_alert_ident (job_data
, "calendar:failed-add-timezone");
842 sd
->success
= ece_save_component_attachments_sync (sd
->target_client
, sd
->component
, cancellable
, error
);
844 e_alert_sink_thread_job_set_alert_ident (job_data
, "calendar:failed-save-attachments");
848 orig_uid
= g_strdup (icalcomponent_get_uid (sd
->component
));
850 if (cal_comp_is_icalcomp_on_server_sync (sd
->component
, sd
->target_client
, cancellable
, error
)) {
852 gboolean has_recurrences
;
854 e_alert_sink_thread_job_set_alert_ident (job_data
, modify_alert_ident
);
856 comp
= e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (sd
->component
));
857 g_return_if_fail (comp
!= NULL
);
859 has_recurrences
= e_cal_util_component_has_recurrences (sd
->component
);
861 if (has_recurrences
&& sd
->recur_mod
== E_CAL_OBJ_MOD_ALL
)
862 sd
->success
= comp_util_sanitize_recurrence_master_sync (comp
, sd
->target_client
, cancellable
, error
);
866 if (sd
->recur_mod
== E_CAL_OBJ_MOD_THIS
) {
867 e_cal_component_set_rdate_list (comp
, NULL
);
868 e_cal_component_set_rrule_list (comp
, NULL
);
869 e_cal_component_set_exdate_list (comp
, NULL
);
870 e_cal_component_set_exrule_list (comp
, NULL
);
873 sd
->success
= sd
->success
&& e_cal_client_modify_object_sync (
874 sd
->target_client
, e_cal_component_get_icalcomponent (comp
), sd
->recur_mod
, cancellable
, error
);
876 g_clear_object (&comp
);
878 e_alert_sink_thread_job_set_alert_ident (job_data
, create_alert_ident
);
880 sd
->success
= e_cal_client_create_object_sync (sd
->target_client
, sd
->component
, &new_uid
, cancellable
, error
);
883 sd
->object_created
= TRUE
;
886 if (sd
->success
&& sd
->source_client
&&
887 !e_source_equal (e_client_get_source (E_CLIENT (sd
->target_client
)),
888 e_client_get_source (E_CLIENT (sd
->source_client
))) &&
889 cal_comp_is_icalcomp_on_server_sync (sd
->component
, sd
->source_client
, cancellable
, NULL
)) {
890 ECalObjModType recur_mod
= E_CAL_OBJ_MOD_THIS
;
892 /* Comp found a new home. Remove it from old one. */
893 if (e_cal_util_component_is_instance (sd
->component
) ||
894 e_cal_util_component_has_recurrences (sd
->component
))
895 recur_mod
= E_CAL_OBJ_MOD_ALL
;
897 sd
->success
= e_cal_client_remove_object_sync (
898 sd
->source_client
, orig_uid
,
899 NULL
, recur_mod
, cancellable
, error
);
902 gchar
*source_display_name
;
904 source_display_name
= e_util_get_source_full_name (e_shell_get_registry (sd
->comp_editor
->priv
->shell
),
905 e_client_get_source (E_CLIENT (sd
->source_client
)));
907 e_alert_sink_thread_job_set_alert_ident (job_data
, remove_alert_ident
);
908 e_alert_sink_thread_job_set_alert_arg_0 (job_data
, source_display_name
);
910 g_free (source_display_name
);
915 icalcomponent_set_uid (sd
->component
, new_uid
);
921 if (sd
->success
&& !sd
->close_after_save
) {
922 icalcomponent
*comp
= NULL
;
923 gchar
*uid
, *rid
= NULL
;
925 uid
= g_strdup (icalcomponent_get_uid (sd
->component
));
926 if (icalcomponent_get_first_property (sd
->component
, ICAL_RECURRENCEID_PROPERTY
)) {
927 struct icaltimetype ridtt
;
929 ridtt
= icalcomponent_get_recurrenceid (sd
->component
);
930 if (icaltime_is_valid_time (ridtt
) && !icaltime_is_null_time (ridtt
)) {
931 rid
= icaltime_as_ical_string_r (ridtt
);
935 sd
->success
= e_cal_client_get_object_sync (sd
->target_client
, uid
, rid
, &comp
, cancellable
, error
);
936 if (sd
->success
&& comp
) {
937 icalcomponent_free (sd
->component
);
938 sd
->component
= comp
;
940 e_alert_sink_thread_job_set_alert_ident (job_data
, get_alert_ident
);
949 ece_save_component (ECompEditor
*comp_editor
,
950 icalcomponent
*component
,
952 gboolean close_after_save
)
955 const gchar
*summary
;
956 ECalObjModType recur_mod
= E_CAL_OBJ_MOD_THIS
;
958 gchar
*source_display_name
;
960 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
961 g_return_if_fail (component
!= NULL
);
963 summary
= icalcomponent_get_summary (component
);
964 if (!summary
|| !*summary
) {
965 if (!e_cal_dialogs_send_component_prompt_subject (GTK_WINDOW (comp_editor
), component
)) {
970 if (e_cal_util_component_is_instance (component
)) {
971 if (!e_cal_dialogs_recur_icalcomp (comp_editor
->priv
->target_client
,
972 component
, &recur_mod
, GTK_WINDOW (comp_editor
), FALSE
)) {
975 } else if (e_cal_util_component_has_recurrences (component
)) {
976 recur_mod
= E_CAL_OBJ_MOD_ALL
;
979 e_comp_editor_enable (comp_editor
, FALSE
);
981 sd
= g_new0 (SaveData
, 1);
982 sd
->comp_editor
= g_object_ref (comp_editor
);
983 sd
->source_client
= comp_editor
->priv
->source_client
? g_object_ref (comp_editor
->priv
->source_client
) : NULL
;
984 sd
->target_client
= g_object_ref (comp_editor
->priv
->target_client
);
985 sd
->component
= icalcomponent_new_clone (component
);
986 sd
->with_send
= with_send
;
987 sd
->close_after_save
= close_after_save
;
988 sd
->recur_mod
= recur_mod
;
989 sd
->first_send
= E_CAL_COMPONENT_METHOD_NONE
;
990 sd
->second_send
= E_CAL_COMPONENT_METHOD_NONE
;
993 source_display_name
= e_util_get_source_full_name (e_shell_get_registry (comp_editor
->priv
->shell
),
994 e_client_get_source (E_CLIENT (sd
->target_client
)));
996 activity
= e_alert_sink_submit_thread_job (E_ALERT_SINK (comp_editor
),
997 _("Saving changes..."), "calendar:failed-create-event", source_display_name
,
998 ece_save_component_thread
, sd
, ece_save_component_done
);
1001 e_activity_bar_set_activity (comp_editor
->priv
->activity_bar
, activity
);
1003 g_clear_object (&activity
);
1004 g_free (source_display_name
);
1007 typedef struct _OpenTargetClientData
{
1008 ECompEditor
*comp_editor
;
1010 gchar
*extension_name
;
1012 gchar
*cal_email_address
;
1013 gchar
*alarm_email_address
;
1014 gboolean is_target_client_change
;
1015 EActivity
*activity
;
1016 } OpenTargetClientData
;
1019 open_target_client_data_free (gpointer ptr
)
1021 OpenTargetClientData
*otc
= ptr
;
1024 if (otc
->comp_editor
) {
1026 gboolean previous_changed
= e_comp_editor_get_changed (otc
->comp_editor
);
1028 e_comp_editor_set_alarm_email_address (otc
->comp_editor
, otc
->alarm_email_address
);
1029 e_comp_editor_set_cal_email_address (otc
->comp_editor
, otc
->cal_email_address
);
1030 e_comp_editor_set_target_client (otc
->comp_editor
, E_CAL_CLIENT (otc
->client
));
1032 if (otc
->is_target_client_change
)
1033 e_comp_editor_set_changed (otc
->comp_editor
, TRUE
);
1035 e_comp_editor_set_changed (otc
->comp_editor
, previous_changed
);
1038 if (otc
->comp_editor
->priv
->activity_bar
&& otc
->activity
) {
1039 if (otc
->activity
== e_activity_bar_get_activity (otc
->comp_editor
->priv
->activity_bar
))
1040 e_activity_bar_set_activity (otc
->comp_editor
->priv
->activity_bar
, NULL
);
1042 if (otc
->activity
== otc
->comp_editor
->priv
->target_client_opening
)
1043 g_clear_object (&otc
->comp_editor
->priv
->target_client_opening
);
1048 ECredentialsPrompter
*credentials_prompter
;
1050 shell
= e_comp_editor_get_shell (otc
->comp_editor
);
1051 credentials_prompter
= e_shell_get_credentials_prompter (shell
);
1053 e_credentials_prompter_set_auto_prompt_disabled_for (credentials_prompter
, otc
->source
, TRUE
);
1056 e_comp_editor_sensitize_widgets (otc
->comp_editor
);
1059 g_clear_object (&otc
->comp_editor
);
1060 g_clear_object (&otc
->source
);
1061 g_clear_object (&otc
->client
);
1062 g_clear_object (&otc
->activity
);
1063 g_free (otc
->extension_name
);
1064 g_free (otc
->cal_email_address
);
1065 g_free (otc
->alarm_email_address
);
1071 comp_editor_open_target_client_thread (EAlertSinkThreadJobData
*job_data
,
1073 GCancellable
*cancellable
,
1076 OpenTargetClientData
*otc
= user_data
;
1077 EClientCache
*client_cache
;
1079 g_return_if_fail (otc
!= NULL
);
1081 if (g_cancellable_set_error_if_cancelled (cancellable
, error
))
1084 g_return_if_fail (E_IS_COMP_EDITOR (otc
->comp_editor
));
1085 g_return_if_fail (E_IS_SOURCE (otc
->source
));
1086 g_return_if_fail (otc
->extension_name
!= NULL
);
1088 client_cache
= e_shell_get_client_cache (e_comp_editor_get_shell (otc
->comp_editor
));
1090 otc
->client
= e_client_cache_get_client_sync (client_cache
, otc
->source
, otc
->extension_name
,
1091 30, cancellable
, error
);
1094 /* Cache some properties which require remote calls */
1096 if (!g_cancellable_is_cancelled (cancellable
)) {
1097 e_client_get_capabilities (otc
->client
);
1100 if (!g_cancellable_is_cancelled (cancellable
)) {
1101 e_client_get_backend_property_sync (otc
->client
,
1102 CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS
,
1103 &otc
->cal_email_address
,
1104 cancellable
, error
);
1107 if (!g_cancellable_is_cancelled (cancellable
)) {
1108 e_client_get_backend_property_sync (otc
->client
,
1109 CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS
,
1110 &otc
->alarm_email_address
,
1111 cancellable
, error
);
1114 if (g_cancellable_is_cancelled (cancellable
))
1115 g_clear_object (&otc
->client
);
1119 typedef struct _UpdateActivityBarData
{
1120 ECompEditor
*comp_editor
;
1121 EActivity
*activity
;
1122 } UpdateActivityBarData
;
1125 update_activity_bar_data_free (gpointer ptr
)
1127 UpdateActivityBarData
*uab
= ptr
;
1130 g_clear_object (&uab
->comp_editor
);
1131 g_clear_object (&uab
->activity
);
1137 update_activity_bar_cb (gpointer user_data
)
1139 UpdateActivityBarData
*uab
= user_data
;
1141 g_return_val_if_fail (uab
!= NULL
, FALSE
);
1142 g_return_val_if_fail (E_IS_COMP_EDITOR (uab
->comp_editor
), FALSE
);
1143 g_return_val_if_fail (E_IS_ACTIVITY (uab
->activity
), FALSE
);
1145 if (uab
->comp_editor
->priv
->target_client_opening
== uab
->activity
&&
1146 e_activity_get_state (uab
->activity
) != E_ACTIVITY_CANCELLED
&&
1147 e_activity_get_state (uab
->activity
) != E_ACTIVITY_COMPLETED
) {
1148 e_activity_bar_set_activity (uab
->comp_editor
->priv
->activity_bar
, uab
->activity
);
1155 e_comp_editor_open_target_client (ECompEditor
*comp_editor
)
1157 OpenTargetClientData
*otc
;
1159 EActivity
*activity
;
1160 ECredentialsPrompter
*credentials_prompter
;
1161 gchar
*source_display_name
, *description
= NULL
, *alert_ident
= NULL
, *alert_arg_0
= NULL
;
1162 gboolean is_target_client_change
;
1163 const gchar
*extension_name
;
1165 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1166 g_return_if_fail (comp_editor
->priv
->page_general
!= NULL
);
1168 source
= e_comp_editor_page_general_ref_selected_source (comp_editor
->priv
->page_general
);
1172 if (comp_editor
->priv
->target_client
&&
1173 e_client_get_source (E_CLIENT (comp_editor
->priv
->target_client
)) == source
) {
1174 g_clear_object (&source
);
1178 if (comp_editor
->priv
->target_client_opening
) {
1179 e_activity_cancel (comp_editor
->priv
->target_client_opening
);
1180 g_clear_object (&comp_editor
->priv
->target_client_opening
);
1183 is_target_client_change
= comp_editor
->priv
->target_client
!= NULL
;
1184 g_clear_object (&comp_editor
->priv
->target_client
);
1186 extension_name
= e_comp_editor_page_general_get_source_extension_name (comp_editor
->priv
->page_general
);
1187 source_display_name
= e_util_get_source_full_name (
1188 e_shell_get_registry (e_comp_editor_get_shell (comp_editor
)),
1191 g_return_if_fail (e_util_get_open_source_job_info (extension_name
, source_display_name
,
1192 &description
, &alert_ident
, &alert_arg_0
));
1194 credentials_prompter
= e_shell_get_credentials_prompter (e_comp_editor_get_shell (comp_editor
));
1195 e_credentials_prompter_set_auto_prompt_disabled_for (credentials_prompter
, source
, FALSE
);
1197 otc
= g_new0 (OpenTargetClientData
, 1);
1198 otc
->extension_name
= g_strdup (extension_name
);
1199 otc
->comp_editor
= g_object_ref (comp_editor
);
1200 otc
->source
= g_object_ref (source
);
1201 otc
->is_target_client_change
= is_target_client_change
;
1203 activity
= e_alert_sink_submit_thread_job (
1204 E_ALERT_SINK (comp_editor
), description
, alert_ident
, alert_arg_0
,
1205 comp_editor_open_target_client_thread
, otc
,
1206 open_target_client_data_free
);
1208 otc
->activity
= g_object_ref (activity
);
1209 comp_editor
->priv
->target_client_opening
= g_object_ref (activity
);
1211 /* Close all alerts */
1212 while (e_alert_bar_close_alert (comp_editor
->priv
->alert_bar
)) {
1216 if (comp_editor
->priv
->activity_bar
) {
1217 UpdateActivityBarData
*uab
;
1219 uab
= g_new0 (UpdateActivityBarData
, 1);
1220 uab
->comp_editor
= g_object_ref (comp_editor
);
1221 uab
->activity
= g_object_ref (activity
);
1223 /* To avoid UI flickering when the source can be opened quickly */
1224 g_timeout_add_seconds_full (G_PRIORITY_LOW
, 1,
1225 update_activity_bar_cb
, uab
, update_activity_bar_data_free
);
1228 g_free (description
);
1229 g_free (alert_ident
);
1230 g_free (alert_arg_0
);
1231 g_free (source_display_name
);
1232 g_clear_object (&source
);
1233 g_clear_object (&activity
);
1237 e_comp_editor_update_window_title (ECompEditor
*comp_editor
)
1239 ECompEditorClass
*comp_editor_class
;
1240 gboolean with_attendees
= FALSE
;
1241 const gchar
*format
, *title_suffix
;
1244 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1246 if (comp_editor
->priv
->page_general
)
1247 with_attendees
= e_comp_editor_page_general_get_show_attendees (comp_editor
->priv
->page_general
);
1249 comp_editor_class
= E_COMP_EDITOR_GET_CLASS (comp_editor
);
1251 format
= comp_editor_class
->title_format_with_attendees
;
1253 format
= comp_editor_class
->title_format_without_attendees
;
1255 title_suffix
= e_comp_editor_get_title_suffix (comp_editor
);
1257 title
= g_strdup_printf (format
, title_suffix
&& *title_suffix
? title_suffix
: _("No Summary"));
1259 gtk_window_set_icon_name (GTK_WINDOW (comp_editor
), comp_editor_class
->icon_name
);
1260 gtk_window_set_title (GTK_WINDOW (comp_editor
), title
);
1266 e_comp_editor_close (ECompEditor
*comp_editor
)
1268 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1270 g_signal_emit (comp_editor
, signals
[EDITOR_CLOSED
], 0, FALSE
, NULL
);
1272 gtk_widget_destroy (GTK_WIDGET (comp_editor
));
1276 e_comp_editor_save_and_close (ECompEditor
*comp_editor
,
1279 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1281 if (comp_editor
->priv
->component
) {
1282 icalcomponent
*component
= icalcomponent_new_clone (comp_editor
->priv
->component
);
1283 if (component
&& e_comp_editor_fill_component (comp_editor
, component
)) {
1284 ece_save_component (comp_editor
, component
, TRUE
, can_close
);
1285 icalcomponent_free (component
);
1290 static GtkResponseType
1291 ece_save_component_dialog (ECompEditor
*comp_editor
)
1293 const icalcomponent
*component
;
1296 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), GTK_RESPONSE_NO
);
1297 g_return_val_if_fail (e_comp_editor_get_component (comp_editor
) != NULL
, GTK_RESPONSE_NO
);
1299 parent
= GTK_WINDOW (comp_editor
);
1300 component
= e_comp_editor_get_component (comp_editor
);
1301 switch (icalcomponent_isa (component
)) {
1302 case ICAL_VEVENT_COMPONENT
:
1303 if (e_comp_editor_page_general_get_show_attendees (comp_editor
->priv
->page_general
))
1304 return e_alert_run_dialog_for_args (parent
, "calendar:prompt-save-meeting", NULL
);
1306 return e_alert_run_dialog_for_args (parent
, "calendar:prompt-save-appointment", NULL
);
1307 case ICAL_VTODO_COMPONENT
:
1308 return e_alert_run_dialog_for_args (parent
, "calendar:prompt-save-task", NULL
);
1309 case ICAL_VJOURNAL_COMPONENT
:
1310 return e_alert_run_dialog_for_args (parent
, "calendar:prompt-save-memo", NULL
);
1312 return GTK_RESPONSE_NO
;
1317 e_comp_editor_prompt_and_save_changes (ECompEditor
*comp_editor
,
1320 icalcomponent
*component
;
1322 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
1324 if (!e_comp_editor_get_changed (comp_editor
))
1327 switch (ece_save_component_dialog (comp_editor
)) {
1328 case GTK_RESPONSE_YES
: /* Save */
1329 if (e_client_is_readonly (E_CLIENT (comp_editor
->priv
->target_client
))) {
1331 E_ALERT_SINK (comp_editor
),
1332 "calendar:prompt-read-only-cal-editor",
1333 e_source_get_display_name (
1334 e_client_get_source (E_CLIENT (comp_editor
->priv
->target_client
))),
1336 /* don't discard changes when selected readonly calendar */
1340 if (comp_editor
->priv
->component
&&
1341 e_comp_editor_page_general_get_show_attendees (comp_editor
->priv
->page_general
) &&
1342 icalcomponent_isa (comp_editor
->priv
->component
) == ICAL_VTODO_COMPONENT
1343 && e_client_check_capability (E_CLIENT (comp_editor
->priv
->target_client
), CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT
)) {
1345 E_ALERT_SINK (comp_editor
),
1346 "calendar:prompt-no-task-assignment-editor",
1347 e_source_get_display_name (
1348 e_client_get_source (E_CLIENT (comp_editor
->priv
->target_client
))),
1353 component
= icalcomponent_new_clone (comp_editor
->priv
->component
);
1354 if (!e_comp_editor_fill_component (comp_editor
, component
)) {
1355 icalcomponent_free (component
);
1359 ece_save_component (comp_editor
, component
, with_send
, TRUE
);
1362 case GTK_RESPONSE_NO
: /* Discard */
1364 case GTK_RESPONSE_CANCEL
: /* Cancel */
1373 action_close_cb (GtkAction
*action
,
1374 ECompEditor
*comp_editor
)
1376 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1378 if (e_comp_editor_prompt_and_save_changes (comp_editor
, TRUE
))
1379 e_comp_editor_close (comp_editor
);
1383 action_help_cb (GtkAction
*action
,
1384 ECompEditor
*comp_editor
)
1386 ECompEditorClass
*klass
;
1388 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1390 klass
= E_COMP_EDITOR_GET_CLASS (comp_editor
);
1391 g_return_if_fail (klass
->help_section
!= NULL
);
1393 e_display_help (GTK_WINDOW (comp_editor
), klass
->help_section
);
1397 ece_print_or_preview (ECompEditor
*comp_editor
,
1398 GtkPrintOperationAction print_action
)
1400 icalcomponent
*component
;
1401 ECalComponent
*comp
;
1403 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1404 g_return_if_fail (e_comp_editor_get_component (comp_editor
) != NULL
);
1406 component
= icalcomponent_new_clone (e_comp_editor_get_component (comp_editor
));
1407 if (!e_comp_editor_fill_component (comp_editor
, component
)) {
1408 icalcomponent_free (component
);
1412 comp
= e_cal_component_new_from_icalcomponent (component
);
1413 g_return_if_fail (comp
!= NULL
);
1416 e_comp_editor_get_target_client (comp_editor
),
1417 calendar_config_get_icaltimezone (),
1418 calendar_config_get_24_hour_format (),
1421 g_object_unref (comp
);
1425 action_print_cb (GtkAction
*action
,
1426 ECompEditor
*comp_editor
)
1428 ece_print_or_preview (comp_editor
, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
);
1432 action_print_preview_cb (GtkAction
*action
,
1433 ECompEditor
*comp_editor
)
1435 ece_print_or_preview (comp_editor
, GTK_PRINT_OPERATION_ACTION_PREVIEW
);
1439 action_save_cb (GtkAction
*action
,
1440 ECompEditor
*comp_editor
)
1442 e_comp_editor_save_and_close (comp_editor
, FALSE
);
1446 action_save_and_close_cb (GtkAction
*action
,
1447 ECompEditor
*comp_editor
)
1449 e_comp_editor_save_and_close (comp_editor
, TRUE
);
1453 ece_organizer_email_address_is_user (ECompEditor
*comp_editor
,
1455 const gchar
*email_address
,
1456 gboolean is_organizer
)
1458 ESourceRegistry
*registry
;
1459 const gchar
*cal_email_address
;
1461 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
1462 g_return_val_if_fail (E_IS_CAL_CLIENT (client
), FALSE
);
1464 email_address
= itip_strip_mailto (email_address
);
1466 if (!email_address
|| !*email_address
)
1469 cal_email_address
= e_comp_editor_get_cal_email_address (comp_editor
);
1470 if (cal_email_address
&& *cal_email_address
&&
1471 g_ascii_strcasecmp (cal_email_address
, email_address
) == 0) {
1475 if (is_organizer
&& e_client_check_capability (client
, CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS
))
1478 registry
= e_shell_get_registry (e_comp_editor_get_shell (comp_editor
));
1480 return itip_address_is_user (registry
, email_address
);
1484 ece_organizer_is_user (ECompEditor
*comp_editor
,
1485 icalcomponent
*component
,
1489 const gchar
*organizer
;
1491 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
1492 g_return_val_if_fail (component
!= NULL
, FALSE
);
1493 g_return_val_if_fail (E_IS_CAL_CLIENT (client
), FALSE
);
1495 prop
= icalcomponent_get_first_property (component
, ICAL_ORGANIZER_PROPERTY
);
1496 if (!prop
|| e_client_check_capability (client
, CAL_STATIC_CAPABILITY_NO_ORGANIZER
))
1499 organizer
= itip_strip_mailto (icalproperty_get_organizer (prop
));
1500 if (!organizer
|| !*organizer
)
1503 return ece_organizer_email_address_is_user (comp_editor
, client
, organizer
, TRUE
);
1507 ece_sentby_is_user (ECompEditor
*comp_editor
,
1508 icalcomponent
*component
,
1512 icalparameter
*param
;
1513 const gchar
*sentby
;
1515 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
1516 g_return_val_if_fail (component
!= NULL
, FALSE
);
1517 g_return_val_if_fail (E_IS_CAL_CLIENT (client
), FALSE
);
1519 prop
= icalcomponent_get_first_property (component
, ICAL_ORGANIZER_PROPERTY
);
1520 if (!prop
|| e_client_check_capability (client
, CAL_STATIC_CAPABILITY_NO_ORGANIZER
))
1523 param
= icalproperty_get_first_parameter (prop
, ICAL_SENTBY_PARAMETER
);
1527 sentby
= icalparameter_get_sentby (param
);
1529 return ece_organizer_email_address_is_user (comp_editor
, client
, sentby
, FALSE
);
1533 ece_emit_times_changed_cb (ECompEditor
*comp_editor
)
1535 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1537 g_signal_emit (comp_editor
, signals
[TIMES_CHANGED
], 0, NULL
);
1541 ece_connect_time_parts (ECompEditor
*comp_editor
,
1542 ECompEditorPropertyPart
*dtstart_part
,
1543 ECompEditorPropertyPart
*dtend_part
)
1545 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1547 #define update_part(x) G_STMT_START { \
1550 if (comp_editor->priv->x) { \
1551 g_signal_handlers_disconnect_by_func (comp_editor->priv->x, G_CALLBACK (ece_emit_times_changed_cb), comp_editor); \
1552 g_clear_object (&comp_editor->priv->x); \
1555 comp_editor->priv->x = x; \
1556 g_signal_connect_swapped (comp_editor->priv->x, "changed", \
1557 G_CALLBACK (ece_emit_times_changed_cb), comp_editor); \
1561 update_part (dtstart_part
);
1562 update_part (dtend_part
);
1568 ece_sensitize_widgets (ECompEditor
*comp_editor
,
1569 gboolean force_insensitive
)
1571 GtkActionGroup
*group
;
1574 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1576 for (link
= comp_editor
->priv
->pages
; link
; link
= g_slist_next (link
)) {
1577 ECompEditorPage
*page
= link
->data
;
1579 g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page
));
1580 if (!E_IS_COMP_EDITOR_PAGE (page
))
1583 e_comp_editor_page_sensitize_widgets (page
, force_insensitive
);
1586 group
= e_comp_editor_get_action_group (comp_editor
, "individual");
1587 gtk_action_group_set_sensitive (group
, !force_insensitive
);
1589 group
= e_comp_editor_get_action_group (comp_editor
, "editable");
1590 gtk_action_group_set_sensitive (group
, !force_insensitive
);
1594 ece_fill_widgets (ECompEditor
*comp_editor
,
1595 icalcomponent
*component
)
1599 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1600 g_return_if_fail (component
!= NULL
);
1602 for (link
= comp_editor
->priv
->pages
; link
; link
= g_slist_next (link
)) {
1603 ECompEditorPage
*page
= link
->data
;
1605 g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page
));
1606 if (!E_IS_COMP_EDITOR_PAGE (page
))
1609 e_comp_editor_page_fill_widgets (page
, component
);
1614 ece_fill_component (ECompEditor
*comp_editor
,
1615 icalcomponent
*component
)
1619 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
1620 g_return_val_if_fail (component
!= NULL
, FALSE
);
1622 for (link
= comp_editor
->priv
->pages
; link
; link
= g_slist_next (link
)) {
1623 ECompEditorPage
*page
= link
->data
;
1625 g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page
));
1626 if (!E_IS_COMP_EDITOR_PAGE (page
))
1629 if (!e_comp_editor_page_fill_component (page
, component
))
1637 comp_editor_realize_cb (ECompEditor
*comp_editor
)
1639 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1641 if (comp_editor
->priv
->component
) {
1642 e_comp_editor_fill_widgets (comp_editor
, comp_editor
->priv
->component
);
1643 e_comp_editor_set_changed (comp_editor
, FALSE
);
1646 e_comp_editor_update_window_title (comp_editor
);
1647 e_comp_editor_sensitize_widgets (comp_editor
);
1649 if (comp_editor
->priv
->page_general
&& comp_editor
->priv
->origin_source
) {
1650 e_comp_editor_page_general_set_selected_source (
1651 comp_editor
->priv
->page_general
,
1652 comp_editor
->priv
->origin_source
);
1653 e_comp_editor_set_changed (comp_editor
, FALSE
);
1656 if (comp_editor
->priv
->page_general
) {
1657 e_comp_editor_page_general_update_view (comp_editor
->priv
->page_general
);
1659 if (!comp_editor
->priv
->show_attendees_handler_id
) {
1660 comp_editor
->priv
->show_attendees_handler_id
=
1661 e_signal_connect_notify_swapped (comp_editor
->priv
->page_general
,
1662 "notify::show-attendees",
1663 G_CALLBACK (e_comp_editor_update_window_title
), comp_editor
);
1667 if (!comp_editor
->priv
->target_client
)
1668 e_comp_editor_open_target_client (comp_editor
);
1672 comp_editor_unrealize_cb (ECompEditor
*comp_editor
)
1674 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1676 if (comp_editor
->priv
->page_general
) {
1677 e_signal_disconnect_notify_handler (comp_editor
->priv
->page_general
,
1678 &comp_editor
->priv
->show_attendees_handler_id
);
1683 comp_editor_delete_event (GtkWidget
*widget
,
1686 ECompEditor
*comp_editor
;
1688 g_return_val_if_fail (E_IS_COMP_EDITOR (widget
), FALSE
);
1690 comp_editor
= E_COMP_EDITOR (widget
);
1692 /* It's disabled when the component is being saved */
1693 if (gtk_widget_get_sensitive (GTK_WIDGET (comp_editor
->priv
->content
)))
1694 action_close_cb (NULL
, comp_editor
);
1700 comp_editor_key_press_event (GtkWidget
*widget
,
1703 ECompEditor
*comp_editor
;
1705 g_return_val_if_fail (E_IS_COMP_EDITOR (widget
), FALSE
);
1707 comp_editor
= E_COMP_EDITOR (widget
);
1709 if (event
->keyval
== GDK_KEY_Escape
&&
1710 !e_alert_bar_close_alert (comp_editor
->priv
->alert_bar
)) {
1713 action
= e_comp_editor_get_action (comp_editor
, "close");
1714 gtk_action_activate (action
);
1719 /* Chain up to parent's method. */
1720 return GTK_WIDGET_CLASS (e_comp_editor_parent_class
)->key_press_event (widget
, event
);
1724 comp_editor_selected_source_notify_cb (ECompEditorPageGeneral
*page_general
,
1726 ECompEditor
*comp_editor
)
1728 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general
));
1729 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1730 g_return_if_fail (comp_editor
->priv
->page_general
== page_general
);
1732 e_comp_editor_open_target_client (comp_editor
);
1736 e_comp_editor_submit_alert (EAlertSink
*alert_sink
,
1739 ECompEditor
*comp_editor
;
1741 g_return_if_fail (E_IS_COMP_EDITOR (alert_sink
));
1742 g_return_if_fail (E_IS_ALERT (alert
));
1744 comp_editor
= E_COMP_EDITOR (alert_sink
);
1746 e_alert_bar_submit_alert (comp_editor
->priv
->alert_bar
, alert
);
1750 e_comp_editor_set_origin_source (ECompEditor
*comp_editor
,
1751 ESource
*origin_source
)
1753 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1755 g_return_if_fail (E_IS_SOURCE (origin_source
));
1757 g_clear_object (&comp_editor
->priv
->origin_source
);
1759 comp_editor
->priv
->origin_source
= g_object_ref (origin_source
);
1763 e_comp_editor_set_shell (ECompEditor
*comp_editor
,
1766 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
1767 g_return_if_fail (E_IS_SHELL (shell
));
1769 g_clear_object (&comp_editor
->priv
->shell
);
1770 comp_editor
->priv
->shell
= g_object_ref (shell
);
1774 e_comp_editor_set_property (GObject
*object
,
1776 const GValue
*value
,
1779 switch (property_id
) {
1780 case PROP_ALARM_EMAIL_ADDRESS
:
1781 e_comp_editor_set_alarm_email_address (
1782 E_COMP_EDITOR (object
),
1783 g_value_get_string (value
));
1786 case PROP_CAL_EMAIL_ADDRESS
:
1787 e_comp_editor_set_cal_email_address (
1788 E_COMP_EDITOR (object
),
1789 g_value_get_string (value
));
1793 e_comp_editor_set_changed (
1794 E_COMP_EDITOR (object
),
1795 g_value_get_boolean (value
));
1798 case PROP_COMPONENT
:
1799 e_comp_editor_set_component (
1800 E_COMP_EDITOR (object
),
1801 g_value_get_pointer (value
));
1805 e_comp_editor_set_flags (
1806 E_COMP_EDITOR (object
),
1807 g_value_get_uint (value
));
1810 case PROP_ORIGIN_SOURCE
:
1811 e_comp_editor_set_origin_source (
1812 E_COMP_EDITOR (object
),
1813 g_value_get_object (value
));
1817 e_comp_editor_set_shell (
1818 E_COMP_EDITOR (object
),
1819 g_value_get_object (value
));
1822 case PROP_SOURCE_CLIENT
:
1823 e_comp_editor_set_source_client (
1824 E_COMP_EDITOR (object
),
1825 g_value_get_object (value
));
1828 case PROP_TARGET_CLIENT
:
1829 e_comp_editor_set_target_client (
1830 E_COMP_EDITOR (object
),
1831 g_value_get_object (value
));
1834 case PROP_TITLE_SUFFIX
:
1835 e_comp_editor_set_title_suffix (
1836 E_COMP_EDITOR (object
),
1837 g_value_get_string (value
));
1841 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1845 e_comp_editor_get_property (GObject
*object
,
1850 switch (property_id
) {
1851 case PROP_ALARM_EMAIL_ADDRESS
:
1852 g_value_set_string (
1854 e_comp_editor_get_alarm_email_address (
1855 E_COMP_EDITOR (object
)));
1858 case PROP_CAL_EMAIL_ADDRESS
:
1859 g_value_set_string (
1861 e_comp_editor_get_cal_email_address (
1862 E_COMP_EDITOR (object
)));
1866 g_value_set_boolean (
1868 e_comp_editor_get_changed (
1869 E_COMP_EDITOR (object
)));
1872 case PROP_COMPONENT
:
1873 g_value_set_pointer (
1875 e_comp_editor_get_component (
1876 E_COMP_EDITOR (object
)));
1882 e_comp_editor_get_flags (
1883 E_COMP_EDITOR (object
)));
1886 case PROP_ORIGIN_SOURCE
:
1887 g_value_set_object (
1889 e_comp_editor_get_origin_source (
1890 E_COMP_EDITOR (object
)));
1894 g_value_set_object (
1896 e_comp_editor_get_shell (
1897 E_COMP_EDITOR (object
)));
1900 case PROP_SOURCE_CLIENT
:
1901 g_value_set_object (
1903 e_comp_editor_get_source_client (
1904 E_COMP_EDITOR (object
)));
1907 case PROP_TARGET_CLIENT
:
1908 g_value_set_object (
1910 e_comp_editor_get_target_client (
1911 E_COMP_EDITOR (object
)));
1914 case PROP_TITLE_SUFFIX
:
1915 g_value_set_string (
1917 e_comp_editor_get_title_suffix (
1918 E_COMP_EDITOR (object
)));
1922 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1926 e_comp_editor_constructed (GObject
*object
)
1930 " <menubar action='main-menu'>"
1931 " <menu action='file-menu'>"
1932 " <menuitem action='save'/>"
1933 " <menuitem action='save-and-close'/>"
1935 " <placeholder name='custom-actions-placeholder'/>"
1937 " <menuitem action='print-preview'/>"
1938 " <menuitem action='print'/>"
1940 " <menuitem action='close'/>"
1942 " <menu action='edit-menu'>"
1943 " <menuitem action='undo'/>"
1944 " <menuitem action='redo'/>"
1946 " <menuitem action='cut-clipboard'/>"
1947 " <menuitem action='copy-clipboard'/>"
1948 " <menuitem action='paste-clipboard'/>"
1949 " <menuitem action='delete-selection'/>"
1951 " <menuitem action='select-all'/>"
1953 " <menu action='view-menu'>"
1954 " <placeholder name='parts'/>"
1956 " <placeholder name='columns'/>"
1958 " <menu action='insert-menu'/>"
1959 " <menu action='options-menu'>"
1960 " <placeholder name='tabs'/>"
1961 " <placeholder name='toggles'/>"
1963 " <menu action='help-menu'>"
1964 " <menuitem action='help'/>"
1967 " <toolbar name='main-toolbar'>"
1968 " <toolitem action='save-and-close'/>\n"
1969 " <toolitem action='save'/>"
1970 " <toolitem action='print'/>"
1972 " <toolitem action='undo'/>"
1973 " <toolitem action='redo'/>"
1975 " <placeholder name='content'/>"
1976 " <placeholder name='after-content'/>"
1980 GtkActionEntry core_entries
[] = {
1986 N_("Close the current window"),
1987 G_CALLBACK (action_close_cb
) },
1993 N_("Copy the selection"),
1994 NULL
}, /* Handled by EFocusTracker */
2000 N_("Cut the selection"),
2001 NULL
}, /* Handled by EFocusTracker */
2003 { "delete-selection",
2007 N_("Delete the selection"),
2008 NULL
}, /* Handled by EFocusTracker */
2015 G_CALLBACK (action_help_cb
) },
2017 { "paste-clipboard",
2021 N_("Paste the clipboard"),
2022 NULL
}, /* Handled by EFocusTracker */
2029 G_CALLBACK (action_print_cb
) },
2032 "document-print-preview",
2036 G_CALLBACK (action_print_preview_cb
) },
2042 N_("Select all text"),
2043 NULL
}, /* Handled by EFocusTracker */
2050 NULL
}, /* Handled by EFocusTracker */
2057 NULL
}, /* Handled by EFocusTracker */
2061 { "classification-menu",
2063 N_("_Classification"),
2111 GtkActionEntry editable_entries
[] = {
2117 N_("Save current changes"),
2118 G_CALLBACK (action_save_cb
) },
2122 N_("Save and Close"),
2124 N_("Save current changes and close editor"),
2125 G_CALLBACK (action_save_and_close_cb
) }
2128 ECompEditor
*comp_editor
= E_COMP_EDITOR (object
);
2132 GtkActionGroup
*action_group
;
2133 EFocusTracker
*focus_tracker
;
2134 GError
*error
= NULL
;
2136 G_OBJECT_CLASS (e_comp_editor_parent_class
)->constructed (object
);
2138 g_signal_connect (comp_editor
, "key-press-event",
2139 G_CALLBACK (e_util_check_gtk_bindings_in_key_press_event_cb
), NULL
);
2141 comp_editor
->priv
->calendar_settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
2142 comp_editor
->priv
->ui_manager
= gtk_ui_manager_new ();
2144 gtk_window_add_accel_group (
2145 GTK_WINDOW (comp_editor
),
2146 gtk_ui_manager_get_accel_group (comp_editor
->priv
->ui_manager
));
2148 /* Setup Action Groups */
2150 action_group
= gtk_action_group_new ("individual");
2151 gtk_action_group_set_translation_domain (
2152 action_group
, GETTEXT_PACKAGE
);
2153 gtk_ui_manager_insert_action_group (
2154 comp_editor
->priv
->ui_manager
, action_group
, 0);
2155 g_object_unref (action_group
);
2157 action_group
= gtk_action_group_new ("core");
2158 gtk_action_group_set_translation_domain (
2159 action_group
, GETTEXT_PACKAGE
);
2160 gtk_action_group_add_actions (
2161 action_group
, core_entries
,
2162 G_N_ELEMENTS (core_entries
), comp_editor
);
2163 gtk_ui_manager_insert_action_group (
2164 comp_editor
->priv
->ui_manager
, action_group
, 0);
2165 g_object_unref (action_group
);
2167 action_group
= gtk_action_group_new ("editable");
2168 gtk_action_group_set_translation_domain (
2169 action_group
, GETTEXT_PACKAGE
);
2170 gtk_action_group_add_actions (
2171 action_group
, editable_entries
,
2172 G_N_ELEMENTS (editable_entries
), comp_editor
);
2173 gtk_ui_manager_insert_action_group (
2174 comp_editor
->priv
->ui_manager
, action_group
, 0);
2175 g_object_unref (action_group
);
2177 action
= gtk_action_group_get_action (action_group
, "save-and-close");
2179 GtkAction
*save_action
;
2181 GIcon
*emblemed_icon
;
2184 icon
= g_themed_icon_new ("window-close");
2185 emblemed_icon
= g_themed_icon_new ("document-save");
2186 emblem
= g_emblem_new (emblemed_icon
);
2187 g_object_unref (emblemed_icon
);
2189 emblemed_icon
= g_emblemed_icon_new (icon
, emblem
);
2190 g_object_unref (emblem
);
2191 g_object_unref (icon
);
2193 gtk_action_set_gicon (action
, emblemed_icon
);
2195 g_object_unref (emblemed_icon
);
2197 save_action
= gtk_action_group_get_action (action_group
, "save");
2198 e_binding_bind_property (
2199 save_action
, "sensitive",
2200 action
, "sensitive",
2201 G_BINDING_SYNC_CREATE
);
2204 gtk_ui_manager_add_ui_from_string (comp_editor
->priv
->ui_manager
, ui
, -1, &error
);
2205 if (error
!= NULL
) {
2206 g_warning ("%s: %s", G_STRFUNC
, error
->message
);
2207 g_error_free (error
);
2210 widget
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
2211 g_object_set (G_OBJECT (widget
),
2213 "halign", GTK_ALIGN_FILL
,
2215 "valign", GTK_ALIGN_FILL
,
2217 gtk_widget_show (widget
);
2219 vbox
= GTK_BOX (widget
);
2221 gtk_container_add (GTK_CONTAINER (comp_editor
), widget
);
2223 widget
= e_comp_editor_get_managed_widget (comp_editor
, "/main-menu");
2224 gtk_box_pack_start (GTK_BOX (vbox
), widget
, FALSE
, FALSE
, 0);
2225 gtk_widget_set_visible (widget
, TRUE
);
2227 widget
= e_comp_editor_get_managed_widget (comp_editor
, "/main-toolbar");
2228 gtk_box_pack_start (GTK_BOX (vbox
), widget
, FALSE
, FALSE
, 0);
2229 gtk_widget_show (widget
);
2231 gtk_style_context_add_class (
2232 gtk_widget_get_style_context (widget
),
2233 GTK_STYLE_CLASS_PRIMARY_TOOLBAR
);
2235 widget
= e_alert_bar_new ();
2236 g_object_set (G_OBJECT (widget
),
2238 "halign", GTK_ALIGN_FILL
,
2240 "valign", GTK_ALIGN_START
,
2243 comp_editor
->priv
->alert_bar
= E_ALERT_BAR (widget
);
2245 gtk_box_pack_start (vbox
, widget
, FALSE
, FALSE
, 0);
2247 widget
= e_activity_bar_new ();
2248 g_object_set (G_OBJECT (widget
),
2250 "halign", GTK_ALIGN_FILL
,
2252 "valign", GTK_ALIGN_START
,
2255 comp_editor
->priv
->activity_bar
= E_ACTIVITY_BAR (widget
);
2257 gtk_box_pack_start (vbox
, widget
, FALSE
, FALSE
, 0);
2259 widget
= gtk_notebook_new ();
2260 g_object_set (G_OBJECT (widget
),
2262 "halign", GTK_ALIGN_FILL
,
2264 "valign", GTK_ALIGN_FILL
,
2266 "show-border", FALSE
,
2268 gtk_widget_show (widget
);
2270 comp_editor
->priv
->content
= GTK_NOTEBOOK (widget
);
2272 gtk_box_pack_start (vbox
, widget
, TRUE
, TRUE
, 0);
2274 /* Configure an EFocusTracker to manage selection actions. */
2276 focus_tracker
= e_focus_tracker_new (GTK_WINDOW (comp_editor
));
2278 action
= e_comp_editor_get_action (comp_editor
, "cut-clipboard");
2279 e_focus_tracker_set_cut_clipboard_action (focus_tracker
, action
);
2281 action
= e_comp_editor_get_action (comp_editor
, "copy-clipboard");
2282 e_focus_tracker_set_copy_clipboard_action (focus_tracker
, action
);
2284 action
= e_comp_editor_get_action (comp_editor
, "paste-clipboard");
2285 e_focus_tracker_set_paste_clipboard_action (focus_tracker
, action
);
2287 action
= e_comp_editor_get_action (comp_editor
, "delete-selection");
2288 e_focus_tracker_set_delete_selection_action (focus_tracker
, action
);
2290 action
= e_comp_editor_get_action (comp_editor
, "select-all");
2291 e_focus_tracker_set_select_all_action (focus_tracker
, action
);
2293 action
= e_comp_editor_get_action (comp_editor
, "undo");
2294 e_focus_tracker_set_undo_action (focus_tracker
, action
);
2296 action
= e_comp_editor_get_action (comp_editor
, "redo");
2297 e_focus_tracker_set_redo_action (focus_tracker
, action
);
2299 comp_editor
->priv
->focus_tracker
= focus_tracker
;
2301 /* Desensitize the "save" action. */
2302 action
= e_comp_editor_get_action (comp_editor
, "save");
2303 gtk_action_set_sensitive (action
, FALSE
);
2305 e_binding_bind_property (comp_editor
, "changed", action
, "sensitive", 0);
2307 g_signal_connect (comp_editor
, "realize", G_CALLBACK (comp_editor_realize_cb
), NULL
);
2308 g_signal_connect (comp_editor
, "unrealize", G_CALLBACK (comp_editor_unrealize_cb
), NULL
);
2310 gtk_application_add_window (GTK_APPLICATION (comp_editor
->priv
->shell
), GTK_WINDOW (comp_editor
));
2312 e_extensible_load_extensions (E_EXTENSIBLE (comp_editor
));
2316 e_comp_editor_dispose (GObject
*object
)
2318 ECompEditor
*comp_editor
= E_COMP_EDITOR (object
);
2320 if (comp_editor
->priv
->page_general
) {
2321 g_signal_handlers_disconnect_by_func (comp_editor
->priv
->page_general
,
2322 G_CALLBACK (comp_editor_selected_source_notify_cb
), comp_editor
);
2323 comp_editor
->priv
->page_general
= NULL
;
2326 if (comp_editor
->priv
->target_client_opening
) {
2327 e_activity_cancel (comp_editor
->priv
->target_client_opening
);
2328 g_clear_object (&comp_editor
->priv
->target_client_opening
);
2331 g_slist_free_full (comp_editor
->priv
->pages
, g_object_unref
);
2332 comp_editor
->priv
->pages
= NULL
;
2334 g_free (comp_editor
->priv
->alarm_email_address
);
2335 comp_editor
->priv
->alarm_email_address
= NULL
;
2337 g_free (comp_editor
->priv
->cal_email_address
);
2338 comp_editor
->priv
->cal_email_address
= NULL
;
2340 g_free (comp_editor
->priv
->title_suffix
);
2341 comp_editor
->priv
->title_suffix
= NULL
;
2343 if (comp_editor
->priv
->component
) {
2344 icalcomponent_free (comp_editor
->priv
->component
);
2345 comp_editor
->priv
->component
= NULL
;
2348 ece_connect_time_parts (comp_editor
, NULL
, NULL
);
2350 g_clear_object (&comp_editor
->priv
->origin_source
);
2351 g_clear_object (&comp_editor
->priv
->shell
);
2352 g_clear_object (&comp_editor
->priv
->focus_tracker
);
2353 g_clear_object (&comp_editor
->priv
->ui_manager
);
2354 g_clear_object (&comp_editor
->priv
->source_client
);
2355 g_clear_object (&comp_editor
->priv
->target_client
);
2356 g_clear_object (&comp_editor
->priv
->calendar_settings
);
2357 g_clear_object (&comp_editor
->priv
->validation_alert
);
2359 comp_editor
->priv
->activity_bar
= NULL
;
2361 opened_editors
= g_slist_remove (opened_editors
, comp_editor
);
2363 G_OBJECT_CLASS (e_comp_editor_parent_class
)->dispose (object
);
2367 e_comp_editor_init (ECompEditor
*comp_editor
)
2369 comp_editor
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (comp_editor
, E_TYPE_COMP_EDITOR
, ECompEditorPrivate
);
2373 e_comp_editor_alert_sink_iface_init (EAlertSinkInterface
*iface
)
2375 iface
->submit_alert
= e_comp_editor_submit_alert
;
2379 e_comp_editor_class_init (ECompEditorClass
*klass
)
2381 GtkWidgetClass
*widget_class
;
2382 GObjectClass
*object_class
;
2384 g_type_class_add_private (klass
, sizeof (ECompEditorPrivate
));
2386 klass
->sensitize_widgets
= ece_sensitize_widgets
;
2387 klass
->fill_widgets
= ece_fill_widgets
;
2388 klass
->fill_component
= ece_fill_component
;
2390 widget_class
= GTK_WIDGET_CLASS (klass
);
2391 widget_class
->delete_event
= comp_editor_delete_event
;
2392 widget_class
->key_press_event
= comp_editor_key_press_event
;
2394 object_class
= G_OBJECT_CLASS (klass
);
2395 object_class
->set_property
= e_comp_editor_set_property
;
2396 object_class
->get_property
= e_comp_editor_get_property
;
2397 object_class
->constructed
= e_comp_editor_constructed
;
2398 object_class
->dispose
= e_comp_editor_dispose
;
2400 g_object_class_install_property (
2402 PROP_ALARM_EMAIL_ADDRESS
,
2403 g_param_spec_string (
2404 "alarm-email-address",
2405 "Alarm Email Address",
2406 "Target client's alarm email address",
2409 G_PARAM_STATIC_STRINGS
));
2411 g_object_class_install_property (
2413 PROP_CAL_EMAIL_ADDRESS
,
2414 g_param_spec_string (
2415 "cal-email-address",
2416 "Calendar Email Address",
2417 "Target client's calendar email address",
2420 G_PARAM_STATIC_STRINGS
));
2422 g_object_class_install_property (
2425 g_param_spec_boolean (
2428 "Whether the editor content changed",
2431 G_PARAM_STATIC_STRINGS
));
2433 g_object_class_install_property (
2436 g_param_spec_pointer (
2439 "icalcomponent currently edited",
2441 G_PARAM_CONSTRUCT_ONLY
|
2442 G_PARAM_STATIC_STRINGS
));
2444 g_object_class_install_property (
2453 G_PARAM_CONSTRUCT_ONLY
|
2454 G_PARAM_STATIC_STRINGS
));
2456 g_object_class_install_property (
2459 g_param_spec_object (
2462 "ESource of an ECalClient the component is stored in",
2465 G_PARAM_CONSTRUCT_ONLY
|
2466 G_PARAM_STATIC_STRINGS
));
2468 g_object_class_install_property (
2471 g_param_spec_object (
2477 G_PARAM_CONSTRUCT_ONLY
|
2478 G_PARAM_STATIC_STRINGS
));
2480 g_object_class_install_property (
2483 g_param_spec_object (
2486 "ECalClient, the source calendar for the component",
2489 G_PARAM_STATIC_STRINGS
));
2491 g_object_class_install_property (
2494 g_param_spec_object (
2497 "ECalClient currently set as the target calendar for the component",
2500 G_PARAM_STATIC_STRINGS
));
2502 g_object_class_install_property (
2505 g_param_spec_string (
2508 "Window title suffix, usually summary of the component",
2511 G_PARAM_STATIC_STRINGS
));
2513 signals
[TIMES_CHANGED
] = g_signal_new (
2515 G_TYPE_FROM_CLASS (klass
),
2517 G_STRUCT_OFFSET (ECompEditorClass
, times_changed
),
2522 signals
[OBJECT_CREATED
] = g_signal_new (
2524 G_TYPE_FROM_CLASS (klass
),
2526 G_STRUCT_OFFSET (ECompEditorClass
, object_created
),
2531 signals
[EDITOR_CLOSED
] = g_signal_new (
2533 G_TYPE_FROM_CLASS (klass
),
2535 G_STRUCT_OFFSET (ECompEditorClass
, editor_closed
),
2537 g_cclosure_marshal_VOID__BOOLEAN
,
2538 G_TYPE_NONE
, 1, G_TYPE_BOOLEAN
);
2542 e_comp_editor_sensitize_widgets (ECompEditor
*comp_editor
)
2544 ECompEditorClass
*comp_editor_class
;
2545 gboolean force_insensitive
;
2546 GtkWidget
*current_focus
;
2548 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2550 comp_editor_class
= E_COMP_EDITOR_GET_CLASS (comp_editor
);
2551 g_return_if_fail (comp_editor_class
!= NULL
);
2552 g_return_if_fail (comp_editor_class
->sensitize_widgets
!= NULL
);
2554 current_focus
= gtk_window_get_focus (GTK_WINDOW (comp_editor
));
2556 force_insensitive
= !comp_editor
->priv
->component
;
2558 if (!force_insensitive
) {
2559 ECalClient
*target_client
;
2561 target_client
= e_comp_editor_get_target_client (comp_editor
);
2562 if (target_client
) {
2563 EClient
*client
= E_CLIENT (target_client
);
2565 if (e_client_is_readonly (client
)) {
2566 force_insensitive
= TRUE
;
2568 if (!e_cal_util_component_has_organizer (comp_editor
->priv
->component
) ||
2569 ece_organizer_is_user (comp_editor
, comp_editor
->priv
->component
, client
) ||
2570 ece_sentby_is_user (comp_editor
, comp_editor
->priv
->component
, client
)) {
2571 comp_editor
->priv
->flags
= comp_editor
->priv
->flags
| E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER
;
2573 comp_editor
->priv
->flags
= comp_editor
->priv
->flags
& (~E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER
);
2577 force_insensitive
= TRUE
;
2581 comp_editor_class
->sensitize_widgets (comp_editor
, force_insensitive
);
2583 if (force_insensitive
)
2584 comp_editor
->priv
->restore_focus
= current_focus
;
2586 ece_restore_focus (comp_editor
);
2590 e_comp_editor_fill_widgets (ECompEditor
*comp_editor
,
2591 icalcomponent
*component
)
2593 ECompEditorClass
*comp_editor_class
;
2595 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2596 g_return_if_fail (component
!= NULL
);
2598 comp_editor_class
= E_COMP_EDITOR_GET_CLASS (comp_editor
);
2599 g_return_if_fail (comp_editor_class
!= NULL
);
2600 g_return_if_fail (comp_editor_class
->fill_widgets
!= NULL
);
2602 e_comp_editor_set_updating (comp_editor
, TRUE
);
2604 comp_editor_class
->fill_widgets (comp_editor
, component
);
2606 e_comp_editor_set_updating (comp_editor
, FALSE
);
2610 e_comp_editor_fill_component (ECompEditor
*comp_editor
,
2611 icalcomponent
*component
)
2613 ECompEditorClass
*comp_editor_class
;
2616 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
2617 g_return_val_if_fail (component
!= NULL
, FALSE
);
2619 comp_editor_class
= E_COMP_EDITOR_GET_CLASS (comp_editor
);
2620 g_return_val_if_fail (comp_editor_class
!= NULL
, FALSE
);
2621 g_return_val_if_fail (comp_editor_class
->fill_component
!= NULL
, FALSE
);
2623 is_valid
= comp_editor_class
->fill_component (comp_editor
, component
);
2625 if (is_valid
&& comp_editor
->priv
->validation_alert
) {
2626 e_alert_response (comp_editor
->priv
->validation_alert
, GTK_RESPONSE_CLOSE
);
2627 g_clear_object (&comp_editor
->priv
->validation_alert
);
2631 ECalClient
*target_client
;
2632 EClient
*client
= NULL
;
2634 target_client
= e_comp_editor_get_target_client (comp_editor
);
2636 client
= E_CLIENT (target_client
);
2638 if (!e_cal_util_component_has_organizer (component
) || (client
&& (
2639 ece_organizer_is_user (comp_editor
, component
, client
) ||
2640 ece_sentby_is_user (comp_editor
, component
, client
)))) {
2643 sequence
= icalcomponent_get_sequence (component
);
2644 icalcomponent_set_sequence (component
, sequence
+ 1);
2652 e_comp_editor_set_validation_error (ECompEditor
*comp_editor
,
2653 ECompEditorPage
*error_page
,
2654 GtkWidget
*error_widget
,
2655 const gchar
*error_message
)
2657 EAlert
*alert
, *previous_alert
;
2659 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2660 g_return_if_fail (error_message
!= NULL
);
2662 /* Ignore validation errors when the inner editor is currently updating. */
2663 if (e_comp_editor_get_updating (comp_editor
))
2666 alert
= e_alert_new ("calendar:comp-editor-failed-validate", error_message
, NULL
);
2668 e_alert_bar_add_alert (comp_editor
->priv
->alert_bar
, alert
);
2670 previous_alert
= comp_editor
->priv
->validation_alert
;
2671 comp_editor
->priv
->validation_alert
= alert
;
2673 if (previous_alert
) {
2674 e_alert_response (previous_alert
, GTK_RESPONSE_CLOSE
);
2675 g_clear_object (&previous_alert
);
2679 e_comp_editor_select_page (comp_editor
, error_page
);
2682 gtk_widget_grab_focus (error_widget
);
2686 e_comp_editor_get_shell (ECompEditor
*comp_editor
)
2688 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2690 return comp_editor
->priv
->shell
;
2694 e_comp_editor_get_settings (ECompEditor
*comp_editor
)
2696 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2698 return comp_editor
->priv
->calendar_settings
;
2702 e_comp_editor_get_origin_source (ECompEditor
*comp_editor
)
2704 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2706 return comp_editor
->priv
->origin_source
;
2710 e_comp_editor_get_component (ECompEditor
*comp_editor
)
2712 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2714 return comp_editor
->priv
->component
;
2718 e_comp_editor_get_flags (ECompEditor
*comp_editor
)
2720 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), 0);
2722 return comp_editor
->priv
->flags
;
2726 e_comp_editor_set_flags (ECompEditor
*comp_editor
,
2729 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2731 if (comp_editor
->priv
->flags
== flags
)
2734 comp_editor
->priv
->flags
= flags
;
2736 g_object_notify (G_OBJECT (comp_editor
), "flags");
2740 e_comp_editor_get_focus_tracker (ECompEditor
*comp_editor
)
2742 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2744 return comp_editor
->priv
->focus_tracker
;
2748 e_comp_editor_get_ui_manager (ECompEditor
*comp_editor
)
2750 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2752 return comp_editor
->priv
->ui_manager
;
2756 e_comp_editor_get_action (ECompEditor
*comp_editor
,
2757 const gchar
*action_name
)
2759 GtkUIManager
*ui_manager
;
2761 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2762 g_return_val_if_fail (action_name
!= NULL
, NULL
);
2764 ui_manager
= e_comp_editor_get_ui_manager (comp_editor
);
2766 return e_lookup_action (ui_manager
, action_name
);
2770 e_comp_editor_get_action_group (ECompEditor
*comp_editor
,
2771 const gchar
*group_name
)
2773 GtkUIManager
*ui_manager
;
2775 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2776 g_return_val_if_fail (group_name
!= NULL
, NULL
);
2778 ui_manager
= e_comp_editor_get_ui_manager (comp_editor
);
2780 return e_lookup_action_group (ui_manager
, group_name
);
2784 e_comp_editor_get_managed_widget (ECompEditor
*comp_editor
,
2785 const gchar
*widget_path
)
2787 GtkUIManager
*ui_manager
;
2790 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2791 g_return_val_if_fail (widget_path
!= NULL
, NULL
);
2793 ui_manager
= e_comp_editor_get_ui_manager (comp_editor
);
2794 widget
= gtk_ui_manager_get_widget (ui_manager
, widget_path
);
2795 g_return_val_if_fail (widget
!= NULL
, NULL
);
2801 e_comp_editor_get_alarm_email_address (ECompEditor
*comp_editor
)
2803 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2805 return comp_editor
->priv
->alarm_email_address
;
2809 e_comp_editor_set_alarm_email_address (ECompEditor
*comp_editor
,
2810 const gchar
*alarm_email_address
)
2812 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2814 if (g_strcmp0 (alarm_email_address
, comp_editor
->priv
->alarm_email_address
) == 0)
2817 g_free (comp_editor
->priv
->alarm_email_address
);
2818 comp_editor
->priv
->alarm_email_address
= g_strdup (alarm_email_address
);
2820 g_object_notify (G_OBJECT (comp_editor
), "alarm-email-address");
2824 e_comp_editor_get_cal_email_address (ECompEditor
*comp_editor
)
2826 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2828 return comp_editor
->priv
->cal_email_address
;
2832 e_comp_editor_set_cal_email_address (ECompEditor
*comp_editor
,
2833 const gchar
*cal_email_address
)
2835 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2837 if (g_strcmp0 (cal_email_address
, comp_editor
->priv
->cal_email_address
) == 0)
2840 g_free (comp_editor
->priv
->cal_email_address
);
2841 comp_editor
->priv
->cal_email_address
= g_strdup (cal_email_address
);
2843 g_object_notify (G_OBJECT (comp_editor
), "cal-email-address");
2847 e_comp_editor_get_changed (ECompEditor
*comp_editor
)
2849 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
2851 return comp_editor
->priv
->changed
;
2855 e_comp_editor_set_changed (ECompEditor
*comp_editor
,
2858 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2860 if ((changed
? 1 : 0) == (comp_editor
->priv
->changed
? 1 : 0))
2863 comp_editor
->priv
->changed
= changed
;
2865 g_object_notify (G_OBJECT (comp_editor
), "changed");
2869 e_comp_editor_ensure_changed (ECompEditor
*comp_editor
)
2871 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2873 e_comp_editor_set_changed (comp_editor
, TRUE
);
2877 e_comp_editor_get_updating (ECompEditor
*comp_editor
)
2879 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
2881 return comp_editor
->priv
->updating
> 0;
2885 e_comp_editor_set_updating (ECompEditor
*comp_editor
,
2888 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2891 comp_editor
->priv
->updating
++;
2892 } else if (comp_editor
->priv
->updating
> 0) {
2893 comp_editor
->priv
->updating
--;
2895 g_warn_if_reached ();
2900 e_comp_editor_get_source_client (ECompEditor
*comp_editor
)
2902 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2904 return comp_editor
->priv
->source_client
;
2908 e_comp_editor_set_source_client (ECompEditor
*comp_editor
,
2911 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2913 if (client
== comp_editor
->priv
->source_client
)
2917 g_object_ref (client
);
2918 g_clear_object (&comp_editor
->priv
->source_client
);
2919 comp_editor
->priv
->source_client
= client
;
2921 g_object_notify (G_OBJECT (comp_editor
), "source-client");
2925 e_comp_editor_get_target_client (ECompEditor
*comp_editor
)
2927 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2929 return comp_editor
->priv
->target_client
;
2933 e_comp_editor_set_target_client (ECompEditor
*comp_editor
,
2936 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2938 if (client
== comp_editor
->priv
->target_client
)
2942 g_object_ref (client
);
2943 g_clear_object (&comp_editor
->priv
->target_client
);
2944 comp_editor
->priv
->target_client
= client
;
2946 g_object_notify (G_OBJECT (comp_editor
), "target-client");
2948 if (client
&& !comp_editor
->priv
->source_client
&& comp_editor
->priv
->origin_source
&&
2949 e_source_equal (e_client_get_source (E_CLIENT (client
)), comp_editor
->priv
->origin_source
))
2950 e_comp_editor_set_source_client (comp_editor
, client
);
2952 e_comp_editor_sensitize_widgets (comp_editor
);
2956 e_comp_editor_get_title_suffix (ECompEditor
*comp_editor
)
2958 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
2960 return comp_editor
->priv
->title_suffix
;
2964 e_comp_editor_set_title_suffix (ECompEditor
*comp_editor
,
2965 const gchar
*title_suffix
)
2967 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2969 if (g_strcmp0 (title_suffix
, comp_editor
->priv
->title_suffix
) == 0)
2972 g_free (comp_editor
->priv
->title_suffix
);
2973 comp_editor
->priv
->title_suffix
= g_strdup (title_suffix
);
2975 g_object_notify (G_OBJECT (comp_editor
), "title-suffix");
2977 e_comp_editor_update_window_title (comp_editor
);
2981 e_comp_editor_set_time_parts (ECompEditor
*comp_editor
,
2982 ECompEditorPropertyPart
*dtstart_part
,
2983 ECompEditorPropertyPart
*dtend_part
)
2985 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
2988 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (dtstart_part
));
2990 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (dtend_part
));
2992 ece_connect_time_parts (comp_editor
, dtstart_part
, dtend_part
);
2996 e_comp_editor_get_time_parts (ECompEditor
*comp_editor
,
2997 ECompEditorPropertyPart
**out_dtstart_part
,
2998 ECompEditorPropertyPart
**out_dtend_part
)
3000 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
3002 if (out_dtstart_part
)
3003 *out_dtstart_part
= comp_editor
->priv
->dtstart_part
;
3005 *out_dtend_part
= comp_editor
->priv
->dtend_part
;
3008 /* This consumes the @page. */
3010 e_comp_editor_add_page (ECompEditor
*comp_editor
,
3012 ECompEditorPage
*page
)
3014 ECompEditor
*pages_comp_editor
;
3016 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
3017 g_return_if_fail (label
!= NULL
);
3018 g_return_if_fail (E_IS_COMP_EDITOR_PAGE (page
));
3020 pages_comp_editor
= e_comp_editor_page_ref_editor (page
);
3021 if (pages_comp_editor
!= comp_editor
) {
3022 g_warn_if_fail (pages_comp_editor
== comp_editor
);
3023 g_clear_object (&pages_comp_editor
);
3027 g_clear_object (&pages_comp_editor
);
3029 /* One reference uses the GtkNotebook, the other the pages GSList */
3030 gtk_notebook_append_page (comp_editor
->priv
->content
,
3032 gtk_label_new_with_mnemonic (label
));
3034 comp_editor
->priv
->pages
= g_slist_append (comp_editor
->priv
->pages
, g_object_ref (page
));
3036 g_signal_connect_swapped (page
, "changed", G_CALLBACK (e_comp_editor_ensure_changed
), comp_editor
);
3038 if (E_IS_COMP_EDITOR_PAGE_GENERAL (page
)) {
3039 ECompEditorPageGeneral
*page_general
;
3041 g_return_if_fail (comp_editor
->priv
->page_general
== NULL
);
3043 page_general
= E_COMP_EDITOR_PAGE_GENERAL (page
);
3045 g_signal_connect (page_general
, "notify::selected-source",
3046 G_CALLBACK (comp_editor_selected_source_notify_cb
), comp_editor
);
3048 comp_editor
->priv
->page_general
= page_general
;
3050 if ((comp_editor
->priv
->flags
& E_COMP_EDITOR_FLAG_WITH_ATTENDEES
) != 0) {
3051 e_comp_editor_page_general_set_show_attendees (page_general
, TRUE
);
3056 /* The returned pointer is owned by the @comp_editor; returns the first instance,
3057 in order of the addition. */
3059 e_comp_editor_get_page (ECompEditor
*comp_editor
,
3064 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
3065 g_return_val_if_fail (g_type_is_a (page_type
, E_TYPE_COMP_EDITOR_PAGE
), NULL
);
3066 g_return_val_if_fail (page_type
!= E_TYPE_COMP_EDITOR_PAGE
, NULL
);
3068 for (link
= comp_editor
->priv
->pages
; link
; link
= g_slist_next (link
)) {
3069 ECompEditorPage
*page
= link
->data
;
3071 if (G_TYPE_CHECK_INSTANCE_TYPE (page
, page_type
))
3078 /* Free the returned GSList with g_slist_free(), the memebers are owned by the comp_editor */
3080 e_comp_editor_get_pages (ECompEditor
*comp_editor
)
3082 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
3084 return g_slist_copy (comp_editor
->priv
->pages
);
3088 e_comp_editor_select_page (ECompEditor
*comp_editor
,
3089 ECompEditorPage
*page
)
3093 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
3094 g_return_if_fail (E_IS_COMP_EDITOR_PAGE (page
));
3096 page_num
= gtk_notebook_page_num (comp_editor
->priv
->content
, GTK_WIDGET (page
));
3097 g_return_if_fail (page_num
!= -1);
3099 gtk_notebook_set_current_page (comp_editor
->priv
->content
, page_num
);
3102 /* Unref returned pointer when done with it. */
3104 e_comp_editor_add_alert (ECompEditor
*comp_editor
,
3105 const gchar
*alert_id
,
3106 const gchar
*primary_text
,
3107 const gchar
*secondary_text
)
3111 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), NULL
);
3112 g_return_val_if_fail (alert_id
!= NULL
, NULL
);
3113 g_return_val_if_fail (primary_text
!= NULL
|| secondary_text
!= NULL
, NULL
);
3115 alert
= e_alert_new (alert_id
,
3116 primary_text
? primary_text
: "",
3117 secondary_text
? secondary_text
: "",
3120 e_alert_bar_add_alert (comp_editor
->priv
->alert_bar
, alert
);
3125 /* Unref returned pointer when done with it. */
3127 e_comp_editor_add_information (ECompEditor
*comp_editor
,
3128 const gchar
*primary_text
,
3129 const gchar
*secondary_text
)
3131 return e_comp_editor_add_alert (comp_editor
, "calendar:comp-editor-information", primary_text
, secondary_text
);
3134 /* Unref returned pointer when done with it. */
3136 e_comp_editor_add_warning (ECompEditor
*comp_editor
,
3137 const gchar
*primary_text
,
3138 const gchar
*secondary_text
)
3140 return e_comp_editor_add_alert (comp_editor
, "calendar:comp-editor-warning", primary_text
, secondary_text
);
3143 /* Unref returned pointer when done with it. */
3145 e_comp_editor_add_error (ECompEditor
*comp_editor
,
3146 const gchar
*primary_text
,
3147 const gchar
*secondary_text
)
3149 return e_comp_editor_add_alert (comp_editor
, "calendar:comp-editor-error", primary_text
, secondary_text
);
3154 ece_check_start_before_end (ECompEditor
*comp_editor
,
3155 struct icaltimetype
*start_tt
,
3156 struct icaltimetype
*end_tt
,
3157 gboolean adjust_end_time
)
3159 struct icaltimetype end_tt_copy
;
3160 icaltimezone
*start_zone
, *end_zone
;
3164 if ((e_comp_editor_get_flags (comp_editor
) & E_COMP_EDITOR_FLAG_IS_NEW
) == 0) {
3165 icalcomponent
*icomp
;
3167 icomp
= e_comp_editor_get_component (comp_editor
);
3169 icalcomponent_get_first_property (icomp
, ICAL_DTSTART_PROPERTY
) &&
3170 (icalcomponent_get_first_property (icomp
, ICAL_DTEND_PROPERTY
) ||
3171 icalcomponent_get_first_property (icomp
, ICAL_DUE_PROPERTY
))) {
3172 struct icaltimetype orig_start
, orig_end
;
3174 orig_start
= icalcomponent_get_dtstart (icomp
);
3175 orig_end
= icalcomponent_get_dtend (icomp
);
3177 if (icaltime_is_valid_time (orig_start
) &&
3178 icaltime_is_valid_time (orig_end
)) {
3179 duration
= icaltime_as_timet (orig_end
) - icaltime_as_timet (orig_start
);
3184 start_zone
= (icaltimezone
*) start_tt
->zone
;
3185 end_zone
= (icaltimezone
*) end_tt
->zone
;
3187 /* Convert the end time to the same timezone as the start time. */
3188 end_tt_copy
= *end_tt
;
3190 if (start_zone
&& end_zone
&& start_zone
!= end_zone
)
3191 icaltimezone_convert_time (&end_tt_copy
, end_zone
, start_zone
);
3193 /* Now check if the start time is after the end time. If it is,
3194 * we need to modify one of the times. */
3195 cmp
= icaltime_compare (*start_tt
, end_tt_copy
);
3197 if (adjust_end_time
) {
3198 /* Try to switch only the date */
3199 end_tt
->year
= start_tt
->year
;
3200 end_tt
->month
= start_tt
->month
;
3201 end_tt
->day
= start_tt
->day
;
3203 end_tt_copy
= *end_tt
;
3204 if (start_zone
&& end_zone
&& start_zone
!= end_zone
)
3205 icaltimezone_convert_time (&end_tt_copy
, end_zone
, start_zone
);
3208 icaltime_adjust (&end_tt_copy
, 0, 0, 0, -duration
);
3210 if (icaltime_compare (*start_tt
, end_tt_copy
) >= 0) {
3211 *end_tt
= *start_tt
;
3213 if (duration
>= 0) {
3214 icaltime_adjust (end_tt
, 0, 0, 0, duration
);
3216 /* Modify the end time, to be the start + 1 hour/day. */
3217 icaltime_adjust (end_tt
, 0, start_tt
->is_date
? 24 : 1, 0, 0);
3220 if (start_zone
&& end_zone
&& start_zone
!= end_zone
)
3221 icaltimezone_convert_time (end_tt
, start_zone
, end_zone
);
3224 /* Try to switch only the date */
3225 start_tt
->year
= end_tt
->year
;
3226 start_tt
->month
= end_tt
->month
;
3227 start_tt
->day
= end_tt
->day
;
3229 if (icaltime_compare (*start_tt
, end_tt_copy
) >= 0) {
3230 *start_tt
= *end_tt
;
3232 if (duration
>= 0) {
3233 icaltime_adjust (start_tt
, 0, 0, 0, -duration
);
3235 /* Modify the start time, to be the end - 1 hour/day. */
3236 icaltime_adjust (start_tt
, 0, start_tt
->is_date
? -24 : -1, 0, 0);
3239 if (start_zone
&& end_zone
&& start_zone
!= end_zone
)
3240 icaltimezone_convert_time (start_tt
, end_zone
, start_zone
);
3251 e_comp_editor_ensure_start_before_end (ECompEditor
*comp_editor
,
3252 ECompEditorPropertyPart
*start_datetime
,
3253 ECompEditorPropertyPart
*end_datetime
,
3254 gboolean change_end_datetime
)
3256 ECompEditorPropertyPartDatetime
*start_dtm
, *end_dtm
;
3257 struct icaltimetype start_tt
, end_tt
;
3258 gboolean set_dtstart
= FALSE
, set_dtend
= FALSE
;
3260 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
3261 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (start_datetime
));
3262 g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (end_datetime
));
3264 start_dtm
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (start_datetime
);
3265 end_dtm
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (end_datetime
);
3267 start_tt
= e_comp_editor_property_part_datetime_get_value (start_dtm
);
3268 end_tt
= e_comp_editor_property_part_datetime_get_value (end_dtm
);
3270 if (icaltime_is_null_time (start_tt
) ||
3271 icaltime_is_null_time (end_tt
) ||
3272 !icaltime_is_valid_time (start_tt
) ||
3273 !icaltime_is_valid_time (end_tt
))
3276 if (start_tt
.is_date
|| end_tt
.is_date
) {
3277 /* All Day Events are simple. We just compare the dates and if
3278 * start > end we copy one of them to the other. */
3281 start_tt
.is_date
= TRUE
;
3282 end_tt
.is_date
= TRUE
;
3284 cmp
= icaltime_compare_date_only (start_tt
, end_tt
);
3287 if (change_end_datetime
) {
3296 if (ece_check_start_before_end (comp_editor
, &start_tt
, &end_tt
, change_end_datetime
)) {
3297 if (change_end_datetime
)
3304 if (set_dtstart
|| set_dtend
) {
3305 e_comp_editor_set_updating (comp_editor
, TRUE
);
3308 e_comp_editor_property_part_datetime_set_value (start_dtm
, start_tt
);
3311 e_comp_editor_property_part_datetime_set_value (end_dtm
, end_tt
);
3313 e_comp_editor_set_updating (comp_editor
, FALSE
);
3318 e_comp_editor_holds_component (ECompEditor
*comp_editor
,
3319 ESource
*origin_source
,
3320 const icalcomponent
*component
)
3322 const gchar
*component_uid
, *editor_uid
;
3325 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor
), FALSE
);
3326 g_return_val_if_fail (component
!= NULL
, FALSE
);
3328 if (!origin_source
|| !comp_editor
->priv
->origin_source
||
3329 !e_source_equal (origin_source
, comp_editor
->priv
->origin_source
))
3332 component_uid
= icalcomponent_get_uid ((icalcomponent
*) component
);
3333 editor_uid
= icalcomponent_get_uid (comp_editor
->priv
->component
);
3335 if (!component_uid
|| !editor_uid
)
3338 equal
= g_strcmp0 (component_uid
, editor_uid
) == 0;
3340 struct icaltimetype component_rid
, editor_rid
;
3342 component_rid
= icalcomponent_get_recurrenceid ((icalcomponent
*) component
);
3343 editor_rid
= icalcomponent_get_recurrenceid (comp_editor
->priv
->component
);
3345 if (icaltime_is_null_time (component_rid
)) {
3346 equal
= icaltime_is_null_time (editor_rid
);
3347 } else if (!icaltime_is_null_time (editor_rid
)) {
3348 equal
= icaltime_compare (component_rid
, editor_rid
) == 0;
3356 e_comp_editor_open_for_component (GtkWindow
*parent
,
3358 ESource
*origin_source
,
3359 const icalcomponent
*component
,
3360 guint32 flags
/* bit-or of ECompEditorFlags */)
3362 ECompEditor
*comp_editor
;
3363 GType comp_editor_type
;
3365 g_return_val_if_fail (E_IS_SHELL (shell
), NULL
);
3367 g_return_val_if_fail (E_IS_SOURCE (origin_source
), NULL
);
3368 g_return_val_if_fail (component
!= NULL
, NULL
);
3370 comp_editor
= e_comp_editor_find_existing_for (origin_source
, component
);
3372 gtk_window_present (GTK_WINDOW (comp_editor
));
3376 switch (icalcomponent_isa (component
)) {
3377 case ICAL_VEVENT_COMPONENT
:
3378 comp_editor_type
= E_TYPE_COMP_EDITOR_EVENT
;
3380 case ICAL_VTODO_COMPONENT
:
3381 comp_editor_type
= E_TYPE_COMP_EDITOR_TASK
;
3383 case ICAL_VJOURNAL_COMPONENT
:
3384 comp_editor_type
= E_TYPE_COMP_EDITOR_MEMO
;
3387 g_warn_if_reached ();
3391 comp_editor
= g_object_new (comp_editor_type
,
3393 "origin-source", origin_source
,
3394 "component", component
,
3398 opened_editors
= g_slist_prepend (opened_editors
, comp_editor
);
3400 gtk_widget_show (GTK_WIDGET (comp_editor
));
3406 e_comp_editor_find_existing_for (ESource
*origin_source
,
3407 const icalcomponent
*component
)
3409 ECompEditor
*comp_editor
;
3413 g_return_val_if_fail (E_IS_SOURCE (origin_source
), NULL
);
3414 g_return_val_if_fail (component
!= NULL
, NULL
);
3416 for (link
= opened_editors
; link
; link
= g_slist_next (link
)) {
3417 comp_editor
= link
->data
;
3422 if (e_comp_editor_holds_component (comp_editor
, origin_source
, component
)) {
3423 gtk_window_present (GTK_WINDOW (comp_editor
));