evolution-3.6.4/calendar/gui/dialogs/task-editor.c

No issues found

  1 /*
  2  * Evolution calendar - Task editor dialog
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Authors:
 19  *		Miguel de Icaza <miguel@ximian.com>
 20  *      Federico Mena-Quintero <federico@ximian.com>
 21  *      Seth Alves <alves@hungry.com>
 22  *      JP Rosevear <jpr@ximian.com>
 23  *
 24  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 25  *
 26  */
 27 
 28 #ifdef HAVE_CONFIG_H
 29 #include <config.h>
 30 #endif
 31 
 32 #include <string.h>
 33 #include <glib/gi18n.h>
 34 
 35 #include "e-util/e-plugin-ui.h"
 36 #include "e-util/e-util-private.h"
 37 
 38 #include "task-page.h"
 39 #include "task-details-page.h"
 40 #include "cancel-comp.h"
 41 #include "task-editor.h"
 42 
 43 #define TASK_EDITOR_GET_PRIVATE(obj) \
 44 	(G_TYPE_INSTANCE_GET_PRIVATE \
 45 	((obj), TYPE_TASK_EDITOR, TaskEditorPrivate))
 46 
 47 struct _TaskEditorPrivate {
 48 	TaskPage *task_page;
 49 	TaskDetailsPage *task_details_page;
 50 	GtkWidget *task_details_window;
 51 
 52 	EMeetingStore *model;
 53 	gboolean assignment_shown;
 54 	gboolean updating;
 55 };
 56 
 57 /* Extends the UI definition in CompEditor */
 58 static const gchar *ui =
 59 "<ui>"
 60 "  <menubar action='main-menu'>"
 61 "    <menu action='view-menu'>"
 62 "      <menuitem action='view-type'/>"
 63 "      <menuitem action='view-status'/>"
 64 "      <menuitem action='view-role'/>"
 65 "      <menuitem action='view-rsvp'/>"
 66 "      <separator/>"
 67 "      <menuitem action='view-time-zone'/>"
 68 "      <menuitem action='view-categories'/>"
 69 "    </menu>"
 70 "    <menu action='insert-menu'>"
 71 "      <menuitem action='send-options'/>"
 72 "    </menu>"
 73 "    <menu action='options-menu'>"
 74 "      <menu action='classification-menu'>"
 75 "        <menuitem action='classify-public'/>"
 76 "        <menuitem action='classify-private'/>"
 77 "        <menuitem action='classify-confidential'/>"
 78 "      </menu>"
 79 "      <menuitem action='option-status'/>"
 80 "    </menu>"
 81 "  </menubar>"
 82 "  <toolbar name='main-toolbar'>"
 83 "    <placeholder name='content'>"
 84 "      <toolitem action='view-time-zone'/>"
 85 "      <toolitem action='option-status'/>"
 86 "    </placeholder>"
 87 "  </toolbar>"
 88 "</ui>";
 89 
 90 static void	task_editor_edit_comp		(CompEditor *editor,
 91 						 ECalComponent *comp);
 92 static gboolean	task_editor_send_comp		(CompEditor *editor,
 93 						 ECalComponentItipMethod method,
 94 						 gboolean strip_alarms);
 95 
 96 G_DEFINE_TYPE (TaskEditor, task_editor, TYPE_COMP_EDITOR)
 97 
 98 static void
 99 action_option_status_cb (GtkAction *action,
100                          TaskEditor *editor)
101 {
102 	gtk_widget_show (editor->priv->task_details_window);
103 }
104 
105 static void
106 action_send_options_cb (GtkAction *action,
107                         TaskEditor *editor)
108 {
109 	task_page_send_options_clicked_cb (editor->priv->task_page);
110 }
111 
112 static GtkActionEntry task_entries[] = {
113 
114 	{ "option-status",
115 	  "stock_view-details",
116 	  N_("_Status Details"),
117 	  "<Control>t",
118 	  N_("Click to change or view the status details of the task"),
119 	  G_CALLBACK (action_option_status_cb) }
120 };
121 
122 static GtkActionEntry assigned_task_entries[] = {
123 
124 	{ "send-options",
125 	  NULL,
126 	  N_("_Send Options"),
127 	  NULL,
128 	  N_("Insert advanced send options"),
129 	  G_CALLBACK (action_send_options_cb) }
130 };
131 
132 static void
133 task_editor_model_changed_cb (TaskEditor *te)
134 {
135 	if (!te->priv->updating) {
136 		comp_editor_set_changed (COMP_EDITOR (te), TRUE);
137 		comp_editor_set_needs_send (COMP_EDITOR (te), TRUE);
138 	}
139 }
140 
141 static void
142 task_editor_dispose (GObject *object)
143 {
144 	TaskEditorPrivate *priv;
145 
146 	priv = TASK_EDITOR_GET_PRIVATE (object);
147 
148 	if (priv->task_page) {
149 		g_object_unref (priv->task_page);
150 		priv->task_page = NULL;
151 	}
152 
153 	if (priv->task_details_page) {
154 		g_object_unref (priv->task_details_page);
155 		priv->task_details_page = NULL;
156 	}
157 
158 	if (priv->model) {
159 		g_object_unref (priv->model);
160 		priv->model = NULL;
161 	}
162 
163 	/* Chain up to parent's dispose() method. */
164 	G_OBJECT_CLASS (task_editor_parent_class)->dispose (object);
165 }
166 
167 static void
168 task_editor_constructed (GObject *object)
169 {
170 	TaskEditorPrivate *priv;
171 	CompEditor *editor;
172 	CompEditorFlags flags;
173 	GtkActionGroup *action_group;
174 	gboolean is_assigned;
175 
176 	priv = TASK_EDITOR_GET_PRIVATE (object);
177 	editor = COMP_EDITOR (object);
178 
179 	flags = comp_editor_get_flags (editor);
180 	is_assigned = flags & COMP_EDITOR_IS_ASSIGNED;
181 
182 	priv->task_page = task_page_new (priv->model, editor);
183 	task_page_set_assignment (priv->task_page, is_assigned);
184 	comp_editor_append_page (
185 		editor, COMP_EDITOR_PAGE (priv->task_page),
186 		_("Task"), TRUE);
187 
188 	action_group = comp_editor_get_action_group (editor, "coordinated");
189 	gtk_action_group_set_visible (action_group, is_assigned);
190 
191 	if (is_assigned) {
192 		ECalClient *client;
193 
194 		client = comp_editor_get_client (editor);
195 
196 		if (e_client_check_capability (
197 				E_CLIENT (client),
198 				CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS))
199 			task_page_show_options (priv->task_page);
200 		comp_editor_set_group_item (editor, TRUE);
201 	}
202 
203 	g_object_bind_property (
204 		object, "client",
205 		priv->model, "client",
206 		G_BINDING_SYNC_CREATE);
207 
208 	/* Chain up to parent's constructed() method. */
209 	G_OBJECT_CLASS (task_editor_parent_class)->constructed (object);
210 }
211 
212 static void
213 task_editor_show_categories (CompEditor *editor,
214                              gboolean visible)
215 {
216 	TaskEditor *task_editor = TASK_EDITOR (editor);
217 
218 	task_page_set_show_categories (task_editor->priv->task_page, visible);
219 }
220 
221 static void
222 task_editor_show_role (CompEditor *editor,
223                        gboolean visible)
224 {
225 	TaskEditor *task_editor = TASK_EDITOR (editor);
226 
227 	task_page_set_view_role (task_editor->priv->task_page, visible);
228 }
229 
230 static void
231 task_editor_show_rsvp (CompEditor *editor,
232                        gboolean visible)
233 {
234 	TaskEditor *task_editor = TASK_EDITOR (editor);
235 
236 	task_page_set_view_rsvp (task_editor->priv->task_page, visible);
237 }
238 
239 static void
240 task_editor_show_status (CompEditor *editor,
241                          gboolean visible)
242 {
243 	TaskEditor *task_editor = TASK_EDITOR (editor);
244 
245 	task_page_set_view_status (task_editor->priv->task_page, visible);
246 }
247 
248 static void
249 task_editor_show_time_zone (CompEditor *editor,
250                             gboolean visible)
251 {
252 	TaskEditor *task_editor = TASK_EDITOR (editor);
253 
254 	task_page_set_show_timezone (task_editor->priv->task_page, visible);
255 }
256 
257 static void
258 task_editor_show_type (CompEditor *editor,
259                        gboolean visible)
260 {
261 	TaskEditor *task_editor = TASK_EDITOR (editor);
262 
263 	task_page_set_view_type (task_editor->priv->task_page, visible);
264 }
265 
266 static void
267 task_editor_class_init (TaskEditorClass *class)
268 {
269 	GObjectClass *object_class;
270 	CompEditorClass *editor_class;
271 
272 	g_type_class_add_private (class, sizeof (TaskEditorPrivate));
273 
274 	object_class = G_OBJECT_CLASS (class);
275 	object_class->dispose = task_editor_dispose;
276 	object_class->constructed = task_editor_constructed;
277 
278 	editor_class = COMP_EDITOR_CLASS (class);
279 	editor_class->help_section = "tasks-usage";
280 	editor_class->edit_comp = task_editor_edit_comp;
281 	editor_class->send_comp = task_editor_send_comp;
282 	editor_class->show_categories = task_editor_show_categories;
283 	editor_class->show_role = task_editor_show_role;
284 	editor_class->show_rsvp = task_editor_show_rsvp;
285 	editor_class->show_status = task_editor_show_status;
286 	editor_class->show_time_zone = task_editor_show_time_zone;
287 	editor_class->show_type = task_editor_show_type;
288 }
289 
290 static void
291 task_editor_init (TaskEditor *te)
292 {
293 	CompEditor *editor = COMP_EDITOR (te);
294 	GtkUIManager *ui_manager;
295 	GtkActionGroup *action_group;
296 	GtkWidget *content_area;
297 	GtkAction *action;
298 	const gchar *id;
299 	GError *error = NULL;
300 
301 	te->priv = TASK_EDITOR_GET_PRIVATE (te);
302 	te->priv->model = E_MEETING_STORE (e_meeting_store_new ());
303 	te->priv->assignment_shown = TRUE;
304 	te->priv->updating = FALSE;
305 
306 	te->priv->task_details_window = gtk_dialog_new_with_buttons (
307 		_("Task Details"), GTK_WINDOW (te), GTK_DIALOG_MODAL,
308 		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
309 	g_signal_connect (
310 		te->priv->task_details_window, "response",
311 		G_CALLBACK (gtk_widget_hide), NULL);
312 	g_signal_connect (
313 		te->priv->task_details_window, "delete-event",
314 		G_CALLBACK (gtk_widget_hide), NULL);
315 
316 	te->priv->task_details_page = task_details_page_new (editor);
317 	content_area = gtk_dialog_get_content_area (
318 		GTK_DIALOG (te->priv->task_details_window));
319 	gtk_container_add (
320 		GTK_CONTAINER (content_area),
321 		comp_editor_page_get_widget (
322 		(CompEditorPage *) te->priv->task_details_page));
323 	gtk_widget_show_all (
324 		gtk_bin_get_child (GTK_BIN (te->priv->task_details_window)));
325 	comp_editor_append_page (
326 		editor, COMP_EDITOR_PAGE (te->priv->task_details_page), NULL, FALSE);
327 
328 	action_group = comp_editor_get_action_group (editor, "individual");
329 	gtk_action_group_add_actions (
330 		action_group, task_entries,
331 		G_N_ELEMENTS (task_entries), te);
332 
333 	action_group = comp_editor_get_action_group (editor, "coordinated");
334 	gtk_action_group_add_actions (
335 		action_group, assigned_task_entries,
336 		G_N_ELEMENTS (assigned_task_entries), te);
337 
338 	ui_manager = comp_editor_get_ui_manager (editor);
339 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
340 
341 	id = "org.gnome.evolution.task-editor";
342 	e_plugin_ui_register_manager (ui_manager, id, te);
343 	e_plugin_ui_enable_manager (ui_manager, id);
344 
345 	if (error != NULL) {
346 		g_critical ("%s: %s", G_STRFUNC, error->message);
347 		g_error_free (error);
348 	}
349 
350 	action = comp_editor_get_action (editor, "print");
351 	gtk_action_set_tooltip (action, _("Print this task"));
352 
353 	g_signal_connect_swapped (
354 		te->priv->model, "row_changed",
355 		G_CALLBACK (task_editor_model_changed_cb), te);
356 	g_signal_connect_swapped (
357 		te->priv->model, "row_inserted",
358 		G_CALLBACK (task_editor_model_changed_cb), te);
359 	g_signal_connect_swapped (
360 		te->priv->model, "row_deleted",
361 		G_CALLBACK (task_editor_model_changed_cb), te);
362 }
363 
364 static void
365 task_editor_edit_comp (CompEditor *editor,
366                        ECalComponent *comp)
367 {
368 	TaskEditorPrivate *priv;
369 	ECalComponentOrganizer organizer;
370 	ECalClient *client;
371 	GSList *attendees = NULL;
372 	ESourceRegistry *registry;
373 	EShell *shell;
374 
375 	priv = TASK_EDITOR_GET_PRIVATE (editor);
376 
377 	priv->updating = TRUE;
378 
379 	if (COMP_EDITOR_CLASS (task_editor_parent_class)->edit_comp)
380 		COMP_EDITOR_CLASS (task_editor_parent_class)->edit_comp (editor, comp);
381 
382 	shell = comp_editor_get_shell (editor);
383 	client = comp_editor_get_client (editor);
384 
385 	registry = e_shell_get_registry (shell);
386 
387 	/* Get meeting related stuff */
388 	e_cal_component_get_organizer (comp, &organizer);
389 	e_cal_component_get_attendee_list (comp, &attendees);
390 
391 	if (attendees != NULL) {
392 		GSList *l;
393 		gint row;
394 
395 		task_page_hide_options (priv->task_page);
396 		task_page_set_assignment (priv->task_page, TRUE);
397 
398 		for (l = attendees; l != NULL; l = l->next) {
399 			ECalComponentAttendee *ca = l->data;
400 			EMeetingAttendee *ia;
401 
402 			ia = E_MEETING_ATTENDEE (
403 				e_meeting_attendee_new_from_e_cal_component_attendee (ca));
404 			/* If we aren't the organizer or the attendee is just
405 			 * delegating, don't allow editing. */
406 			if (!comp_editor_get_user_org (editor) ||
407 				e_meeting_attendee_is_set_delto (ia))
408 				e_meeting_attendee_set_edit_level (
409 					ia,  E_MEETING_ATTENDEE_EDIT_NONE);
410 			comp_editor_page_add_attendee (
411 				COMP_EDITOR_PAGE (priv->task_page), ia);
412 
413 			g_object_unref (ia);
414 		}
415 
416 		/* If we aren't the organizer we can still change our own status */
417 		if (!comp_editor_get_user_org (editor)) {
418 			EMeetingAttendee *ia;
419 
420 			ia = e_meeting_store_find_self (priv->model, &row);
421 
422 			if (ia != NULL)
423 				e_meeting_attendee_set_edit_level (
424 					ia, E_MEETING_ATTENDEE_EDIT_STATUS);
425 		} else if (e_cal_client_check_organizer_must_attend (client)) {
426 			EMeetingAttendee *ia;
427 
428 			ia = e_meeting_store_find_attendee (priv->model, organizer.value, &row);
429 			if (ia != NULL)
430 				e_meeting_attendee_set_edit_level (
431 					ia, E_MEETING_ATTENDEE_EDIT_NONE);
432 		}
433 
434 		comp_editor_set_group_item (editor, TRUE);
435 		priv->assignment_shown = TRUE;
436 	}
437 	e_cal_component_free_attendee_list (attendees);
438 
439 	comp_editor_set_needs_send (
440 		editor, priv->assignment_shown &&
441 		itip_organizer_is_user (registry, comp, client));
442 
443 	priv->updating = FALSE;
444 }
445 
446 static gboolean
447 task_editor_send_comp (CompEditor *editor,
448                        ECalComponentItipMethod method,
449                        gboolean strip_alarms)
450 {
451 	TaskEditorPrivate *priv;
452 	EShell *shell;
453 	ESourceRegistry *registry;
454 	ECalComponent *comp = NULL;
455 
456 	priv = TASK_EDITOR_GET_PRIVATE (editor);
457 
458 	/* Don't cancel more than once or when just publishing */
459 	if (method == E_CAL_COMPONENT_METHOD_PUBLISH ||
460 	    method == E_CAL_COMPONENT_METHOD_CANCEL)
461 		goto parent;
462 
463 	shell = comp_editor_get_shell (editor);
464 	registry = e_shell_get_registry (shell);
465 
466 	comp = task_page_get_cancel_comp (priv->task_page);
467 	if (comp != NULL) {
468 		ECalClient *client;
469 		gboolean result;
470 
471 		client = e_meeting_store_get_client (priv->model);
472 		result = itip_send_comp (
473 			registry, E_CAL_COMPONENT_METHOD_CANCEL, comp,
474 			client, NULL, NULL, NULL, strip_alarms, FALSE);
475 		g_object_unref (comp);
476 
477 		if (!result)
478 			return FALSE;
479 	}
480 
481  parent:
482 	if (COMP_EDITOR_CLASS (task_editor_parent_class)->send_comp)
483 		return COMP_EDITOR_CLASS (task_editor_parent_class)->
484 			send_comp (editor, method, strip_alarms);
485 
486 	return FALSE;
487 }
488 
489 /**
490  * task_editor_new:
491  * @client: a ECalClient
492  *
493  * Creates a new event editor dialog.
494  *
495  * Return value: A newly-created event editor dialog, or NULL if the event
496  * editor could not be created.
497  **/
498 CompEditor *
499 task_editor_new (ECalClient *client,
500                  EShell *shell,
501                  CompEditorFlags flags)
502 {
503 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
504 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
505 
506 	return g_object_new (
507 		TYPE_TASK_EDITOR,
508 		"client", client, "flags", flags, "shell", shell, NULL);
509 }
510 
511 void
512 task_editor_show_assignment (TaskEditor *te)
513 {
514 	CompEditor *editor;
515 
516 	g_return_if_fail (IS_TASK_EDITOR (te));
517 
518 	editor = COMP_EDITOR (te);
519 
520 	task_page_set_assignment (te->priv->task_page, TRUE);
521 	if (!te->priv->assignment_shown) {
522 		te->priv->assignment_shown = TRUE;
523 		comp_editor_set_needs_send (editor, TRUE);
524 		comp_editor_set_changed (editor, FALSE);
525 	}
526 
527 }