2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
21 #include <glib/gi18n-lib.h>
24 #include <e-util/e-util.h>
26 #include "e-comp-editor-page-schedule.h"
28 struct _ECompEditorPageSchedulePrivate
{
30 EMeetingTimeSelector
*selector
;
38 G_DEFINE_TYPE (ECompEditorPageSchedule
, e_comp_editor_page_schedule
, E_TYPE_COMP_EDITOR_PAGE
)
41 ecep_schedule_get_work_day_range_for (GSettings
*settings
,
48 gint start_adept
= -1, end_adept
= -1;
49 const gchar
*start_key
= NULL
, *end_key
= NULL
;
51 g_return_if_fail (G_IS_SETTINGS (settings
));
52 g_return_if_fail (start_hour
!= NULL
);
53 g_return_if_fail (start_minute
!= NULL
);
54 g_return_if_fail (end_hour
!= NULL
);
55 g_return_if_fail (end_minute
!= NULL
);
59 start_key
= "day-start-mon";
60 end_key
= "day-end-mon";
63 start_key
= "day-start-tue";
64 end_key
= "day-end-tue";
66 case G_DATE_WEDNESDAY
:
67 start_key
= "day-start-wed";
68 end_key
= "day-end-wed";
71 start_key
= "day-start-thu";
72 end_key
= "day-end-thu";
75 start_key
= "day-start-fri";
76 end_key
= "day-end-fri";
79 start_key
= "day-start-sat";
80 end_key
= "day-end-sat";
83 start_key
= "day-start-sun";
84 end_key
= "day-end-sun";
90 if (start_key
&& end_key
) {
91 start_adept
= g_settings_get_int (settings
, start_key
);
92 end_adept
= g_settings_get_int (settings
, end_key
);
95 if (start_adept
> 0 && (start_adept
/ 100) >= 0 && (start_adept
/ 100) <= 23 &&
96 (start_adept
% 100) >= 0 && (start_adept
% 100) <= 59) {
97 *start_hour
= start_adept
/ 100;
98 *start_minute
= start_adept
% 100;
100 *start_hour
= g_settings_get_int (settings
, "day-start-hour");
101 *start_minute
= g_settings_get_int (settings
, "day-start-minute");
104 if (end_adept
> 0 && (end_adept
/ 100) >= 0 && (end_adept
/ 100) <= 23 &&
105 (end_adept
% 100) >= 0 && (end_adept
% 100) <= 59) {
106 *end_hour
= end_adept
/ 100;
107 *end_minute
= end_adept
% 100;
109 *end_hour
= g_settings_get_int (settings
, "day-end-hour");
110 *end_minute
= g_settings_get_int (settings
, "day-end-minute");
115 ecep_schedule_editor_times_changed_cb (ECompEditor
*comp_editor
,
116 ECompEditorPageSchedule
*page_schedule
)
118 ECompEditorPropertyPartDatetime
*dtstart
, *dtend
;
119 ECompEditorPropertyPart
*dtstart_part
= NULL
, *dtend_part
= NULL
;
120 EDateEdit
*start_date_edit
, *end_date_edit
;
121 struct icaltimetype start_tt
, end_tt
;
123 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
124 g_return_if_fail (page_schedule
->priv
->selector
!= NULL
);
126 e_comp_editor_get_time_parts (comp_editor
, &dtstart_part
, &dtend_part
);
128 if (!dtstart_part
|| !dtend_part
)
131 dtstart
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtstart_part
);
132 dtend
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtend_part
);
134 start_tt
= e_comp_editor_property_part_datetime_get_value (dtstart
);
135 end_tt
= e_comp_editor_property_part_datetime_get_value (dtend
);
137 /* For All Day Events, if DTEND is after DTSTART, we subtract 1 day from it. */
138 if (start_tt
.is_date
&& end_tt
.is_date
&&
139 icaltime_compare_date_only (end_tt
, start_tt
) > 0)
140 icaltime_adjust (&end_tt
, -1, 0, 0, 0);
142 e_comp_editor_page_set_updating (E_COMP_EDITOR_PAGE (page_schedule
), TRUE
);
144 start_date_edit
= E_DATE_EDIT (page_schedule
->priv
->selector
->start_date_edit
);
145 end_date_edit
= E_DATE_EDIT (page_schedule
->priv
->selector
->end_date_edit
);
147 e_date_edit_set_date (start_date_edit
, start_tt
.year
, start_tt
.month
, start_tt
.day
);
148 e_date_edit_set_time_of_day (start_date_edit
, start_tt
.hour
, start_tt
.minute
);
150 e_date_edit_set_date (end_date_edit
, end_tt
.year
, end_tt
.month
, end_tt
.day
);
151 e_date_edit_set_time_of_day (end_date_edit
, end_tt
.hour
, end_tt
.minute
);
153 e_comp_editor_page_set_updating (E_COMP_EDITOR_PAGE (page_schedule
), FALSE
);
157 ecep_schedule_editor_target_client_notify_cb (GObject
*comp_editor
,
161 ECompEditorPageSchedule
*page_schedule
= user_data
;
162 ECalClient
*target_client
;
164 g_return_if_fail (E_IS_COMP_EDITOR (comp_editor
));
165 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
166 g_return_if_fail (page_schedule
->priv
->store
!= NULL
);
167 g_return_if_fail (page_schedule
->priv
->selector
!= NULL
);
169 target_client
= e_comp_editor_get_target_client (E_COMP_EDITOR (comp_editor
));
170 e_meeting_store_set_client (page_schedule
->priv
->store
, target_client
);
171 e_meeting_time_selector_refresh_free_busy (page_schedule
->priv
->selector
, -1, TRUE
);
175 ecep_schedule_set_time_to_editor (ECompEditorPageSchedule
*page_schedule
)
177 EMeetingTimeSelector
*selector
;
178 ECompEditorPropertyPartDatetime
*dtstart
, *dtend
;
179 ECompEditorPropertyPart
*dtstart_part
= NULL
, *dtend_part
= NULL
;
180 ECompEditor
*comp_editor
;
181 struct icaltimetype start_tt
, end_tt
;
183 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
184 g_return_if_fail (E_IS_MEETING_TIME_SELECTOR (page_schedule
->priv
->selector
));
186 comp_editor
= e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_schedule
));
188 e_comp_editor_get_time_parts (comp_editor
, &dtstart_part
, &dtend_part
);
190 if (!dtstart_part
|| !dtend_part
) {
191 g_clear_object (&comp_editor
);
195 selector
= page_schedule
->priv
->selector
;
196 dtstart
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtstart_part
);
197 dtend
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtend_part
);
199 start_tt
= e_comp_editor_property_part_datetime_get_value (dtstart
);
200 end_tt
= e_comp_editor_property_part_datetime_get_value (dtend
);
202 e_date_edit_get_date (
203 E_DATE_EDIT (selector
->start_date_edit
),
207 e_date_edit_get_time_of_day (
208 E_DATE_EDIT (selector
->start_date_edit
),
211 e_date_edit_get_date (
212 E_DATE_EDIT (selector
->end_date_edit
),
216 e_date_edit_get_time_of_day (
217 E_DATE_EDIT (selector
->end_date_edit
),
221 if (!e_date_edit_get_show_time (E_DATE_EDIT (selector
->start_date_edit
))) {
222 /* For All-Day Events, we set the timezone to NULL, and add 1 day to DTEND. */
223 start_tt
.is_date
= TRUE
;
224 start_tt
.zone
= NULL
;
225 end_tt
.is_date
= TRUE
;
228 icaltime_adjust (&end_tt
, 1, 0, 0, 0);
230 start_tt
.is_date
= FALSE
;
231 end_tt
.is_date
= FALSE
;
234 e_comp_editor_property_part_datetime_set_value (dtstart
, start_tt
);
235 e_comp_editor_property_part_datetime_set_value (dtend
, end_tt
);
237 g_clear_object (&comp_editor
);
241 ecep_schedule_selector_changed_cb (EMeetingTimeSelector
*selector
,
242 ECompEditorPageSchedule
*page_schedule
)
244 ECompEditorPage
*page
;
246 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
247 g_return_if_fail (page_schedule
->priv
->selector
== selector
);
249 page
= E_COMP_EDITOR_PAGE (page_schedule
);
251 if (e_comp_editor_page_get_updating (page
))
254 e_comp_editor_page_set_updating (page
, TRUE
);
256 ecep_schedule_set_time_to_editor (page_schedule
);
258 e_comp_editor_page_set_updating (page
, FALSE
);
259 e_comp_editor_page_emit_changed (page
);
263 ecep_schedule_sensitize_widgets (ECompEditorPage
*page
,
264 gboolean force_insensitive
)
266 ECompEditorPageSchedule
*page_schedule
;
268 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page
));
270 E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_schedule_parent_class
)->sensitize_widgets (page
, force_insensitive
);
272 page_schedule
= E_COMP_EDITOR_PAGE_SCHEDULE (page
);
274 e_meeting_time_selector_set_read_only (page_schedule
->priv
->selector
, force_insensitive
);
278 ecep_schedule_fill_widgets (ECompEditorPage
*page
,
279 icalcomponent
*component
)
281 ECompEditorPageSchedule
*page_schedule
;
282 ECompEditorPropertyPartDatetime
*dtstart
, *dtend
;
283 ECompEditorPropertyPart
*dtstart_part
= NULL
, *dtend_part
= NULL
;
284 ECompEditor
*comp_editor
;
285 EMeetingTimeSelector
*selector
;
286 struct icaltimetype start_tt
, end_tt
;
288 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page
));
289 g_return_if_fail (component
!= NULL
);
291 E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_schedule_parent_class
)->fill_widgets (page
, component
);
293 page_schedule
= E_COMP_EDITOR_PAGE_SCHEDULE (page
);
295 /* dtstart/dtend parts should be already populated, thus
296 get values from them, instead of from the component */
298 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
299 g_return_if_fail (E_IS_MEETING_TIME_SELECTOR (page_schedule
->priv
->selector
));
301 comp_editor
= e_comp_editor_page_ref_editor (page
);
303 e_comp_editor_get_time_parts (comp_editor
, &dtstart_part
, &dtend_part
);
305 if (!dtstart_part
|| !dtend_part
) {
306 g_clear_object (&comp_editor
);
310 selector
= page_schedule
->priv
->selector
;
311 dtstart
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtstart_part
);
312 dtend
= E_COMP_EDITOR_PROPERTY_PART_DATETIME (dtend_part
);
314 start_tt
= e_comp_editor_property_part_datetime_get_value (dtstart
);
315 end_tt
= e_comp_editor_property_part_datetime_get_value (dtend
);
317 if (start_tt
.is_date
) {
318 /* For All-Day Events, we set the timezone to NULL, and add 1 day to DTEND. */
319 start_tt
.is_date
= TRUE
;
320 start_tt
.zone
= NULL
;
321 end_tt
.is_date
= TRUE
;
324 icaltime_adjust (&end_tt
, 1, 0, 0, 0);
326 start_tt
.is_date
= FALSE
;
327 end_tt
.is_date
= FALSE
;
330 e_comp_editor_page_set_updating (page
, TRUE
);
332 e_date_edit_set_date (
333 E_DATE_EDIT (selector
->start_date_edit
),
337 e_date_edit_set_time_of_day (
338 E_DATE_EDIT (selector
->start_date_edit
),
341 e_date_edit_set_date (
342 E_DATE_EDIT (selector
->end_date_edit
),
346 e_date_edit_set_time_of_day (
347 E_DATE_EDIT (selector
->end_date_edit
),
351 e_comp_editor_page_set_updating (page
, FALSE
);
353 g_clear_object (&comp_editor
);
357 ecep_schedule_fill_component (ECompEditorPage
*page
,
358 icalcomponent
*component
)
360 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page
), FALSE
);
361 g_return_val_if_fail (component
!= NULL
, FALSE
);
363 return E_COMP_EDITOR_PAGE_CLASS (e_comp_editor_page_schedule_parent_class
)->fill_component (page
, component
);
367 e_comp_editor_page_schedule_set_store (ECompEditorPageSchedule
*page_schedule
,
368 EMeetingStore
*store
)
370 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
371 g_return_if_fail (E_IS_MEETING_STORE (store
));
372 g_return_if_fail (page_schedule
->priv
->store
== NULL
);
374 page_schedule
->priv
->store
= g_object_ref (store
);
378 e_comp_editor_page_schedule_set_property (GObject
*object
,
383 switch (property_id
) {
385 e_comp_editor_page_schedule_set_store (
386 E_COMP_EDITOR_PAGE_SCHEDULE (object
),
387 g_value_get_object (value
));
391 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
395 e_comp_editor_page_schedule_get_property (GObject
*object
,
400 switch (property_id
) {
404 e_comp_editor_page_schedule_get_store (
405 E_COMP_EDITOR_PAGE_SCHEDULE (object
)));
409 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
413 ecep_schedule_select_page_cb (GtkAction
*action
,
414 ECompEditorPage
*page
)
416 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page
));
418 e_comp_editor_page_select (page
);
422 ecep_schedule_setup_ui (ECompEditorPageSchedule
*page_schedule
)
426 " <menubar action='main-menu'>"
427 " <menu action='options-menu'>"
428 " <placeholder name='tabs'>"
429 " <menuitem action='page-schedule'/>"
433 " <toolbar name='main-toolbar'>"
434 " <placeholder name='after-content'>\n"
435 " <toolitem action='page-schedule'/>\n"
440 const GtkActionEntry options_actions
[] = {
445 N_("Query free / busy information for the attendees"),
446 G_CALLBACK (ecep_schedule_select_page_cb
) }
449 ECompEditor
*comp_editor
;
450 GtkUIManager
*ui_manager
;
452 GtkActionGroup
*action_group
;
453 GError
*error
= NULL
;
455 g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
));
457 comp_editor
= e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_schedule
));
458 ui_manager
= e_comp_editor_get_ui_manager (comp_editor
);
459 action_group
= e_comp_editor_get_action_group (comp_editor
, "individual");
461 gtk_action_group_add_actions (action_group
,
462 options_actions
, G_N_ELEMENTS (options_actions
), page_schedule
);
464 gtk_ui_manager_add_ui_from_string (ui_manager
, ui
, -1, &error
);
467 g_critical ("%s: %s", G_STRFUNC
, error
->message
);
468 g_error_free (error
);
471 action
= e_comp_editor_get_action (comp_editor
, "page-schedule");
472 e_binding_bind_property (
473 page_schedule
, "visible",
475 G_BINDING_SYNC_CREATE
);
477 g_clear_object (&comp_editor
);
481 e_comp_editor_page_schedule_constructed (GObject
*object
)
483 ECompEditorPageSchedule
*page_schedule
;
484 ECompEditor
*comp_editor
;
489 G_OBJECT_CLASS (e_comp_editor_page_schedule_parent_class
)->constructed (object
);
491 page_schedule
= E_COMP_EDITOR_PAGE_SCHEDULE (object
);
493 g_return_if_fail (page_schedule
->priv
->store
!= NULL
);
495 widget
= e_meeting_time_selector_new (page_schedule
->priv
->store
);
496 g_object_set (G_OBJECT (widget
),
498 "halign", GTK_ALIGN_FILL
,
500 "valign", GTK_ALIGN_FILL
,
502 gtk_widget_show (widget
);
503 gtk_grid_attach (GTK_GRID (page_schedule
), widget
, 0, 0, 1, 1);
505 page_schedule
->priv
->selector
= E_MEETING_TIME_SELECTOR (widget
);
507 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
509 for (weekday
= G_DATE_BAD_WEEKDAY
; weekday
<= G_DATE_SUNDAY
; weekday
++) {
510 gint start_hour
= 8, start_minute
= 0, end_hour
= 17, end_minute
= 0;
512 ecep_schedule_get_work_day_range_for (settings
, weekday
,
513 &start_hour
, &start_minute
, &end_hour
, &end_minute
);
515 e_meeting_time_selector_set_working_hours (page_schedule
->priv
->selector
,
516 weekday
, start_hour
, start_minute
, end_hour
, end_minute
);
519 g_clear_object (&settings
);
521 comp_editor
= e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_schedule
));
523 g_signal_connect (comp_editor
, "times-changed",
524 G_CALLBACK (ecep_schedule_editor_times_changed_cb
), page_schedule
);
526 g_signal_connect (comp_editor
, "notify::target-client",
527 G_CALLBACK (ecep_schedule_editor_target_client_notify_cb
), page_schedule
);
530 g_clear_object (&comp_editor
);
532 g_signal_connect (page_schedule
->priv
->selector
, "changed",
533 G_CALLBACK (ecep_schedule_selector_changed_cb
), page_schedule
);
535 ecep_schedule_setup_ui (page_schedule
);
539 e_comp_editor_page_schedule_dispose (GObject
*object
)
541 ECompEditorPageSchedule
*page_schedule
;
542 ECompEditor
*comp_editor
;
544 page_schedule
= E_COMP_EDITOR_PAGE_SCHEDULE (object
);
546 comp_editor
= e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_schedule
));
548 g_signal_handlers_disconnect_by_func (comp_editor
,
549 G_CALLBACK (ecep_schedule_editor_times_changed_cb
), page_schedule
);
550 g_clear_object (&comp_editor
);
553 g_clear_object (&page_schedule
->priv
->store
);
555 G_OBJECT_CLASS (e_comp_editor_page_schedule_parent_class
)->dispose (object
);
559 e_comp_editor_page_schedule_init (ECompEditorPageSchedule
*page_schedule
)
561 page_schedule
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (page_schedule
,
562 E_TYPE_COMP_EDITOR_PAGE_SCHEDULE
,
563 ECompEditorPageSchedulePrivate
);
567 e_comp_editor_page_schedule_class_init (ECompEditorPageScheduleClass
*klass
)
569 ECompEditorPageClass
*page_class
;
570 GObjectClass
*object_class
;
572 g_type_class_add_private (klass
, sizeof (ECompEditorPageSchedulePrivate
));
574 page_class
= E_COMP_EDITOR_PAGE_CLASS (klass
);
575 page_class
->sensitize_widgets
= ecep_schedule_sensitize_widgets
;
576 page_class
->fill_widgets
= ecep_schedule_fill_widgets
;
577 page_class
->fill_component
= ecep_schedule_fill_component
;
579 object_class
= G_OBJECT_CLASS (klass
);
580 object_class
->set_property
= e_comp_editor_page_schedule_set_property
;
581 object_class
->get_property
= e_comp_editor_page_schedule_get_property
;
582 object_class
->constructed
= e_comp_editor_page_schedule_constructed
;
583 object_class
->dispose
= e_comp_editor_page_schedule_dispose
;
585 g_object_class_install_property (
588 g_param_spec_object (
592 E_TYPE_MEETING_STORE
,
594 G_PARAM_CONSTRUCT_ONLY
|
595 G_PARAM_STATIC_STRINGS
));
599 e_comp_editor_page_schedule_new (ECompEditor
*editor
,
600 EMeetingStore
*meeting_store
)
602 g_return_val_if_fail (E_IS_COMP_EDITOR (editor
), NULL
);
604 return g_object_new (E_TYPE_COMP_EDITOR_PAGE_SCHEDULE
,
606 "store", meeting_store
,
611 e_comp_editor_page_schedule_get_store (ECompEditorPageSchedule
*page_schedule
)
613 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
), NULL
);
615 return page_schedule
->priv
->store
;
618 EMeetingTimeSelector
*
619 e_comp_editor_page_schedule_get_time_selector (ECompEditorPageSchedule
*page_schedule
)
621 g_return_val_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule
), NULL
);
623 return page_schedule
->priv
->selector
;