Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
schedule-page.c:147:12 | clang-analyzer | Dereference of null pointer (loaded from field 'value') | ||
schedule-page.c:147:12 | clang-analyzer | Dereference of null pointer (loaded from field 'value') |
1 /*
2 * Evolution calendar - Scheduling page
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 * Federico Mena-Quintero <federico@ximian.com>
20 * Miguel de Icaza <miguel@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 <gtk/gtk.h>
33 #include <glib/gi18n.h>
34 #include <e-util/e-util-private.h>
35 #include <misc/e-dateedit.h>
36 #include "../e-meeting-time-sel.h"
37 #include "../itip-utils.h"
38 #include "comp-editor-util.h"
39 #include "e-delegate-dialog.h"
40 #include "schedule-page.h"
41
42 #define SCHEDULE_PAGE_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), TYPE_SCHEDULE_PAGE, SchedulePagePrivate))
45
46 /* Private part of the SchedulePage structure */
47 struct _SchedulePagePrivate {
48 GtkBuilder *builder;
49
50 /* Widgets from the UI file */
51 GtkWidget *main;
52
53 /* Model */
54 EMeetingStore *model;
55
56 /* Selector */
57 EMeetingTimeSelector *sel;
58
59 /* The timezone we use. Note that we use the same timezone for the
60 * start and end date. We convert the end date if it is passed in in
61 * another timezone. */
62 icaltimezone *zone;
63 };
64
65 static void times_changed_cb (GtkWidget *widget, SchedulePage *spage);
66
67 G_DEFINE_TYPE (SchedulePage, schedule_page, TYPE_COMP_EDITOR_PAGE)
68
69 static void
70 sensitize_widgets (SchedulePage *spage)
71 {
72 SchedulePagePrivate *priv = spage->priv;
73 CompEditor *editor;
74 ECalClient *client;
75
76 editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (spage));
77 client = comp_editor_get_client (editor);
78
79 e_meeting_time_selector_set_read_only (
80 priv->sel, e_client_is_readonly (E_CLIENT (client)));
81 }
82
83 /* Set date/time */
84 static void
85 update_time (SchedulePage *spage,
86 ECalComponentDateTime *start_date,
87 ECalComponentDateTime *end_date)
88 {
89 SchedulePagePrivate *priv = spage->priv;
90 CompEditor *editor;
91 struct icaltimetype start_tt, end_tt;
92 icaltimezone *start_zone = NULL, *end_zone = NULL;
93 ECalClient *client;
94 gboolean all_day;
95
96 editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (spage));
97 client = comp_editor_get_client (editor);
98
99 if (start_date->tzid) {
100 /* Note that if we are creating a new event, the timezones may not be
101 * on the server, so we try to get the builtin timezone with the TZID
102 * first. */
103 start_zone = icaltimezone_get_builtin_timezone_from_tzid (start_date->tzid);
104 if (!start_zone) {
105 GError *error = NULL;
106
107 e_cal_client_get_timezone_sync (
108 client, start_date->tzid,
109 &start_zone, NULL, &error);
110
111 if (error != NULL) {
112 /* FIXME: Handle error better. */
113 g_warning (
114 "Couldn't get timezone '%s' from server: %s",
115 start_date->tzid ? start_date->tzid : "",
116 error->message);
117 g_error_free (error);
118 }
119 }
120 }
121
122 if (end_date->tzid) {
123 end_zone = icaltimezone_get_builtin_timezone_from_tzid (end_date->tzid);
124 if (!end_zone) {
125 GError *error = NULL;
126
127 e_cal_client_get_timezone_sync (
128 client, end_date->tzid,
129 &end_zone, NULL, &error);
130
131 if (error != NULL) {
132 /* FIXME: Handle error better. */
133 g_warning (
134 "Couldn't get timezone '%s' from server: %s",
135 end_date->tzid ? end_date->tzid : "",
136 error->message);
137 g_error_free (error);
138 }
139 }
140 }
141
142 start_tt = *start_date->value;
143 if (!end_date->value && start_tt.is_date) {
144 end_tt = start_tt;
145 icaltime_adjust (&end_tt, 1, 0, 0, 0);
146 } else {
147 end_tt = *end_date->value;
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
148 }
149
150 /* If the end zone is not the same as the start zone, we convert it. */
151 priv->zone = start_zone;
152 if (start_zone != end_zone) {
153 icaltimezone_convert_time (&end_tt, end_zone, start_zone);
154 }
155 e_meeting_store_set_timezone (priv->model, priv->zone);
156
157 all_day = (start_tt.is_date && end_tt.is_date) ? TRUE : FALSE;
158
159 /* For All Day Events, if DTEND is after DTSTART, we subtract 1 day
160 * from it. */
161 if (all_day) {
162 if (icaltime_compare_date_only (end_tt, start_tt) > 0) {
163 icaltime_adjust (&end_tt, -1, 0, 0, 0);
164 }
165 }
166
167 e_date_edit_set_date (
168 E_DATE_EDIT (priv->sel->start_date_edit), start_tt.year,
169 start_tt.month, start_tt.day);
170 e_date_edit_set_time_of_day (
171 E_DATE_EDIT (priv->sel->start_date_edit),
172 start_tt.hour, start_tt.minute);
173
174 e_date_edit_set_date (
175 E_DATE_EDIT (priv->sel->end_date_edit), end_tt.year,
176 end_tt.month, end_tt.day);
177 e_date_edit_set_time_of_day (
178 E_DATE_EDIT (priv->sel->end_date_edit),
179 end_tt.hour, end_tt.minute);
180
181 }
182
183 static void
184 schedule_page_dispose (GObject *object)
185 {
186 SchedulePagePrivate *priv;
187
188 priv = SCHEDULE_PAGE_GET_PRIVATE (object);
189
190 if (priv->main != NULL) {
191 g_object_unref (priv->main);
192 priv->main = NULL;
193 }
194
195 if (priv->builder != NULL) {
196 g_object_unref (priv->builder);
197 priv->builder = NULL;
198 }
199
200 if (priv->model != NULL) {
201 g_object_unref (priv->model);
202 priv->model = NULL;
203 }
204
205 /* Chain up to parent's dispose() method. */
206 G_OBJECT_CLASS (schedule_page_parent_class)->dispose (object);
207 }
208
209 static GtkWidget *
210 schedule_page_get_widget (CompEditorPage *page)
211 {
212 SchedulePage *spage;
213 SchedulePagePrivate *priv;
214
215 spage = SCHEDULE_PAGE (page);
216 priv = spage->priv;
217
218 return priv->main;
219 }
220
221 static void
222 schedule_page_focus_main_widget (CompEditorPage *page)
223 {
224 SchedulePage *spage;
225 SchedulePagePrivate *priv;
226
227 spage = SCHEDULE_PAGE (page);
228 priv = spage->priv;
229
230 gtk_widget_grab_focus (GTK_WIDGET (priv->sel));
231 }
232
233 static gboolean
234 schedule_page_fill_widgets (CompEditorPage *page,
235 ECalComponent *comp)
236 {
237 SchedulePage *spage;
238 ECalComponentDateTime start_date, end_date;
239 gboolean validated = TRUE;
240
241 spage = SCHEDULE_PAGE (page);
242
243 /* Start and end times */
244 e_cal_component_get_dtstart (comp, &start_date);
245 e_cal_component_get_dtend (comp, &end_date);
246 if (!start_date.value)
247 validated = FALSE;
248 else if (!end_date.value)
249 validated = FALSE;
250 else
251 update_time (spage, &start_date, &end_date);
252
253 e_cal_component_free_datetime (&start_date);
254 e_cal_component_free_datetime (&end_date);
255
256 sensitize_widgets (spage);
257
258 return validated;
259 }
260
261 static gboolean
262 schedule_page_fill_component (CompEditorPage *page,
263 ECalComponent *comp)
264 {
265 return TRUE;
266 }
267
268 static void
269 schedule_page_set_dates (CompEditorPage *page,
270 CompEditorPageDates *dates)
271 {
272 SchedulePage *spage;
273
274 spage = SCHEDULE_PAGE (page);
275
276 comp_editor_page_set_updating (page, TRUE);
277 update_time (spage, dates->start, dates->end);
278 comp_editor_page_set_updating (page, FALSE);
279 }
280
281 static void
282 schedule_page_class_init (SchedulePageClass *class)
283 {
284 GObjectClass *object_class;
285 CompEditorPageClass *editor_page_class;
286
287 g_type_class_add_private (class, sizeof (SchedulePagePrivate));
288
289 object_class = G_OBJECT_CLASS (class);
290 object_class->dispose = schedule_page_dispose;
291
292 editor_page_class = COMP_EDITOR_PAGE_CLASS (class);
293 editor_page_class->get_widget = schedule_page_get_widget;
294 editor_page_class->focus_main_widget = schedule_page_focus_main_widget;
295 editor_page_class->fill_widgets = schedule_page_fill_widgets;
296 editor_page_class->fill_component = schedule_page_fill_component;
297 editor_page_class->set_dates = schedule_page_set_dates;
298 }
299
300 static void
301 schedule_page_init (SchedulePage *spage)
302 {
303 spage->priv = SCHEDULE_PAGE_GET_PRIVATE (spage);
304 }
305
306 /* Gets the widgets from the XML file and returns if they are all available. */
307 static gboolean
308 get_widgets (SchedulePage *spage)
309 {
310 CompEditorPage *page = COMP_EDITOR_PAGE (spage);
311 SchedulePagePrivate *priv;
312 GSList *accel_groups;
313 GtkWidget *toplevel;
314 GtkWidget *parent;
315
316 priv = spage->priv;
317
318 #define GW(name) e_builder_get_widget (priv->builder, name)
319
320 priv->main = GW ("schedule-page");
321 if (!priv->main)
322 return FALSE;
323
324 /* Get the GtkAccelGroup from the toplevel window, so we can install
325 * it when the notebook page is mapped. */
326 toplevel = gtk_widget_get_toplevel (priv->main);
327 accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
328 if (accel_groups)
329 page->accel_group = g_object_ref (accel_groups->data);
330
331 g_object_ref (priv->main);
332 parent = gtk_widget_get_parent (priv->main);
333 gtk_container_remove (GTK_CONTAINER (parent), priv->main);
334
335 #undef GW
336
337 return TRUE;
338 }
339
340 static gboolean
341 init_widgets (SchedulePage *spage)
342 {
343 SchedulePagePrivate *priv;
344
345 priv = spage->priv;
346
347 g_signal_connect (
348 priv->sel, "changed",
349 G_CALLBACK (times_changed_cb), spage);
350
351 return TRUE;
352 }
353
354 void
355 schedule_page_set_meeting_time (SchedulePage *spage,
356 icaltimetype *start_tt,
357 icaltimetype *end_tt)
358 {
359 SchedulePagePrivate *priv;
360 gboolean all_day;
361
362 priv = spage->priv;
363
364 all_day = (start_tt->is_date && end_tt->is_date) ? TRUE : FALSE;
365
366 if (all_day) {
367 if (icaltime_compare_date_only (*end_tt, *start_tt) > 0) {
368 icaltime_adjust (end_tt, -1, 0, 0, 0);
369 }
370 }
371
372 e_meeting_time_selector_set_meeting_time (
373 priv->sel, start_tt->year, start_tt->month,
374 start_tt->day, start_tt->hour, start_tt->minute,
375 end_tt->year, end_tt->month, end_tt->day,
376 end_tt->hour, end_tt->minute);
377 e_meeting_time_selector_set_all_day (priv->sel, all_day);
378
379 }
380
381 /**
382 * schedule_page_construct:
383 * @spage: An schedule page.
384 *
385 * Constructs an schedule page by loading its Glade data.
386 *
387 * Return value: The same object as @spage, or NULL if the widgets could not
388 * be created.
389 **/
390 SchedulePage *
391 schedule_page_construct (SchedulePage *spage,
392 EMeetingStore *ems)
393 {
394 SchedulePagePrivate *priv = spage->priv;
395 CompEditor *editor;
396
397 editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (spage));
398
399 priv->builder = gtk_builder_new ();
400 e_load_ui_builder_definition (priv->builder, "schedule-page.ui");
401
402 if (!get_widgets (spage)) {
403 g_message (
404 "schedule_page_construct(): "
405 "Could not find all widgets in the XML file!");
406 return NULL;
407 }
408
409 /* Model */
410 g_object_ref (ems);
411 priv->model = ems;
412
413 /* Selector */
414 priv->sel = E_MEETING_TIME_SELECTOR (e_meeting_time_selector_new (ems));
415 gtk_widget_set_size_request ((GtkWidget *) priv->sel, -1, 400);
416 e_meeting_time_selector_set_working_hours (
417 priv->sel,
418 comp_editor_get_work_day_start_hour (editor),
419 comp_editor_get_work_day_start_minute (editor),
420 comp_editor_get_work_day_end_hour (editor),
421 comp_editor_get_work_day_end_minute (editor));
422 gtk_widget_show (GTK_WIDGET (priv->sel));
423 gtk_box_pack_start (GTK_BOX (priv->main), GTK_WIDGET (priv->sel), TRUE, TRUE, 6);
424
425 if (!init_widgets (spage)) {
426 g_message (
427 "schedule_page_construct(): "
428 "Could not initialize the widgets!");
429 return NULL;
430 }
431
432 g_signal_connect_swapped (
433 editor, "notify::client",
434 G_CALLBACK (sensitize_widgets), spage);
435
436 return spage;
437 }
438
439 /**
440 * schedule_page_new:
441 *
442 * Creates a new schedule page.
443 *
444 * Return value: A newly-created schedule page, or NULL if the page could
445 * not be created.
446 **/
447 SchedulePage *
448 schedule_page_new (EMeetingStore *ems,
449 CompEditor *editor)
450 {
451 SchedulePage *spage;
452
453 spage = g_object_new (TYPE_SCHEDULE_PAGE, "editor", editor, NULL);
454 if (!schedule_page_construct (spage, ems)) {
455 g_object_unref (spage);
456 g_return_val_if_reached (NULL);
457 }
458
459 return spage;
460 }
461
462 void
463 schedule_page_update_free_busy (SchedulePage *spage)
464 {
465 SchedulePagePrivate *priv;
466
467 g_return_if_fail (spage != NULL);
468 g_return_if_fail (IS_SCHEDULE_PAGE (spage));
469
470 priv = spage->priv;
471
472 e_meeting_time_selector_refresh_free_busy (priv->sel, 0, TRUE);
473 }
474
475 void
476 schedule_page_set_name_selector (SchedulePage *spage,
477 ENameSelector *name_selector)
478 {
479 SchedulePagePrivate *priv;
480
481 g_return_if_fail (spage != NULL);
482 g_return_if_fail (IS_SCHEDULE_PAGE (spage));
483
484 priv = spage->priv;
485
486 e_meeting_list_view_set_name_selector (priv->sel->list_view, name_selector);
487 }
488
489 static void
490 times_changed_cb (GtkWidget *widget,
491 SchedulePage *spage)
492 {
493 SchedulePagePrivate *priv;
494 CompEditorPageDates dates;
495 CompEditor *editor;
496 ECalComponentDateTime start_dt, end_dt;
497 struct icaltimetype start_tt = icaltime_null_time ();
498 struct icaltimetype end_tt = icaltime_null_time ();
499
500 priv = spage->priv;
501
502 if (comp_editor_page_get_updating (COMP_EDITOR_PAGE (spage)))
503 return;
504
505 editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (spage));
506
507 e_date_edit_get_date (
508 E_DATE_EDIT (priv->sel->start_date_edit),
509 &start_tt.year,
510 &start_tt.month,
511 &start_tt.day);
512 e_date_edit_get_time_of_day (
513 E_DATE_EDIT (priv->sel->start_date_edit),
514 &start_tt.hour,
515 &start_tt.minute);
516 e_date_edit_get_date (
517 E_DATE_EDIT (priv->sel->end_date_edit),
518 &end_tt.year,
519 &end_tt.month,
520 &end_tt.day);
521 e_date_edit_get_time_of_day (
522 E_DATE_EDIT (priv->sel->end_date_edit),
523 &end_tt.hour,
524 &end_tt.minute);
525
526 start_dt.value = &start_tt;
527 end_dt.value = &end_tt;
528
529 if (e_date_edit_get_show_time (E_DATE_EDIT (priv->sel->start_date_edit))) {
530 /* We set the start and end to the same timezone. */
531 start_dt.tzid = icaltimezone_get_tzid (priv->zone);
532 end_dt.tzid = start_dt.tzid;
533 } else {
534 /* For All-Day Events, we set the timezone to NULL, and add
535 * 1 day to DTEND. */
536 start_dt.value->is_date = TRUE;
537 start_dt.tzid = NULL;
538 end_dt.value->is_date = TRUE;
539 icaltime_adjust (&end_tt, 1, 0, 0, 0);
540 end_dt.tzid = NULL;
541 }
542
543 dates.start = &start_dt;
544 dates.end = &end_dt;
545 dates.due = NULL;
546 dates.complete = NULL;
547
548 comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (spage), &dates);
549 comp_editor_set_changed (editor, TRUE);
550 }