1 /*
2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
3 *
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.
7 *
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
11 * for more details.
12 *
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/>.
15 *
16 */
17
18 #include "evolution-config.h"
19
20 #include <glib.h>
21 #include <glib/gi18n-lib.h>
22 #include <gtk/gtk.h>
23
24 #include <libedataserver/libedataserver.h>
25 #include <camel/camel.h>
26 #include <e-util/e-util.h>
27
28 #include "comp-util.h"
29 #include "e-comp-editor.h"
30 #include "e-comp-editor-page.h"
31 #include "e-comp-editor-property-parts.h"
32 #include "e-meeting-list-view.h"
33 #include "itip-utils.h"
34
35 #include "e-comp-editor-page-general.h"
36
37 #define BACKEND_EMAIL_ID "backend-email-id"
38
39 struct _ECompEditorPageGeneralPrivate {
40 GtkWidget *source_label;
41 GtkWidget *source_combo_box;
42 GtkWidget *organizer_label;
43 GtkWidget *organizer_combo_box;
44 GtkWidget *organizer_hbox;
45 GtkWidget *attendees_button;
46 GtkWidget *attendees_hbox;
47 GtkWidget *attendees_list_view;
48 GtkWidget *attendees_button_box;
49 GtkWidget *attendees_button_add;
50 GtkWidget *attendees_button_edit;
51 GtkWidget *attendees_button_remove;
52 ECompEditorPropertyPart *comp_color;
53 gulong comp_color_changed_handler_id;
54 GtkWidget *source_and_color_hbox; /* has together source_combo_box and comp_color::edit_widget */
55
56 gint data_column_width;
57 gchar *source_label_text;
58 gchar *source_extension_name;
59 ESource *select_source;
60 gboolean show_attendees;
61
62 EMeetingStore *meeting_store;
63 GSList *orig_attendees; /* gchar *mail_addresses */
64 gchar *user_delegator;
65 };
66
67 enum {
68 PROP_0,
69 PROP_DATA_COLUMN_WIDTH,
70 PROP_SOURCE_LABEL,
71 PROP_SOURCE_EXTENSION_NAME,
72 PROP_SELECTED_SOURCE,
73 PROP_SHOW_ATTENDEES
74 };
75
76 G_DEFINE_TYPE (ECompEditorPageGeneral, e_comp_editor_page_general, E_TYPE_COMP_EDITOR_PAGE)
77
78 static void ecep_general_sensitize_widgets (ECompEditorPage *page,
79 gboolean force_insensitive);
80
81 static void
ecep_general_set_column_visible(ECompEditorPageGeneral * page_general,EMeetingStoreColumns column,gboolean visible)82 ecep_general_set_column_visible (ECompEditorPageGeneral *page_general,
83 EMeetingStoreColumns column,
84 gboolean visible)
85 {
86 EMeetingListView *meeting_list_view;
87
88 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
89
90 meeting_list_view = E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view);
91 e_meeting_list_view_column_set_visible (meeting_list_view, column, visible);
92 }
93
94 static void
action_view_role_cb(GtkToggleAction * action,ECompEditorPageGeneral * page_general)95 action_view_role_cb (GtkToggleAction *action,
96 ECompEditorPageGeneral *page_general)
97 {
98 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
99
100 ecep_general_set_column_visible (page_general, E_MEETING_STORE_ROLE_COL,
101 gtk_toggle_action_get_active (action));
102 }
103
104 static void
action_view_rsvp_cb(GtkToggleAction * action,ECompEditorPageGeneral * page_general)105 action_view_rsvp_cb (GtkToggleAction *action,
106 ECompEditorPageGeneral *page_general)
107 {
108 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
109
110 ecep_general_set_column_visible (page_general, E_MEETING_STORE_RSVP_COL,
111 gtk_toggle_action_get_active (action));
112 }
113
114 static void
action_view_status_cb(GtkToggleAction * action,ECompEditorPageGeneral * page_general)115 action_view_status_cb (GtkToggleAction *action,
116 ECompEditorPageGeneral *page_general)
117 {
118 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
119
120 ecep_general_set_column_visible (page_general, E_MEETING_STORE_STATUS_COL,
121 gtk_toggle_action_get_active (action));
122 }
123
124 static void
action_view_type_cb(GtkToggleAction * action,ECompEditorPageGeneral * page_general)125 action_view_type_cb (GtkToggleAction *action,
126 ECompEditorPageGeneral *page_general)
127 {
128 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
129
130 ecep_general_set_column_visible (page_general, E_MEETING_STORE_TYPE_COL,
131 gtk_toggle_action_get_active (action));
132 }
133
134 static void
ecep_general_fill_organizer_combo_box(ECompEditorPageGeneral * page_general)135 ecep_general_fill_organizer_combo_box (ECompEditorPageGeneral *page_general)
136 {
137 GtkComboBoxText *combo_box_text;
138 ECompEditor *comp_editor;
139 EShell *shell;
140 ESourceRegistry *registry;
141 gchar **address_strings;
142 gint ii;
143
144 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
145 g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box));
146
147 combo_box_text = GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box);
148 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
149 shell = e_comp_editor_get_shell (comp_editor);
150 registry = e_shell_get_registry (shell);
151 address_strings = itip_get_user_identities (registry);
152
153 for (ii = 0; address_strings && address_strings[ii]; ii++) {
154 gtk_combo_box_text_append_text (combo_box_text, address_strings[ii]);
155 }
156
157 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box_text), 0);
158
159 g_strfreev (address_strings);
160 g_clear_object (&comp_editor);
161 }
162
163 static void
ecep_general_source_combo_box_changed_cb(ESourceComboBox * source_combo_box,ECompEditorPageGeneral * page_general)164 ecep_general_source_combo_box_changed_cb (ESourceComboBox *source_combo_box,
165 ECompEditorPageGeneral *page_general)
166 {
167 ESource *source;
168
169 g_return_if_fail (E_IS_SOURCE_COMBO_BOX (source_combo_box));
170 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
171
172 source = e_source_combo_box_ref_active (source_combo_box);
173 e_comp_editor_page_general_set_selected_source (page_general, source);
174 g_clear_object (&source);
175 }
176
177 static void
ecep_general_attendees_clicked_cb(GtkWidget * widget,ECompEditorPageGeneral * page_general)178 ecep_general_attendees_clicked_cb (GtkWidget *widget,
179 ECompEditorPageGeneral *page_general)
180 {
181 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
182
183 e_meeting_list_view_invite_others_dialog (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view));
184 }
185
186 static void
ecep_general_attendees_add_clicked_cb(GtkButton * button,ECompEditorPageGeneral * page_general)187 ecep_general_attendees_add_clicked_cb (GtkButton *button,
188 ECompEditorPageGeneral *page_general)
189 {
190 ECompEditor *comp_editor;
191 EMeetingAttendee *attendee;
192 guint32 flags;
193
194 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
195
196 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
197 flags = e_comp_editor_get_flags (comp_editor);
198
199 attendee = e_meeting_store_add_attendee_with_defaults (page_general->priv->meeting_store);
200
201 if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) {
202 gchar *mailto;
203
204 mailto = g_strdup_printf ("mailto:%s",
205 page_general->priv->user_delegator ? page_general->priv->user_delegator : "");
206 e_meeting_attendee_set_delfrom (attendee, mailto);
207 g_free (mailto);
208 }
209
210 e_meeting_list_view_edit (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), attendee);
211
212 g_clear_object (&comp_editor);
213 }
214
215 static void
ecep_general_attendees_edit_clicked_cb(GtkButton * button,ECompEditorPageGeneral * page_general)216 ecep_general_attendees_edit_clicked_cb (GtkButton *button,
217 ECompEditorPageGeneral *page_general)
218 {
219 GtkTreeView *tree_view;
220 GtkTreePath *path = NULL;
221 GtkTreeViewColumn *focus_col;
222
223 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
224
225 tree_view = GTK_TREE_VIEW (page_general->priv->attendees_list_view);
226
227 gtk_tree_view_get_cursor (tree_view, &path, NULL);
228 g_return_if_fail (path != NULL);
229
230 gtk_tree_view_get_cursor (tree_view, &path, &focus_col);
231 gtk_tree_view_set_cursor (tree_view, path, focus_col, TRUE);
232 gtk_tree_path_free (path);
233 }
234
235 static void
ecep_general_remove_attendee(ECompEditorPageGeneral * page_general,EMeetingAttendee * attendee)236 ecep_general_remove_attendee (ECompEditorPageGeneral *page_general,
237 EMeetingAttendee *attendee)
238 {
239 ECompEditor *comp_editor;
240 gint pos = 0;
241
242 /* If this was a delegatee, no longer delegate */
243 if (e_meeting_attendee_is_set_delfrom (attendee)) {
244 EMeetingAttendee *ib;
245
246 ib = e_meeting_store_find_attendee (page_general->priv->meeting_store, e_meeting_attendee_get_delfrom (attendee), &pos);
247 if (ib != NULL) {
248 ECompEditor *comp_editor;
249 ECompEditorFlags flags;
250
251 e_meeting_attendee_set_delto (ib, NULL);
252
253 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
254 flags = e_comp_editor_get_flags (comp_editor);
255
256 if (!(flags & E_COMP_EDITOR_FLAG_DELEGATE))
257 e_meeting_attendee_set_edit_level (ib, E_MEETING_ATTENDEE_EDIT_FULL);
258
259 g_clear_object (&comp_editor);
260 }
261 }
262
263 /* Handle deleting all attendees in the delegation chain */
264 while (attendee) {
265 EMeetingAttendee *ib = NULL;
266
267 if (e_meeting_attendee_get_delto (attendee)) {
268 ib = e_meeting_store_find_attendee (page_general->priv->meeting_store,
269 e_meeting_attendee_get_delto (attendee), NULL);
270 }
271
272 e_meeting_list_view_remove_attendee_from_name_selector (
273 E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), attendee);
274 e_meeting_store_remove_attendee (page_general->priv->meeting_store, attendee);
275
276 attendee = ib;
277 }
278
279 ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
280
281 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
282 e_comp_editor_set_changed (comp_editor, TRUE);
283 g_clear_object (&comp_editor);
284 }
285
286 static void
ecep_general_attendees_remove_clicked_cb(GtkButton * button,ECompEditorPageGeneral * page_general)287 ecep_general_attendees_remove_clicked_cb (GtkButton *button,
288 ECompEditorPageGeneral *page_general)
289 {
290 EMeetingAttendee *attendee;
291 GtkTreeSelection *selection;
292 GList *paths = NULL, *tmp;
293 GtkTreeIter iter;
294 GtkTreePath *path = NULL;
295 GtkTreeModel *model = NULL;
296 gboolean valid_iter;
297 gchar *address;
298 gint failures = 0;
299 GString *errors = NULL;
300
301 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
302
303 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
304 paths = gtk_tree_selection_get_selected_rows (selection, &model);
305 g_return_if_fail (paths != NULL);
306
307 paths = g_list_reverse (paths);
308
309 for (tmp = paths; tmp; tmp = tmp->next) {
310 path = tmp->data;
311
312 gtk_tree_model_get_iter (model, &iter, path);
313
314 gtk_tree_model_get (model, &iter, E_MEETING_STORE_ADDRESS_COL, &address, -1);
315 attendee = e_meeting_store_find_attendee (E_MEETING_STORE (model), address, NULL);
316
317 if (!attendee) {
318 if (!errors)
319 errors = g_string_new ("");
320 else
321 g_string_append_c (errors, '\n');
322 g_string_append_printf (errors, _("Cannot find attendee “%s” in the list of attendees"), address);
323 failures++;
324 } else if (e_meeting_attendee_get_edit_level (attendee) != E_MEETING_ATTENDEE_EDIT_FULL) {
325 if (!errors)
326 errors = g_string_new ("");
327 else
328 g_string_append_c (errors, '\n');
329 g_string_append_printf (errors, _("Not enough rights to delete attendee “%s”"), e_meeting_attendee_get_address (attendee));
330 failures++;
331 } else {
332 ecep_general_remove_attendee (page_general, attendee);
333 }
334
335 g_free (address);
336 }
337
338 /* Select closest item after removal */
339 valid_iter = gtk_tree_model_get_iter (model, &iter, path);
340 if (!valid_iter) {
341 gtk_tree_path_prev (path);
342 valid_iter = gtk_tree_model_get_iter (model, &iter, path);
343 }
344
345 if (valid_iter) {
346 gtk_tree_selection_unselect_all (selection);
347 gtk_tree_selection_select_iter (selection, &iter);
348 }
349
350 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
351
352 if (errors) {
353 ECompEditor *comp_editor;
354 EAlert *alert;
355
356 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
357
358 alert = e_comp_editor_add_error (comp_editor, g_dngettext (GETTEXT_PACKAGE,
359 "Failed to delete selected attendee",
360 "Failed to delete selected attendees",
361 failures), errors->str);
362
363 g_string_free (errors, TRUE);
364 g_clear_object (&alert);
365 g_clear_object (&comp_editor);
366 }
367 }
368
369 static void
ecep_general_attendees_selection_changed_cb(GtkTreeSelection * selection,ECompEditorPageGeneral * page_general)370 ecep_general_attendees_selection_changed_cb (GtkTreeSelection *selection,
371 ECompEditorPageGeneral *page_general)
372 {
373 g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
374 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
375
376 ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
377 }
378
379 static void
ecep_general_attendee_added_cb(EMeetingListView * meeting_list_view,EMeetingAttendee * attendee,ECompEditorPageGeneral * page_general)380 ecep_general_attendee_added_cb (EMeetingListView *meeting_list_view,
381 EMeetingAttendee *attendee,
382 ECompEditorPageGeneral *page_general)
383 {
384 ECompEditor *comp_editor;
385 ECompEditorFlags flags;
386 ECalClient *client;
387 gchar *mailto;
388
389 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
390 flags = e_comp_editor_get_flags (comp_editor);
391
392 e_comp_editor_set_changed (comp_editor, TRUE);
393
394 if (!(flags & E_COMP_EDITOR_FLAG_DELEGATE)) {
395 g_clear_object (&comp_editor);
396 return;
397 }
398
399 client = e_comp_editor_get_target_client (comp_editor);
400
401 /* do not remove here, it did EMeetingListView already */
402 mailto = g_strdup_printf ("mailto:%s", page_general->priv->user_delegator ? page_general->priv->user_delegator : "");
403 e_meeting_attendee_set_delfrom (attendee, mailto);
404 g_free (mailto);
405
406 if (client && !e_client_check_capability (E_CLIENT (client), E_CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY)) {
407 EMeetingAttendee *delegator;
408
409 delegator = e_meeting_store_find_attendee (page_general->priv->meeting_store,
410 page_general->priv->user_delegator, NULL);
411 g_return_if_fail (delegator != NULL);
412
413 e_meeting_attendee_set_delto (delegator, e_meeting_attendee_get_address (attendee));
414 }
415
416 ecep_general_sensitize_widgets (E_COMP_EDITOR_PAGE (page_general), FALSE);
417
418 g_clear_object (&comp_editor);
419 }
420
421 static void
ecep_general_attendee_row_changed_cb(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,ECompEditorPageGeneral * page_general)422 ecep_general_attendee_row_changed_cb (GtkTreeModel *model,
423 GtkTreePath *path,
424 GtkTreeIter *iter,
425 ECompEditorPageGeneral *page_general)
426 {
427 ECompEditor *comp_editor;
428
429 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
430
431 if (comp_editor)
432 e_comp_editor_set_changed (comp_editor, TRUE);
433
434 g_clear_object (&comp_editor);
435 }
436
437 static void
ecep_general_attendee_show_address_notify_cb(GObject * store,GParamSpec * param,ECompEditorPageGeneral * page_general)438 ecep_general_attendee_show_address_notify_cb (GObject *store,
439 GParamSpec *param,
440 ECompEditorPageGeneral *page_general)
441 {
442 if (gtk_widget_get_realized (GTK_WIDGET (page_general)) &&
443 gtk_widget_get_realized (page_general->priv->attendees_list_view))
444 gtk_widget_queue_draw (page_general->priv->attendees_list_view);
445 }
446
447 static gboolean
ecep_general_get_organizer(ECompEditorPageGeneral * page_general,gchar ** out_name,gchar ** out_mailto,const gchar ** out_error_message)448 ecep_general_get_organizer (ECompEditorPageGeneral *page_general,
449 gchar **out_name,
450 gchar **out_mailto,
451 const gchar **out_error_message)
452 {
453 gchar *organizer_text;
454 gboolean valid = FALSE;
455
456 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
457
458 organizer_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box));
459 if (organizer_text) {
460 CamelInternetAddress *address;
461 const gchar *str_name, *str_address;
462
463 address = camel_internet_address_new ();
464 if (camel_address_unformat (CAMEL_ADDRESS (address), organizer_text) == 1 &&
465 camel_internet_address_get (address, 0, &str_name, &str_address)) {
466 valid = TRUE;
467
468 if (out_name)
469 *out_name = g_strdup (str_name);
470 if (out_mailto)
471 *out_mailto = g_strconcat ("mailto:", itip_strip_mailto (str_address), NULL);
472 } else if (out_error_message) {
473 *out_error_message = _("Organizer address is not a valid user mail address");
474 }
475
476 g_object_unref (address);
477 g_free (organizer_text);
478 }
479
480 return valid;
481 }
482
483 static void
ecep_general_remove_organizer_backend_address(GtkComboBox * combo_box)484 ecep_general_remove_organizer_backend_address (GtkComboBox *combo_box)
485 {
486 GtkTreeModel *model;
487 GtkTreeIter iter;
488
489 model = gtk_combo_box_get_model (combo_box);
490
491 if (gtk_tree_model_get_iter_first (model, &iter)) {
492 gint id_column;
493
494 id_column = gtk_combo_box_get_id_column (combo_box);
495
496 do {
497 gchar *value = NULL;
498
499 gtk_tree_model_get (model, &iter, id_column, &value, -1);
500
501 if (g_strcmp0 (value, BACKEND_EMAIL_ID) == 0) {
502 g_free (value);
503 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
504 break;
505 }
506
507 g_free (value);
508 } while (gtk_tree_model_iter_next (model, &iter));
509 }
510 }
511
512 static gboolean
ecep_general_pick_organizer_for_email_address(ECompEditorPageGeneral * page_general,const gchar * email_address,gboolean can_add)513 ecep_general_pick_organizer_for_email_address (ECompEditorPageGeneral *page_general,
514 const gchar *email_address,
515 gboolean can_add)
516 {
517 GtkTreeModel *model;
518 GtkTreeIter iter;
519 GtkComboBox *combo_box;
520 gint ii = 0, entry_text_column;
521
522 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
523
524 combo_box = GTK_COMBO_BOX (page_general->priv->organizer_combo_box);
525 model = gtk_combo_box_get_model (combo_box);
526
527 if (can_add)
528 ecep_general_remove_organizer_backend_address (combo_box);
529
530 email_address = itip_strip_mailto (email_address);
531
532 if (!email_address || !*email_address) {
533 if (can_add && gtk_combo_box_get_active (combo_box) == -1 &&
534 gtk_tree_model_get_iter_first (model, &iter))
535 gtk_combo_box_set_active (combo_box, 0);
536
537 return FALSE;
538 }
539
540 entry_text_column = gtk_combo_box_get_entry_text_column (combo_box);
541
542 if (gtk_tree_model_get_iter_first (model, &iter)) {
543 do {
544 gchar *value = NULL;
545
546 gtk_tree_model_get (model, &iter, entry_text_column, &value, -1);
547
548 if (value && g_strrstr (value, email_address)) {
549 g_free (value);
550 gtk_combo_box_set_active (combo_box, ii);
551 return TRUE;
552 }
553
554 g_free (value);
555
556 ii++;
557 } while (gtk_tree_model_iter_next (model, &iter));
558 }
559
560 if (can_add) {
561 /* The expected address is not in the list, thus add it */
562 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo_box), BACKEND_EMAIL_ID, email_address);
563 gtk_combo_box_set_active (combo_box, ii);
564
565 return TRUE;
566 }
567
568 return FALSE;
569 }
570
571 static void
ecep_general_target_client_notify_cb(ECompEditor * comp_editor,GParamSpec * param,ECompEditorPageGeneral * page_general)572 ecep_general_target_client_notify_cb (ECompEditor *comp_editor,
573 GParamSpec *param,
574 ECompEditorPageGeneral *page_general)
575 {
576 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor));
577 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
578
579 if ((e_comp_editor_get_flags (comp_editor) & E_COMP_EDITOR_FLAG_IS_NEW) != 0 ||
580 (e_comp_editor_get_source_client (comp_editor) != NULL &&
581 e_comp_editor_get_target_client (comp_editor) != e_comp_editor_get_source_client (comp_editor))) {
582 const gchar *cal_email_address;
583
584 cal_email_address = e_comp_editor_get_cal_email_address (comp_editor);
585 ecep_general_pick_organizer_for_email_address (page_general, cal_email_address, TRUE);
586 }
587
588 if (page_general->priv->comp_color) {
589 ECalClient *target_client;
590 gboolean supports_color = FALSE;
591
592 target_client = e_comp_editor_get_target_client (comp_editor);
593 if (target_client)
594 supports_color = e_client_check_capability (E_CLIENT (target_client), E_CAL_STATIC_CAPABILITY_COMPONENT_COLOR);
595
596 e_comp_editor_property_part_set_visible (page_general->priv->comp_color, supports_color);
597 }
598 }
599
600 static gboolean
ecep_general_list_view_event_cb(EMeetingListView * list_view,GdkEvent * event,ECompEditorPageGeneral * page_general)601 ecep_general_list_view_event_cb (EMeetingListView *list_view,
602 GdkEvent *event,
603 ECompEditorPageGeneral *page_general)
604 {
605 g_return_val_if_fail (E_IS_MEETING_LIST_VIEW (list_view), FALSE);
606 g_return_val_if_fail (event != NULL, FALSE);
607 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
608
609 if (event->type == GDK_2BUTTON_PRESS && gtk_widget_get_sensitive (GTK_WIDGET (list_view)) &&
610 gtk_widget_get_sensitive (page_general->priv->attendees_button_add)) {
611 EMeetingAttendee *attendee;
612 ECompEditor *comp_editor;
613 guint32 flags;
614
615 attendee = e_meeting_store_add_attendee_with_defaults (page_general->priv->meeting_store);
616
617 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
618 flags = e_comp_editor_get_flags (comp_editor);
619
620 if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) {
621 gchar *mailto;
622
623 mailto = g_strdup_printf ("mailto:%s", page_general->priv->user_delegator);
624 e_meeting_attendee_set_delfrom (attendee, mailto);
625 g_free (mailto);
626 }
627
628 g_clear_object (&comp_editor);
629 e_meeting_list_view_edit (list_view, attendee);
630
631 return TRUE;
632 }
633
634 return FALSE;
635 }
636
637 static gboolean
ecep_general_list_view_key_press_cb(EMeetingListView * list_view,GdkEventKey * event,ECompEditorPageGeneral * page_general)638 ecep_general_list_view_key_press_cb (EMeetingListView *list_view,
639 GdkEventKey *event,
640 ECompEditorPageGeneral *page_general)
641 {
642 g_return_val_if_fail (E_IS_MEETING_LIST_VIEW (list_view), FALSE);
643 g_return_val_if_fail (event != NULL, FALSE);
644 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
645
646 if (event->keyval == GDK_KEY_Delete) {
647 if (gtk_widget_get_sensitive (page_general->priv->attendees_button_remove))
648 ecep_general_attendees_remove_clicked_cb (NULL, page_general);
649 return TRUE;
650 } else if (event->keyval == GDK_KEY_Insert) {
651 if (gtk_widget_get_sensitive (page_general->priv->attendees_button_add))
652 ecep_general_attendees_add_clicked_cb (NULL, page_general);
653 return TRUE;
654 }
655
656 return FALSE;
657 }
658
659 static void
ecep_general_init_ui(ECompEditorPageGeneral * page_general,ECompEditor * comp_editor)660 ecep_general_init_ui (ECompEditorPageGeneral *page_general,
661 ECompEditor *comp_editor)
662 {
663 const gchar *ui =
664 "<ui>"
665 " <menubar action='main-menu'>"
666 " <menu action='view-menu'>"
667 " <placeholder name='columns'>"
668 " <menuitem action='view-role'/>"
669 " <menuitem action='view-rsvp'/>"
670 " <menuitem action='view-status'/>"
671 " <menuitem action='view-type'/>"
672 " </placeholder>"
673 " </menu>"
674 " <menu action='options-menu'>"
675 " <placeholder name='toggles'>"
676 " <menuitem action='option-attendees'/>"
677 " </placeholder>"
678 " </menu>"
679 " </menubar>"
680 "</ui>";
681
682 const GtkToggleActionEntry attendees_toggle_entry[] = {
683
684 { "option-attendees",
685 NULL,
686 N_("A_ttendees"),
687 NULL,
688 N_("Toggles whether the Attendees are displayed"),
689 NULL,
690 FALSE }
691 };
692
693 const GtkToggleActionEntry columns_toggle_entries[] = {
694
695 { "view-role",
696 NULL,
697 N_("R_ole Field"),
698 NULL,
699 N_("Toggles whether the Role field is displayed"),
700 G_CALLBACK (action_view_role_cb),
701 TRUE },
702
703 { "view-rsvp",
704 NULL,
705 N_("_RSVP"),
706 NULL,
707 N_("Toggles whether the RSVP field is displayed"),
708 G_CALLBACK (action_view_rsvp_cb),
709 TRUE },
710
711 { "view-status",
712 NULL,
713 N_("_Status Field"),
714 NULL,
715 N_("Toggles whether the Status field is displayed"),
716 G_CALLBACK (action_view_status_cb),
717 TRUE },
718
719 { "view-type",
720 NULL,
721 N_("_Type Field"),
722 NULL,
723 N_("Toggles whether the Attendee Type is displayed"),
724 G_CALLBACK (action_view_type_cb),
725 TRUE }
726 };
727
728 GtkUIManager *ui_manager;
729 GtkActionGroup *action_group;
730 GtkAction *action;
731 GSettings *settings;
732 GError *error = NULL;
733
734 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
735 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor));
736
737 settings = e_comp_editor_get_settings (comp_editor);
738 ui_manager = e_comp_editor_get_ui_manager (comp_editor);
739
740 action_group = gtk_action_group_new ("columns");
741 gtk_action_group_set_translation_domain (
742 action_group, GETTEXT_PACKAGE);
743 gtk_action_group_add_toggle_actions (
744 action_group, columns_toggle_entries,
745 G_N_ELEMENTS (columns_toggle_entries), page_general);
746 gtk_ui_manager_insert_action_group (
747 ui_manager, action_group, 0);
748
749 e_binding_bind_property (
750 page_general, "show-attendees",
751 action_group, "sensitive",
752 G_BINDING_SYNC_CREATE);
753
754 g_object_unref (action_group);
755
756 action_group = e_comp_editor_get_action_group (comp_editor, "individual");
757 gtk_action_group_add_toggle_actions (
758 action_group, attendees_toggle_entry,
759 G_N_ELEMENTS (attendees_toggle_entry), page_general);
760
761 gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
762
763 if (error) {
764 g_critical ("%s: %s", G_STRFUNC, error->message);
765 g_error_free (error);
766 }
767
768 action = e_comp_editor_get_action (comp_editor, "option-attendees");
769 e_binding_bind_property (
770 page_general, "show-attendees",
771 action, "active",
772 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
773
774 action = e_comp_editor_get_action (comp_editor, "view-role");
775 g_settings_bind (
776 settings, "editor-show-role",
777 action, "active",
778 G_SETTINGS_BIND_DEFAULT);
779
780 action = e_comp_editor_get_action (comp_editor, "view-rsvp");
781 g_settings_bind (
782 settings, "editor-show-rsvp",
783 action, "active",
784 G_SETTINGS_BIND_DEFAULT);
785
786 action = e_comp_editor_get_action (comp_editor, "view-status");
787 g_settings_bind (
788 settings, "editor-show-status",
789 action, "active",
790 G_SETTINGS_BIND_DEFAULT);
791
792 action = e_comp_editor_get_action (comp_editor, "view-type");
793 g_settings_bind (
794 settings, "editor-show-type",
795 action, "active",
796 G_SETTINGS_BIND_DEFAULT);
797 }
798
799 static void
ecep_general_sensitize_widgets(ECompEditorPage * page,gboolean force_insensitive)800 ecep_general_sensitize_widgets (ECompEditorPage *page,
801 gboolean force_insensitive)
802 {
803 ECompEditorPageGeneral *page_general;
804 GtkTreeSelection *selection;
805 GtkAction *action;
806 gboolean sensitive, organizer_is_user, delegate, delegate_to_many = FALSE, read_only = TRUE, any_selected = FALSE;
807 ECompEditor *comp_editor;
808 ECalClient *client;
809 guint32 flags;
810
811 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page));
812
813 E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->sensitize_widgets (page, force_insensitive);
814
815 page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
816
817 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
818 flags = e_comp_editor_get_flags (comp_editor);
819 client = e_comp_editor_get_target_client (comp_editor);
820
821 if (client) {
822 EClient *cl = E_CLIENT (client);
823
824 read_only = e_client_is_readonly (cl);
825 delegate_to_many = e_client_check_capability (cl, E_CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY);
826 } else {
827 force_insensitive = TRUE;
828 }
829
830 delegate = (flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0;
831 organizer_is_user = (flags & (E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER | E_COMP_EDITOR_FLAG_IS_NEW)) != 0 ||
832 !e_comp_editor_page_general_get_show_attendees (page_general);
833 sensitive = (!read_only && organizer_is_user) || delegate;
834
835 if (!delegate)
836 delegate_to_many = TRUE;
837
838 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
839 any_selected = selection && gtk_tree_selection_count_selected_rows (selection) > 0;
840
841 gtk_widget_set_sensitive (page_general->priv->organizer_label, !force_insensitive);
842 gtk_widget_set_sensitive (page_general->priv->organizer_combo_box, !read_only && !force_insensitive);
843 gtk_widget_set_sensitive (page_general->priv->attendees_button, sensitive && delegate_to_many && !force_insensitive);
844 gtk_widget_set_sensitive (page_general->priv->attendees_hbox, !force_insensitive);
845 gtk_widget_set_sensitive (page_general->priv->attendees_button_add, sensitive && delegate_to_many && !force_insensitive);
846 gtk_widget_set_sensitive (page_general->priv->attendees_button_edit, sensitive && delegate_to_many && !force_insensitive && any_selected);
847 gtk_widget_set_sensitive (page_general->priv->attendees_button_remove, sensitive && !force_insensitive && any_selected);
848 e_meeting_list_view_set_editable (E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view), sensitive && !force_insensitive);
849 gtk_widget_set_sensitive (page_general->priv->attendees_list_view, !read_only && !force_insensitive);
850
851 action = e_comp_editor_get_action (comp_editor, "option-attendees");
852 gtk_action_set_sensitive (action, !force_insensitive && !read_only);
853
854 if (page_general->priv->comp_color &&
855 !e_comp_editor_property_part_get_sensitize_handled (page_general->priv->comp_color)) {
856 e_comp_editor_property_part_sensitize_widgets (page_general->priv->comp_color, force_insensitive || read_only);
857 }
858
859 g_clear_object (&comp_editor);
860 }
861
862 static void
ecep_general_fill_widgets(ECompEditorPage * page,ICalComponent * component)863 ecep_general_fill_widgets (ECompEditorPage *page,
864 ICalComponent *component)
865 {
866 ECompEditorPageGeneral *page_general;
867 EMeetingListView *attendees_list_view;
868 ICalProperty *prop;
869
870 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page));
871 g_return_if_fail (I_CAL_IS_COMPONENT (component));
872
873 E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->fill_widgets (page, component);
874
875 page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
876
877 if (page_general->priv->comp_color)
878 e_comp_editor_property_part_fill_widget (page_general->priv->comp_color, component);
879
880 g_slist_free_full (page_general->priv->orig_attendees, g_free);
881 page_general->priv->orig_attendees = NULL;
882
883 for (prop = i_cal_component_get_first_property (component, I_CAL_ATTENDEE_PROPERTY);
884 prop;
885 g_object_unref (prop), prop = i_cal_component_get_next_property (component, I_CAL_ATTENDEE_PROPERTY)) {
886 const gchar *address;
887
888 address = itip_strip_mailto (i_cal_property_get_attendee (prop));
889 if (address)
890 page_general->priv->orig_attendees = g_slist_prepend (page_general->priv->orig_attendees, g_strdup (address));
891 }
892
893 page_general->priv->orig_attendees = g_slist_reverse (page_general->priv->orig_attendees);
894
895 prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
896 if (prop) {
897 ICalParameter *param;
898 const gchar *organizer;
899
900 organizer = i_cal_property_get_organizer (prop);
901
902 if (organizer && *organizer) {
903 ECompEditor *comp_editor;
904 ESourceRegistry *registry;
905 guint32 flags;
906 gchar *value = NULL;
907
908 comp_editor = e_comp_editor_page_ref_editor (page);
909 flags = e_comp_editor_get_flags (comp_editor);
910 registry = e_shell_get_registry (e_comp_editor_get_shell (comp_editor));
911
912 flags = flags & E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
913
914 if (itip_address_is_user (registry, itip_strip_mailto (organizer))) {
915 flags = flags | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
916 } else {
917 param = i_cal_property_get_first_parameter (prop, I_CAL_SENTBY_PARAMETER);
918 if (param) {
919 const gchar *sentby = i_cal_parameter_get_sentby (param);
920
921 if (sentby && *sentby &&
922 itip_address_is_user (registry, itip_strip_mailto (organizer))) {
923 flags = flags | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER;
924 }
925
926 g_object_unref (param);
927 }
928 }
929
930 e_comp_editor_page_general_set_show_attendees (page_general, TRUE);
931
932 param = i_cal_property_get_first_parameter (prop, I_CAL_CN_PARAMETER);
933 if (param) {
934 const gchar *cn;
935
936 cn = i_cal_parameter_get_cn (param);
937 if (cn && *cn) {
938 value = camel_internet_address_format_address (cn, itip_strip_mailto (organizer));
939 }
940
941 g_object_unref (param);
942 }
943
944 if (!value)
945 value = g_strdup (itip_strip_mailto (organizer));
946
947 if (!(flags & E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER) ||
948 !ecep_general_pick_organizer_for_email_address (page_general, organizer, FALSE)) {
949 GtkComboBoxText *combo_box_text;
950
951 combo_box_text = GTK_COMBO_BOX_TEXT (page_general->priv->organizer_combo_box);
952 gtk_combo_box_text_remove_all (combo_box_text);
953 gtk_combo_box_text_append_text (combo_box_text, value);
954 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box_text), 0);
955 }
956
957 e_comp_editor_set_flags (comp_editor, flags);
958
959 g_clear_object (&comp_editor);
960 g_free (value);
961 }
962
963 g_object_unref (prop);
964 }
965
966 attendees_list_view = E_MEETING_LIST_VIEW (page_general->priv->attendees_list_view);
967
968 e_meeting_store_remove_all_attendees (page_general->priv->meeting_store);
969 e_meeting_list_view_remove_all_attendees_from_name_selector (attendees_list_view);
970
971 for (prop = i_cal_component_get_first_property (component, I_CAL_ATTENDEE_PROPERTY);
972 prop;
973 g_object_unref (prop), prop = i_cal_component_get_next_property (component, I_CAL_ATTENDEE_PROPERTY)) {
974 const gchar *address;
975
976 address = itip_strip_mailto (i_cal_property_get_attendee (prop));
977 if (address) {
978 EMeetingAttendee *attendee;
979 ECalComponentAttendee *comp_attendee;
980
981 comp_attendee = e_cal_component_attendee_new_from_property (prop);
982 if (!comp_attendee) {
983 g_warn_if_reached ();
984 continue;
985 }
986
987 attendee = E_MEETING_ATTENDEE (e_meeting_attendee_new_from_e_cal_component_attendee (comp_attendee));
988
989 e_cal_component_attendee_free (comp_attendee);
990
991 e_meeting_store_add_attendee (page_general->priv->meeting_store, attendee);
992 e_meeting_list_view_add_attendee_to_name_selector (attendees_list_view, attendee);
993
994 g_object_unref (attendee);
995 }
996 }
997 }
998
999 static gboolean
ecep_general_fill_component(ECompEditorPage * page,ICalComponent * component)1000 ecep_general_fill_component (ECompEditorPage *page,
1001 ICalComponent *component)
1002 {
1003 ECompEditorPageGeneral *page_general;
1004 ICalProperty *prop;
1005
1006 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page), FALSE);
1007 g_return_val_if_fail (I_CAL_IS_COMPONENT (component), FALSE);
1008
1009 page_general = E_COMP_EDITOR_PAGE_GENERAL (page);
1010
1011 if (page_general->priv->comp_color)
1012 e_comp_editor_property_part_fill_component (page_general->priv->comp_color, component);
1013
1014 e_cal_util_component_remove_property_by_kind (component, I_CAL_ATTENDEE_PROPERTY, TRUE);
1015
1016 if (e_comp_editor_page_general_get_show_attendees (page_general)) {
1017 const GPtrArray *attendees;
1018 GHashTable *known_attendees;
1019 ECompEditor *comp_editor;
1020 gchar *organizer_name = NULL, *organizer_mailto = NULL;
1021 guint32 flags;
1022 gint ii, added_attendees = 0;
1023 const gchar *error_message = NULL;
1024
1025 comp_editor = e_comp_editor_page_ref_editor (page);
1026 flags = e_comp_editor_get_flags (comp_editor);
1027
1028 if ((flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0 &&
1029 !ecep_general_get_organizer (page_general, NULL, NULL, &error_message)) {
1030 e_comp_editor_set_validation_error (comp_editor, page,
1031 page_general->priv->organizer_combo_box,
1032 error_message ? error_message : _("An organizer is required."));
1033
1034 g_clear_object (&comp_editor);
1035
1036 return FALSE;
1037 }
1038
1039 if (e_meeting_store_count_actual_attendees (page_general->priv->meeting_store) < 1) {
1040 e_comp_editor_set_validation_error (comp_editor, page,
1041 page_general->priv->attendees_list_view,
1042 _("At least one attendee is required."));
1043
1044 g_clear_object (&comp_editor);
1045
1046 return FALSE;
1047 }
1048
1049 /* Organizer */
1050 if ((flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0 &&
1051 ecep_general_get_organizer (page_general, &organizer_name, &organizer_mailto, NULL)) {
1052 const gchar *cal_email_address;
1053 ICalParameter *param;
1054
1055 prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
1056 if (!prop) {
1057 prop = i_cal_property_new_organizer (organizer_mailto ? organizer_mailto : organizer_name);
1058 i_cal_component_take_property (component, prop);
1059 prop = i_cal_component_get_first_property (component, I_CAL_ORGANIZER_PROPERTY);
1060 } else {
1061 i_cal_property_set_organizer (prop, organizer_mailto ? organizer_mailto : organizer_name);
1062 }
1063
1064 param = i_cal_property_get_first_parameter (prop, I_CAL_CN_PARAMETER);
1065 if (organizer_name && *organizer_name) {
1066 if (!param) {
1067 param = i_cal_parameter_new_cn (organizer_name);
1068 i_cal_property_add_parameter (prop, param);
1069 } else {
1070 i_cal_parameter_set_cn (param, organizer_name);
1071 }
1072 } else if (param) {
1073 i_cal_property_remove_parameter_by_kind (prop, I_CAL_CN_PARAMETER);
1074 }
1075 g_clear_object (¶m);
1076
1077 param = i_cal_property_get_first_parameter (prop, I_CAL_SENTBY_PARAMETER);
1078 cal_email_address = e_comp_editor_get_cal_email_address (comp_editor);
1079 if (cal_email_address && *cal_email_address) {
1080 gchar *sentby;
1081 gboolean differs;
1082
1083 sentby = g_strconcat ("mailto:", cal_email_address, NULL);
1084 differs = !organizer_mailto || g_ascii_strcasecmp (sentby, organizer_mailto) != 0;
1085
1086 if (differs) {
1087 if (!param) {
1088 param = i_cal_parameter_new_sentby (sentby);
1089 i_cal_property_add_parameter (prop, param);
1090 } else {
1091 i_cal_parameter_set_sentby (param, sentby);
1092 }
1093 } else if (param) {
1094 i_cal_property_remove_parameter_by_kind (prop, I_CAL_SENTBY_PARAMETER);
1095 }
1096
1097 g_free (sentby);
1098 } else if (param) {
1099 i_cal_property_remove_parameter_by_kind (prop, I_CAL_SENTBY_PARAMETER);
1100 }
1101 g_clear_object (¶m);
1102
1103 g_object_unref (prop);
1104 }
1105
1106 /* Attendees */
1107 known_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
1108 attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
1109
1110 for (ii = 0; ii < attendees->len; ii++) {
1111 EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
1112 const gchar *address;
1113
1114 address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
1115 if (address) {
1116 ICalParameter *param;
1117
1118 if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0 &&
1119 (e_meeting_attendee_is_set_delfrom (attendee) || e_meeting_attendee_is_set_delto (attendee)) &&
1120 g_hash_table_contains (known_attendees, address))
1121 continue;
1122
1123 g_hash_table_insert (known_attendees, (gpointer) address, GINT_TO_POINTER (1));
1124
1125 prop = i_cal_property_new_attendee (e_meeting_attendee_get_address (attendee));
1126
1127 added_attendees++;
1128
1129 if (e_meeting_attendee_is_set_member (attendee)) {
1130 param = i_cal_parameter_new_member (e_meeting_attendee_get_member (attendee));
1131 i_cal_property_take_parameter (prop, param);
1132 }
1133
1134 param = i_cal_parameter_new_cutype (e_meeting_attendee_get_cutype (attendee));
1135 if (param)
1136 i_cal_property_take_parameter (prop, param);
1137
1138 param = i_cal_parameter_new_role (e_meeting_attendee_get_role (attendee));
1139 if (param)
1140 i_cal_property_take_parameter (prop, param);
1141
1142 param = i_cal_parameter_new_partstat (e_meeting_attendee_get_partstat (attendee));
1143 if (param)
1144 i_cal_property_take_parameter (prop, param);
1145
1146 param = i_cal_parameter_new_rsvp (e_meeting_attendee_get_rsvp (attendee) ? I_CAL_RSVP_TRUE : I_CAL_RSVP_FALSE);
1147 i_cal_property_take_parameter (prop, param);
1148
1149 if (e_meeting_attendee_is_set_delfrom (attendee)) {
1150 param = i_cal_parameter_new_delegatedfrom (e_meeting_attendee_get_delfrom (attendee));
1151 i_cal_property_take_parameter (prop, param);
1152 }
1153 if (e_meeting_attendee_is_set_delto (attendee)) {
1154 param = i_cal_parameter_new_delegatedto (e_meeting_attendee_get_delto (attendee));
1155 i_cal_property_take_parameter (prop, param);
1156 }
1157 if (e_meeting_attendee_is_set_sentby (attendee)) {
1158 param = i_cal_parameter_new_sentby (e_meeting_attendee_get_sentby (attendee));
1159 i_cal_property_take_parameter (prop, param);
1160 }
1161 if (e_meeting_attendee_is_set_cn (attendee)) {
1162 param = i_cal_parameter_new_cn (e_meeting_attendee_get_cn (attendee));
1163 i_cal_property_take_parameter (prop, param);
1164 }
1165 if (e_meeting_attendee_is_set_language (attendee)) {
1166 param = i_cal_parameter_new_language (e_meeting_attendee_get_language (attendee));
1167 i_cal_property_take_parameter (prop, param);
1168 }
1169
1170 e_cal_component_parameter_bag_fill_property (e_meeting_attendee_get_parameter_bag (attendee), prop);
1171
1172 i_cal_component_take_property (component, prop);
1173 }
1174 }
1175
1176 g_hash_table_destroy (known_attendees);
1177
1178 g_free (organizer_name);
1179 g_free (organizer_mailto);
1180
1181 if (!added_attendees) {
1182 e_comp_editor_set_validation_error (comp_editor, page,
1183 page_general->priv->attendees_list_view,
1184 _("At least one attendee is required."));
1185
1186 g_clear_object (&comp_editor);
1187
1188 return FALSE;
1189 }
1190
1191 g_clear_object (&comp_editor);
1192 } else {
1193 e_cal_util_component_remove_property_by_kind (component, I_CAL_ORGANIZER_PROPERTY, TRUE);
1194 }
1195
1196 return E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_general_parent_class)->fill_component (page, component);
1197 }
1198
1199 static void
ecep_general_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1200 ecep_general_set_property (GObject *object,
1201 guint property_id,
1202 const GValue *value,
1203 GParamSpec *pspec)
1204 {
1205 switch (property_id) {
1206 case PROP_DATA_COLUMN_WIDTH:
1207 e_comp_editor_page_general_set_data_column_width (
1208 E_COMP_EDITOR_PAGE_GENERAL (object),
1209 g_value_get_int (value));
1210 return;
1211
1212 case PROP_SOURCE_LABEL:
1213 e_comp_editor_page_general_set_source_label (
1214 E_COMP_EDITOR_PAGE_GENERAL (object),
1215 g_value_get_string (value));
1216 return;
1217
1218 case PROP_SOURCE_EXTENSION_NAME:
1219 e_comp_editor_page_general_set_source_extension_name (
1220 E_COMP_EDITOR_PAGE_GENERAL (object),
1221 g_value_get_string (value));
1222 return;
1223
1224 case PROP_SELECTED_SOURCE:
1225 e_comp_editor_page_general_set_selected_source (
1226 E_COMP_EDITOR_PAGE_GENERAL (object),
1227 g_value_get_object (value));
1228 return;
1229
1230 case PROP_SHOW_ATTENDEES:
1231 e_comp_editor_page_general_set_show_attendees (
1232 E_COMP_EDITOR_PAGE_GENERAL (object),
1233 g_value_get_boolean (value));
1234 return;
1235 }
1236
1237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1238 }
1239
1240 static void
ecep_general_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)1241 ecep_general_get_property (GObject *object,
1242 guint property_id,
1243 GValue *value,
1244 GParamSpec *pspec)
1245 {
1246 switch (property_id) {
1247 case PROP_DATA_COLUMN_WIDTH:
1248 g_value_set_int (
1249 value,
1250 e_comp_editor_page_general_get_data_column_width (
1251 E_COMP_EDITOR_PAGE_GENERAL (object)));
1252 return;
1253
1254 case PROP_SOURCE_LABEL:
1255 g_value_set_string (
1256 value,
1257 e_comp_editor_page_general_get_source_label (
1258 E_COMP_EDITOR_PAGE_GENERAL (object)));
1259 return;
1260
1261 case PROP_SOURCE_EXTENSION_NAME:
1262 g_value_set_string (
1263 value,
1264 e_comp_editor_page_general_get_source_extension_name (
1265 E_COMP_EDITOR_PAGE_GENERAL (object)));
1266 return;
1267
1268 case PROP_SELECTED_SOURCE:
1269 g_value_take_object (
1270 value,
1271 e_comp_editor_page_general_ref_selected_source (
1272 E_COMP_EDITOR_PAGE_GENERAL (object)));
1273 return;
1274
1275 case PROP_SHOW_ATTENDEES:
1276 g_value_set_boolean (
1277 value,
1278 e_comp_editor_page_general_get_show_attendees (
1279 E_COMP_EDITOR_PAGE_GENERAL (object)));
1280 return;
1281 }
1282
1283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1284 }
1285
1286 static void
ecep_general_constructed(GObject * object)1287 ecep_general_constructed (GObject *object)
1288 {
1289 ECompEditor *comp_editor;
1290 ECompEditorPageGeneral *page_general;
1291 ECompEditorPropertyPart *part;
1292 GtkWidget *widget, *scrolled_window;
1293 GtkTreeSelection *selection;
1294 GtkGrid *grid;
1295 EShell *shell;
1296
1297 page_general = E_COMP_EDITOR_PAGE_GENERAL (object);
1298
1299 G_OBJECT_CLASS (e_comp_editor_page_general_parent_class)->constructed (object);
1300
1301 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
1302 g_return_if_fail (comp_editor != NULL);
1303
1304 page_general->priv->meeting_store = E_MEETING_STORE (e_meeting_store_new ());
1305
1306 grid = GTK_GRID (page_general);
1307
1308 widget = gtk_label_new_with_mnemonic (_("Or_ganizer:"));
1309 g_object_set (G_OBJECT (widget),
1310 "hexpand", FALSE,
1311 "halign", GTK_ALIGN_END,
1312 "vexpand", FALSE,
1313 "valign", GTK_ALIGN_CENTER,
1314 NULL);
1315 gtk_grid_attach (grid, widget, 0, 0, 1, 1);
1316 gtk_widget_hide (widget);
1317
1318 page_general->priv->organizer_label = widget;
1319
1320 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
1321 g_object_set (G_OBJECT (widget),
1322 "hexpand", TRUE,
1323 "halign", GTK_ALIGN_FILL,
1324 "vexpand", FALSE,
1325 "valign", GTK_ALIGN_FILL,
1326 NULL);
1327 gtk_grid_attach (grid, widget, 1, 0, page_general->priv->data_column_width, 1);
1328 gtk_widget_hide (widget);
1329
1330 page_general->priv->organizer_hbox = widget;
1331
1332 widget = e_ellipsized_combo_box_text_new (FALSE);
1333 g_object_set (G_OBJECT (widget),
1334 "hexpand", TRUE,
1335 "halign", GTK_ALIGN_FILL,
1336 "vexpand", FALSE,
1337 "valign", GTK_ALIGN_START,
1338 NULL);
1339 gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, TRUE, TRUE, 0);
1340 gtk_widget_show (widget);
1341
1342 page_general->priv->organizer_combo_box = widget;
1343
1344 ecep_general_fill_organizer_combo_box (page_general);
1345
1346 g_signal_connect_swapped (page_general->priv->organizer_combo_box, "changed",
1347 G_CALLBACK (e_comp_editor_ensure_changed), comp_editor);
1348
1349 widget = gtk_label_new_with_mnemonic (page_general->priv->source_label_text);
1350 g_object_set (G_OBJECT (widget),
1351 "hexpand", FALSE,
1352 "halign", GTK_ALIGN_END,
1353 "vexpand", FALSE,
1354 "valign", GTK_ALIGN_CENTER,
1355 NULL);
1356 gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, FALSE, FALSE, 0);
1357 gtk_widget_show (widget);
1358
1359 page_general->priv->source_label = widget;
1360
1361 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
1362 g_object_set (G_OBJECT (widget),
1363 "hexpand", TRUE,
1364 "halign", GTK_ALIGN_FILL,
1365 "vexpand", FALSE,
1366 "valign", GTK_ALIGN_CENTER,
1367 NULL);
1368 gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox), widget, TRUE, TRUE, 0);
1369 gtk_widget_show (widget);
1370
1371 page_general->priv->source_and_color_hbox = widget;
1372
1373 shell = e_comp_editor_get_shell (comp_editor);
1374 widget = e_source_combo_box_new (
1375 e_shell_get_registry (shell),
1376 page_general->priv->source_extension_name);
1377 e_source_combo_box_set_show_colors (E_SOURCE_COMBO_BOX (widget), TRUE);
1378 g_object_set (G_OBJECT (widget),
1379 "hexpand", TRUE,
1380 "halign", GTK_ALIGN_FILL,
1381 "vexpand", FALSE,
1382 "valign", GTK_ALIGN_START,
1383 NULL);
1384 gtk_box_pack_start (GTK_BOX (page_general->priv->source_and_color_hbox), widget, TRUE, TRUE, 0);
1385 gtk_widget_show (widget);
1386
1387 page_general->priv->source_combo_box = widget;
1388
1389 gtk_label_set_mnemonic_widget (GTK_LABEL (page_general->priv->source_label),
1390 page_general->priv->source_combo_box);
1391 g_signal_connect (page_general->priv->source_combo_box, "changed",
1392 G_CALLBACK (ecep_general_source_combo_box_changed_cb), page_general);
1393
1394 part = e_comp_editor_property_part_color_new ();
1395 widget = e_comp_editor_property_part_get_edit_widget (part);
1396
1397 if (widget) {
1398 const gchar *tooltip;
1399
1400 gtk_box_pack_start (GTK_BOX (page_general->priv->source_and_color_hbox), widget, FALSE, FALSE, 0);
1401
1402 if (g_strcmp0 (page_general->priv->source_extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) {
1403 tooltip = _("Override color of the event. If not set, then color of the calendar is used.");
1404 } else if (g_strcmp0 (page_general->priv->source_extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) {
1405 tooltip = _("Override color of the memo. If not set, then color of the memo list is used.");
1406 } else { /* E_SOURCE_EXTENSION_TASK_LIST */
1407 tooltip = _("Override color of the task. If not set, then color of the task list is used.");
1408 }
1409
1410 gtk_widget_set_tooltip_text (widget, tooltip);
1411 }
1412
1413 page_general->priv->comp_color_changed_handler_id = g_signal_connect_swapped (part, "changed",
1414 G_CALLBACK (e_comp_editor_page_emit_changed), page_general);
1415
1416 page_general->priv->comp_color = part;
1417
1418 widget = gtk_button_new_with_mnemonic (C_("ECompEditor", "Atte_ndees…"));
1419 g_object_set (G_OBJECT (widget),
1420 "hexpand", FALSE,
1421 "halign", GTK_ALIGN_END,
1422 "vexpand", FALSE,
1423 "valign", GTK_ALIGN_START,
1424 NULL);
1425 gtk_grid_attach (grid, widget, 0, 1, 1, 1);
1426 gtk_widget_hide (widget);
1427
1428 page_general->priv->attendees_button = widget;
1429
1430 g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_clicked_cb), page_general);
1431
1432 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1433 g_object_set (G_OBJECT (widget),
1434 "hexpand", TRUE,
1435 "halign", GTK_ALIGN_FILL,
1436 "vexpand", FALSE,
1437 "valign", GTK_ALIGN_FILL,
1438 NULL);
1439 gtk_grid_attach (grid, widget, 1, 1, page_general->priv->data_column_width, 1);
1440 gtk_widget_hide (widget);
1441
1442 page_general->priv->attendees_hbox = widget;
1443
1444 widget = GTK_WIDGET (e_meeting_list_view_new (page_general->priv->meeting_store));
1445 g_object_set (G_OBJECT (widget),
1446 "hexpand", FALSE,
1447 "halign", GTK_ALIGN_FILL,
1448 "vexpand", FALSE,
1449 "valign", GTK_ALIGN_FILL,
1450 NULL);
1451 gtk_widget_show (widget);
1452
1453 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1454 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1455 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
1456 gtk_widget_show (scrolled_window);
1457
1458 gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
1459 gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_hbox), scrolled_window, TRUE, TRUE, 0);
1460
1461 page_general->priv->attendees_list_view = widget;
1462
1463 g_signal_connect_object (page_general->priv->attendees_list_view, "attendee-added",
1464 G_CALLBACK (ecep_general_attendee_added_cb), page_general, 0);
1465
1466 g_signal_connect_object (page_general->priv->meeting_store, "row-changed",
1467 G_CALLBACK (ecep_general_attendee_row_changed_cb), page_general, 0);
1468
1469 e_signal_connect_notify_object (page_general->priv->meeting_store, "notify::show-address",
1470 G_CALLBACK (ecep_general_attendee_show_address_notify_cb), page_general, 0);
1471
1472 g_signal_connect_object (page_general->priv->attendees_list_view, "event",
1473 G_CALLBACK (ecep_general_list_view_event_cb), page_general, 0);
1474
1475 g_signal_connect_object (page_general->priv->attendees_list_view, "key_press_event",
1476 G_CALLBACK (ecep_general_list_view_key_press_cb), page_general, 0);
1477
1478 widget = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1479 g_object_set (G_OBJECT (widget),
1480 "hexpand", FALSE,
1481 "halign", GTK_ALIGN_START,
1482 "vexpand", FALSE,
1483 "valign", GTK_ALIGN_START,
1484 NULL);
1485 gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_hbox), widget, FALSE, FALSE, 0);
1486 gtk_widget_show (widget);
1487
1488 page_general->priv->attendees_button_box = widget;
1489
1490 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (page_general->priv->attendees_list_view));
1491 g_signal_connect (selection, "changed", G_CALLBACK (ecep_general_attendees_selection_changed_cb), page_general);
1492
1493 widget = gtk_button_new_with_mnemonic (_("_Add"));
1494 gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
1495 gtk_widget_show (widget);
1496
1497 page_general->priv->attendees_button_add = widget;
1498
1499 g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_add_clicked_cb), page_general);
1500
1501 widget = gtk_button_new_with_mnemonic (_("_Edit"));
1502 gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
1503 gtk_widget_show (widget);
1504
1505 page_general->priv->attendees_button_edit = widget;
1506
1507 g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_edit_clicked_cb), page_general);
1508
1509 widget = gtk_button_new_with_mnemonic (_("_Remove"));
1510 gtk_box_pack_start (GTK_BOX (page_general->priv->attendees_button_box), widget, FALSE, FALSE, 0);
1511 gtk_widget_show (widget);
1512
1513 page_general->priv->attendees_button_remove = widget;
1514
1515 g_signal_connect (widget, "clicked", G_CALLBACK (ecep_general_attendees_remove_clicked_cb), page_general);
1516
1517 e_signal_connect_notify (comp_editor, "notify::target-client", G_CALLBACK (ecep_general_target_client_notify_cb), page_general);
1518
1519 ecep_general_init_ui (page_general, comp_editor);
1520
1521 g_clear_object (&comp_editor);
1522 }
1523
1524 static void
ecep_general_finalize(GObject * object)1525 ecep_general_finalize (GObject *object)
1526 {
1527 ECompEditorPageGeneral *page_general;
1528
1529 page_general = E_COMP_EDITOR_PAGE_GENERAL (object);
1530
1531 g_free (page_general->priv->source_label_text);
1532 page_general->priv->source_label_text = NULL;
1533
1534 g_free (page_general->priv->source_extension_name);
1535 page_general->priv->source_extension_name = NULL;
1536
1537 g_free (page_general->priv->user_delegator);
1538 page_general->priv->user_delegator = NULL;
1539
1540 if (page_general->priv->comp_color && page_general->priv->comp_color_changed_handler_id) {
1541 g_signal_handler_disconnect (page_general->priv->comp_color, page_general->priv->comp_color_changed_handler_id);
1542 page_general->priv->comp_color_changed_handler_id = 0;
1543 }
1544
1545 g_clear_object (&page_general->priv->comp_color);
1546 g_clear_object (&page_general->priv->select_source);
1547 g_clear_object (&page_general->priv->meeting_store);
1548
1549 g_slist_free_full (page_general->priv->orig_attendees, g_free);
1550 page_general->priv->orig_attendees = NULL;
1551
1552 G_OBJECT_CLASS (e_comp_editor_page_general_parent_class)->finalize (object);
1553 }
1554
1555 static void
e_comp_editor_page_general_init(ECompEditorPageGeneral * page_general)1556 e_comp_editor_page_general_init (ECompEditorPageGeneral *page_general)
1557 {
1558 page_general->priv = G_TYPE_INSTANCE_GET_PRIVATE (page_general,
1559 E_TYPE_COMP_EDITOR_PAGE_GENERAL,
1560 ECompEditorPageGeneralPrivate);
1561 }
1562
1563 static void
e_comp_editor_page_general_class_init(ECompEditorPageGeneralClass * klass)1564 e_comp_editor_page_general_class_init (ECompEditorPageGeneralClass *klass)
1565 {
1566 ECompEditorPageClass *page_class;
1567 GObjectClass *object_class;
1568
1569 g_type_class_add_private (klass, sizeof (ECompEditorPageGeneralPrivate));
1570
1571 page_class = E_COMP_EDITOR_PAGE_CLASS (klass);
1572 page_class->sensitize_widgets = ecep_general_sensitize_widgets;
1573 page_class->fill_widgets = ecep_general_fill_widgets;
1574 page_class->fill_component = ecep_general_fill_component;
1575
1576 object_class = G_OBJECT_CLASS (klass);
1577 object_class->set_property = ecep_general_set_property;
1578 object_class->get_property = ecep_general_get_property;
1579 object_class->constructed = ecep_general_constructed;
1580 object_class->finalize = ecep_general_finalize;
1581
1582 g_object_class_install_property (
1583 object_class,
1584 PROP_DATA_COLUMN_WIDTH,
1585 g_param_spec_int (
1586 "data-column-width",
1587 "Data Column Width",
1588 "How many columns should the data column occupy",
1589 1, G_MAXINT, 1,
1590 G_PARAM_READWRITE |
1591 G_PARAM_CONSTRUCT |
1592 G_PARAM_STATIC_STRINGS));
1593
1594 g_object_class_install_property (
1595 object_class,
1596 PROP_SOURCE_LABEL,
1597 g_param_spec_string (
1598 "source-label",
1599 "Source Label",
1600 "Label to use for the source selector",
1601 NULL,
1602 G_PARAM_READWRITE |
1603 G_PARAM_CONSTRUCT_ONLY |
1604 G_PARAM_STATIC_STRINGS));
1605
1606 g_object_class_install_property (
1607 object_class,
1608 PROP_SOURCE_EXTENSION_NAME,
1609 g_param_spec_string (
1610 "source-extension-name",
1611 "Source Extension Name",
1612 "Extension name to use for the source selector",
1613 NULL,
1614 G_PARAM_READWRITE |
1615 G_PARAM_CONSTRUCT_ONLY |
1616 G_PARAM_STATIC_STRINGS));
1617
1618 g_object_class_install_property (
1619 object_class,
1620 PROP_SELECTED_SOURCE,
1621 g_param_spec_object (
1622 "selected-source",
1623 "Selected Source",
1624 "Which source is currently selected in the source selector",
1625 E_TYPE_SOURCE,
1626 G_PARAM_READWRITE |
1627 G_PARAM_STATIC_STRINGS));
1628
1629 g_object_class_install_property (
1630 object_class,
1631 PROP_SHOW_ATTENDEES,
1632 g_param_spec_boolean (
1633 "show-attendees",
1634 "Show Attendees",
1635 "Whether to show also attendees",
1636 TRUE,
1637 G_PARAM_READWRITE |
1638 G_PARAM_CONSTRUCT |
1639 G_PARAM_STATIC_STRINGS));
1640 }
1641
1642 ECompEditorPage *
e_comp_editor_page_general_new(ECompEditor * editor,const gchar * source_label,const gchar * source_extension_name,ESource * select_source,gboolean show_attendees,gint data_column_width)1643 e_comp_editor_page_general_new (ECompEditor *editor,
1644 const gchar *source_label,
1645 const gchar *source_extension_name,
1646 ESource *select_source,
1647 gboolean show_attendees,
1648 gint data_column_width)
1649 {
1650 g_return_val_if_fail (E_IS_COMP_EDITOR (editor), NULL);
1651 g_return_val_if_fail (source_label != NULL, NULL);
1652 g_return_val_if_fail (source_extension_name != NULL, NULL);
1653
1654 if (select_source)
1655 g_return_val_if_fail (E_IS_SOURCE (select_source), NULL);
1656
1657 return g_object_new (E_TYPE_COMP_EDITOR_PAGE_GENERAL,
1658 "editor", editor,
1659 "source-label", source_label,
1660 "source-extension-name", source_extension_name,
1661 "selected-source", select_source,
1662 "show-attendees", show_attendees,
1663 "data-column-width", data_column_width,
1664 NULL);
1665 }
1666
1667 const gchar *
e_comp_editor_page_general_get_source_label(ECompEditorPageGeneral * page_general)1668 e_comp_editor_page_general_get_source_label (ECompEditorPageGeneral *page_general)
1669 {
1670 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1671
1672 if (page_general->priv->source_label)
1673 return gtk_label_get_text (GTK_LABEL (page_general->priv->source_label));
1674
1675 return page_general->priv->source_label_text;
1676 }
1677
1678 void
e_comp_editor_page_general_set_source_label(ECompEditorPageGeneral * page_general,const gchar * source_label)1679 e_comp_editor_page_general_set_source_label (ECompEditorPageGeneral *page_general,
1680 const gchar *source_label)
1681 {
1682 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1683 g_return_if_fail (source_label != NULL);
1684
1685 if (page_general->priv->source_label) {
1686 if (g_strcmp0 (source_label, gtk_label_get_text (GTK_LABEL (page_general->priv->source_label))) != 0) {
1687 gtk_label_set_text (GTK_LABEL (page_general->priv->source_label), source_label);
1688
1689 g_object_notify (G_OBJECT (page_general), "source-label");
1690 }
1691 } else {
1692 g_free (page_general->priv->source_label_text);
1693 page_general->priv->source_label_text = g_strdup (source_label);
1694
1695 g_object_notify (G_OBJECT (page_general), "source-label");
1696 }
1697 }
1698
1699 const gchar *
e_comp_editor_page_general_get_source_extension_name(ECompEditorPageGeneral * page_general)1700 e_comp_editor_page_general_get_source_extension_name (ECompEditorPageGeneral *page_general)
1701 {
1702 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1703
1704 if (page_general->priv->source_combo_box)
1705 return e_source_combo_box_get_extension_name (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box));
1706
1707 return page_general->priv->source_extension_name;
1708 }
1709
1710 void
e_comp_editor_page_general_set_source_extension_name(ECompEditorPageGeneral * page_general,const gchar * source_extension_name)1711 e_comp_editor_page_general_set_source_extension_name (ECompEditorPageGeneral *page_general,
1712 const gchar *source_extension_name)
1713 {
1714 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1715
1716 if (g_strcmp0 (page_general->priv->source_extension_name, source_extension_name) == 0)
1717 return;
1718
1719 g_free (page_general->priv->source_extension_name);
1720 page_general->priv->source_extension_name = g_strdup (source_extension_name);
1721
1722 g_object_notify (G_OBJECT (page_general), "source-extension-name");
1723
1724 if (page_general->priv->source_combo_box) {
1725 e_source_combo_box_set_extension_name (
1726 E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box),
1727 source_extension_name);
1728 }
1729 }
1730
1731 ESource *
e_comp_editor_page_general_ref_selected_source(ECompEditorPageGeneral * page_general)1732 e_comp_editor_page_general_ref_selected_source (ECompEditorPageGeneral *page_general)
1733 {
1734 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1735 g_return_val_if_fail (page_general->priv->source_combo_box != NULL, NULL);
1736
1737 return e_source_combo_box_ref_active (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box));
1738 }
1739
1740 void
e_comp_editor_page_general_set_selected_source(ECompEditorPageGeneral * page_general,ESource * source)1741 e_comp_editor_page_general_set_selected_source (ECompEditorPageGeneral *page_general,
1742 ESource *source)
1743 {
1744 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1745 if (source)
1746 g_return_if_fail (E_IS_SOURCE (source));
1747
1748 if (!page_general->priv->source_combo_box) {
1749 g_clear_object (&page_general->priv->select_source);
1750 page_general->priv->select_source = g_object_ref (source);
1751
1752 g_object_notify (G_OBJECT (page_general), "selected-source");
1753
1754 return;
1755 }
1756
1757 if (source)
1758 e_source_combo_box_set_active (E_SOURCE_COMBO_BOX (page_general->priv->source_combo_box), source);
1759
1760 g_object_notify (G_OBJECT (page_general), "selected-source");
1761 }
1762
1763 gboolean
e_comp_editor_page_general_get_show_attendees(ECompEditorPageGeneral * page_general)1764 e_comp_editor_page_general_get_show_attendees (ECompEditorPageGeneral *page_general)
1765 {
1766 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), FALSE);
1767
1768 return page_general->priv->show_attendees;
1769 }
1770
1771 void
e_comp_editor_page_general_set_show_attendees(ECompEditorPageGeneral * page_general,gboolean show_attendees)1772 e_comp_editor_page_general_set_show_attendees (ECompEditorPageGeneral *page_general,
1773 gboolean show_attendees)
1774 {
1775 ECompEditor *comp_editor;
1776
1777 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1778
1779 if ((show_attendees ? 1 : 0) == (page_general->priv->show_attendees ? 1 : 0))
1780 return;
1781
1782 page_general->priv->show_attendees = show_attendees;
1783
1784 g_object_notify (G_OBJECT (page_general), "show-attendees");
1785
1786 e_comp_editor_page_general_update_view (page_general);
1787
1788 comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_general));
1789 if (comp_editor)
1790 e_comp_editor_set_changed (comp_editor, TRUE);
1791 g_clear_object (&comp_editor);
1792 }
1793
1794 gint
e_comp_editor_page_general_get_data_column_width(ECompEditorPageGeneral * page_general)1795 e_comp_editor_page_general_get_data_column_width (ECompEditorPageGeneral *page_general)
1796 {
1797 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), 0);
1798
1799 return page_general->priv->data_column_width;
1800 }
1801
1802 void
e_comp_editor_page_general_set_data_column_width(ECompEditorPageGeneral * page_general,gint data_column_width)1803 e_comp_editor_page_general_set_data_column_width (ECompEditorPageGeneral *page_general,
1804 gint data_column_width)
1805 {
1806 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1807
1808 if (data_column_width == page_general->priv->data_column_width)
1809 return;
1810
1811 page_general->priv->data_column_width = data_column_width;
1812
1813 g_object_notify (G_OBJECT (page_general), "data-column-width");
1814
1815 e_comp_editor_page_general_update_view (page_general);
1816 }
1817
1818 void
e_comp_editor_page_general_update_view(ECompEditorPageGeneral * page_general)1819 e_comp_editor_page_general_update_view (ECompEditorPageGeneral *page_general)
1820 {
1821 GtkContainer *grid;
1822
1823 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general));
1824
1825 if (!page_general->priv->source_label)
1826 return;
1827
1828 grid = GTK_CONTAINER (page_general);
1829
1830 gtk_container_child_set (grid, page_general->priv->organizer_hbox,
1831 "left-attach", 1, "width", page_general->priv->data_column_width, NULL);
1832 gtk_container_child_set (grid, page_general->priv->attendees_hbox,
1833 "width", page_general->priv->data_column_width, NULL);
1834
1835 if (page_general->priv->show_attendees) {
1836 if (gtk_widget_get_parent (page_general->priv->source_label) == GTK_WIDGET (grid)) {
1837
1838 g_object_ref (page_general->priv->source_label);
1839 g_object_ref (page_general->priv->source_and_color_hbox);
1840
1841 gtk_container_remove (grid, page_general->priv->source_label);
1842 gtk_container_remove (grid, page_general->priv->source_and_color_hbox);
1843
1844 gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox),
1845 page_general->priv->source_label, FALSE, FALSE, 0);
1846 gtk_box_pack_start (GTK_BOX (page_general->priv->organizer_hbox),
1847 page_general->priv->source_and_color_hbox, TRUE, TRUE, 0);
1848
1849 g_object_unref (page_general->priv->source_label);
1850 g_object_unref (page_general->priv->source_and_color_hbox);
1851 }
1852
1853 gtk_container_child_set (grid, page_general->priv->organizer_label,
1854 "left-attach", 0, NULL);
1855
1856 gtk_widget_show (page_general->priv->organizer_label);
1857 gtk_widget_show (page_general->priv->organizer_hbox);
1858 gtk_widget_show (page_general->priv->attendees_button);
1859 gtk_widget_show (page_general->priv->attendees_hbox);
1860 gtk_widget_show (page_general->priv->attendees_list_view);
1861 gtk_widget_show (page_general->priv->attendees_button_box);
1862 } else {
1863 if (gtk_widget_get_parent (page_general->priv->source_label) != GTK_WIDGET (grid)) {
1864 GtkContainer *container;
1865 GtkGrid *ggrid;
1866
1867 container = GTK_CONTAINER (page_general->priv->organizer_hbox);
1868 ggrid = GTK_GRID (grid);
1869
1870 g_object_ref (page_general->priv->source_label);
1871 g_object_ref (page_general->priv->source_and_color_hbox);
1872
1873 gtk_container_remove (container, page_general->priv->source_label);
1874 gtk_container_remove (container, page_general->priv->source_and_color_hbox);
1875
1876 gtk_grid_attach (ggrid, page_general->priv->source_label, 0, 0, 1, 1);
1877 gtk_grid_attach (ggrid, page_general->priv->source_and_color_hbox, 1, 0, 1, 1);
1878
1879 g_object_unref (page_general->priv->source_label);
1880 g_object_unref (page_general->priv->source_and_color_hbox);
1881 }
1882
1883 gtk_container_child_set (grid, page_general->priv->source_label,
1884 "left-attach", 0, NULL);
1885 gtk_container_child_set (grid, page_general->priv->source_and_color_hbox,
1886 "left-attach", 1, "width", page_general->priv->data_column_width, NULL);
1887
1888 gtk_widget_hide (page_general->priv->organizer_label);
1889 gtk_widget_hide (page_general->priv->organizer_hbox);
1890 gtk_widget_hide (page_general->priv->attendees_button);
1891 gtk_widget_hide (page_general->priv->attendees_hbox);
1892 gtk_widget_hide (page_general->priv->attendees_list_view);
1893 gtk_widget_hide (page_general->priv->attendees_button_box);
1894 }
1895 }
1896
1897 EMeetingStore *
e_comp_editor_page_general_get_meeting_store(ECompEditorPageGeneral * page_general)1898 e_comp_editor_page_general_get_meeting_store (ECompEditorPageGeneral *page_general)
1899 {
1900 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1901
1902 return page_general->priv->meeting_store;
1903 }
1904
1905 /* Element is a string, an email address; free with g_slist_free_full (slist, g_free); */
1906 GSList *
e_comp_editor_page_general_get_added_attendees(ECompEditorPageGeneral * page_general)1907 e_comp_editor_page_general_get_added_attendees (ECompEditorPageGeneral *page_general)
1908 {
1909 const GPtrArray *attendees;
1910 GHashTable *orig_attendees = NULL;
1911 GSList *added_attendees = NULL, *link;
1912 gint ii;
1913
1914 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1915
1916 if (!page_general->priv->show_attendees)
1917 return NULL;
1918
1919 if (page_general->priv->orig_attendees) {
1920 for (link = page_general->priv->orig_attendees; link; link = g_slist_next (link)) {
1921 const gchar *address = link->data;
1922
1923 if (address) {
1924 if (!orig_attendees)
1925 orig_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
1926 g_hash_table_insert (orig_attendees, (gpointer) address, GINT_TO_POINTER (1));
1927 }
1928 }
1929 }
1930
1931 attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
1932
1933 for (ii = 0; ii < attendees->len; ii++) {
1934 EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
1935 const gchar *address;
1936
1937 address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
1938
1939 if (address && (!orig_attendees || !g_hash_table_contains (orig_attendees, address)))
1940 added_attendees = g_slist_prepend (added_attendees, g_strdup (address));
1941 }
1942
1943 if (orig_attendees)
1944 g_hash_table_destroy (orig_attendees);
1945
1946 return g_slist_reverse (added_attendees);
1947 }
1948
1949 /* Element is a string, an email address; free with g_slist_free_full (slist, g_free); */
1950 GSList *
e_comp_editor_page_general_get_removed_attendees(ECompEditorPageGeneral * page_general)1951 e_comp_editor_page_general_get_removed_attendees (ECompEditorPageGeneral *page_general)
1952 {
1953 const GPtrArray *attendees;
1954 GHashTable *new_attendees;
1955 GSList *removed_attendees = NULL, *link;
1956 gint ii;
1957
1958 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
1959
1960 if (!page_general->priv->orig_attendees)
1961 return NULL;
1962
1963 if (!page_general->priv->show_attendees) {
1964 GSList *copy, *link;
1965
1966 copy = g_slist_copy (page_general->priv->orig_attendees);
1967 for (link = copy; link; link = g_slist_next (link)) {
1968 link->data = g_strdup (link->data);
1969 }
1970
1971 return copy;
1972 }
1973
1974 new_attendees = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
1975 attendees = e_meeting_store_get_attendees (page_general->priv->meeting_store);
1976
1977 for (ii = 0; ii < attendees->len; ii++) {
1978 EMeetingAttendee *attendee = g_ptr_array_index (attendees, ii);
1979 const gchar *address;
1980
1981 address = itip_strip_mailto (e_meeting_attendee_get_address (attendee));
1982 if (address)
1983 g_hash_table_insert (new_attendees, (gpointer) address, GINT_TO_POINTER (1));
1984 }
1985
1986 for (link = page_general->priv->orig_attendees; link; link = g_slist_next (link)) {
1987 const gchar *address = link->data;
1988
1989 if (address && !g_hash_table_contains (new_attendees, address)) {
1990 removed_attendees = g_slist_prepend (removed_attendees, g_strdup (address));
1991 }
1992 }
1993
1994 g_hash_table_destroy (new_attendees);
1995
1996 return g_slist_reverse (removed_attendees);
1997 }
1998
1999 GtkWidget *
e_comp_editor_page_general_get_source_combo_box(ECompEditorPageGeneral * page_general)2000 e_comp_editor_page_general_get_source_combo_box (ECompEditorPageGeneral *page_general)
2001 {
2002 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general), NULL);
2003
2004 return page_general->priv->source_combo_box;
2005 }
2006