Files
evolution/modules/calendar/e-cal-shell-content.c
T
Milan Crha 8752647eca Make Calendar, Memos and Tasks views non-UI-blocking
The Calendar, Memos and Tasks views use to do D-Bus calls to
the backends on the main (UI) thread, which could result in UI
freezes, until the operation was done on the backend (and server)
side. This commit fixes that by invoking the operations in
a dedicated thread. It has few additional advantages too:
- operations can be cancelled
- proper error reporting to a user
- less code duplication between the views for common operations

There had been fixed some performance issues when selecting/unselecting
sources in the source selector as well.
2014-10-06 12:33:03 +02:00

2175 lines
70 KiB
C

/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
* Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <math.h>
#include <glib/gi18n-lib.h>
#include "calendar/gui/calendar-config.h"
#include "calendar/gui/calendar-view.h"
#include "calendar/gui/comp-util.h"
#include "calendar/gui/e-cal-list-view.h"
#include "calendar/gui/e-cal-model-calendar.h"
#include "calendar/gui/e-cal-model-memos.h"
#include "calendar/gui/e-cal-model-tasks.h"
#include "calendar/gui/e-calendar-view.h"
#include "calendar/gui/e-day-view.h"
#include "calendar/gui/e-month-view.h"
#include "calendar/gui/e-week-view.h"
#include "calendar/gui/tag-calendar.h"
#include "e-cal-base-shell-sidebar.h"
#include "e-cal-shell-view-private.h"
#include "e-cal-shell-content.h"
#define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate))
struct _ECalShellContentPrivate {
GtkWidget *hpaned;
GtkWidget *vpaned;
GtkWidget *calendar_notebook;
GtkWidget *task_table;
ECalModel *task_model;
ECalDataModel *task_data_model;
GtkWidget *memo_table;
ECalModel *memo_model;
ECalDataModel *memo_data_model;
ETagCalendar *tag_calendar;
gulong datepicker_selection_changed_id;
gulong datepicker_range_moved_id;
ECalViewKind current_view;
ECalendarView *views[E_CAL_VIEW_KIND_LAST];
GDate view_start, view_end;
guint32 view_start_range_day_offset;
GDate last_range_start; /* because "date-range-changed" can be emit with no real change */
gulong current_view_id_changed_id;
};
enum {
PROP_0,
PROP_CALENDAR_NOTEBOOK,
PROP_MEMO_TABLE,
PROP_TASK_TABLE,
PROP_CURRENT_VIEW_ID,
PROP_CURRENT_VIEW
};
/* Used to indicate who has the focus within the calendar view. */
typedef enum {
FOCUS_CALENDAR_NOTEBOOK,
FOCUS_MEMO_TABLE,
FOCUS_TASK_TABLE,
FOCUS_OTHER
} FocusLocation;
G_DEFINE_DYNAMIC_TYPE (ECalShellContent, e_cal_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT)
static time_t
convert_to_local_zone (time_t tm,
icaltimezone *from_zone)
{
struct icaltimetype tt;
tt = icaltime_from_timet_with_zone (tm, FALSE, from_zone);
return icaltime_as_timet (tt);
}
static void
cal_shell_content_update_model_and_current_view_times (ECalShellContent *cal_shell_content,
ECalModel *model,
ECalendarItem *calitem,
time_t view_start_tt,
time_t view_end_tt,
const GDate *view_start,
const GDate *view_end)
{
ECalendarView *current_view;
gint syy, smm, sdd, eyy, emm, edd;
time_t visible_range_start, visible_range_end;
gboolean filters_updated = FALSE;
icaltimezone *zone;
gchar *cal_filter;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (E_IS_CAL_MODEL (model));
g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
current_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
g_return_if_fail (current_view != NULL);
zone = e_cal_model_get_timezone (model);
cal_filter = e_cal_data_model_dup_filter (e_cal_model_get_data_model (model));
g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
visible_range_start = view_start_tt;
visible_range_end = view_end_tt;
e_calendar_view_precalc_visible_time_range (current_view, view_start_tt, view_end_tt, &visible_range_start, &visible_range_end);
if (view_start_tt != visible_range_start || view_end_tt != visible_range_end) {
time_t cmp_range_start = convert_to_local_zone (visible_range_start, zone);
time_t cmp_range_end = convert_to_local_zone (visible_range_end, zone);
if (view_start_tt != cmp_range_start ||
view_end_tt != cmp_range_end - 1) {
/* Calendar views update their inner time range during e_cal_model_set_time_range() call,
while they can change it if needed (like a clamp of a week view with a week start day
not being Monday */
GDate new_view_start, new_view_end;
/* Midnight means the next day, which is not desired here */
cmp_range_end--;
visible_range_end--;
/* These times are in the correct zone already */
time_to_gdate_with_zone (&new_view_start, cmp_range_start, NULL);
time_to_gdate_with_zone (&new_view_end, cmp_range_end, NULL);
e_calendar_item_set_selection (calitem, &new_view_start, &new_view_end);
e_cal_shell_content_update_filters (cal_shell_content, cal_filter, visible_range_start, visible_range_end);
e_calendar_view_set_selected_time_range (current_view, cmp_range_start, cmp_range_start);
filters_updated = TRUE;
view_start_tt = cmp_range_start;
view_end_tt = cmp_range_end;
}
}
if (!filters_updated) {
e_calendar_item_set_selection (calitem, view_start, view_end);
e_cal_shell_content_update_filters (cal_shell_content, cal_filter, view_start_tt, view_end_tt);
e_calendar_view_set_selected_time_range (current_view, view_start_tt, view_start_tt);
}
gtk_widget_queue_draw (GTK_WIDGET (current_view));
g_free (cal_filter);
g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
if (e_calendar_item_get_date_range (calitem, &syy, &smm, &sdd, &eyy, &emm, &edd)) {
GDate range_start;
g_date_set_dmy (&range_start, sdd, smm + 1, syy);
cal_shell_content->priv->view_start_range_day_offset =
g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian (&range_start);
}
}
static void
e_cal_shell_content_change_view (ECalShellContent *cal_shell_content,
ECalViewKind to_view,
const GDate *view_start,
const GDate *view_end,
gboolean force_change)
{
EShellSidebar *shell_sidebar;
EShellView *shell_view;
ECalendar *calendar;
ECalModel *model;
icaltimezone *zone;
time_t view_start_tt, view_end_tt;
gboolean view_changed = FALSE;
gint selected_days;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (to_view >= E_CAL_VIEW_KIND_DAY && to_view < E_CAL_VIEW_KIND_LAST);
g_return_if_fail (view_start != NULL);
g_return_if_fail (g_date_valid (view_start));
g_return_if_fail (view_end != NULL);
g_return_if_fail (g_date_valid (view_end));
shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
g_return_if_fail (E_IS_CALENDAR (calendar));
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
zone = e_cal_model_get_timezone (model);
view_start_tt = cal_comp_gdate_to_timet (view_start, zone);
view_end_tt = cal_comp_gdate_to_timet (view_end, zone);
if (to_view != cal_shell_content->priv->current_view) {
g_signal_handler_block (cal_shell_content, cal_shell_content->priv->current_view_id_changed_id);
e_cal_shell_content_set_current_view_id (cal_shell_content, to_view);
g_signal_handler_unblock (cal_shell_content, cal_shell_content->priv->current_view_id_changed_id);
view_changed = TRUE;
}
selected_days = g_date_get_julian (view_end) - g_date_get_julian (view_start) + 1;
if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY) {
EDayView *day_view;
day_view = E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY]);
e_day_view_set_days_shown (day_view, selected_days);
} else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH) {
EWeekView *month_view;
month_view = E_WEEK_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH]);
e_week_view_set_weeks_shown (month_view, selected_days / 7);
}
if (!force_change &&
g_date_valid (&cal_shell_content->priv->view_start) &&
g_date_valid (&cal_shell_content->priv->view_end) &&
g_date_compare (&cal_shell_content->priv->view_start, view_start) == 0 &&
g_date_compare (&cal_shell_content->priv->view_end, view_end) == 0) {
ECalendarItem *calitem = calendar->calitem;
if (view_changed)
cal_shell_content_update_model_and_current_view_times (
cal_shell_content, model, calendar->calitem, view_start_tt, view_end_tt, view_start, view_end);
g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
e_calendar_item_set_selection (calitem, view_start, view_end);
g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
return;
}
cal_shell_content->priv->view_start = *view_start;
cal_shell_content->priv->view_end = *view_end;
cal_shell_content_update_model_and_current_view_times (
cal_shell_content, model, calendar->calitem, view_start_tt, view_end_tt, view_start, view_end);
}
static void
cal_shell_content_clamp_for_whole_weeks (GDateWeekday week_start_day,
GDate *sel_start,
GDate *sel_end)
{
GDateWeekday wday;
guint32 julian_start, julian_end;
g_return_if_fail (sel_start != NULL);
g_return_if_fail (sel_end != NULL);
wday = g_date_get_weekday (sel_start);
if (week_start_day > wday) {
g_date_subtract_days (sel_start, wday);
wday = g_date_get_weekday (sel_start);
}
if (week_start_day < wday)
g_date_subtract_days (sel_start, wday - week_start_day);
julian_start = g_date_get_julian (sel_start);
julian_end = g_date_get_julian (sel_end);
if (((julian_end - julian_start + 1) % 7) != 0)
g_date_add_days (sel_end, 7 - ((julian_end - julian_start + 1) % 7));
julian_end = g_date_get_julian (sel_end);
/* Can show only up to 6 weeks */
if ((julian_end - julian_start + 1) / 7 > 6) {
*sel_end = *sel_start;
g_date_add_days (sel_end, (7 * 6) - 1);
}
if (g_date_compare (sel_start, sel_end) == 0)
g_date_add_days (sel_end, 6);
}
static gboolean
cal_shell_content_weekday_within (GDateWeekday start_wday,
GDateWeekday end_wday,
GDateWeekday test_wday)
{
gint ii;
if (start_wday <= end_wday)
return start_wday <= test_wday && test_wday <= end_wday;
for (ii = 0; ii < 7; ii++) {
if (start_wday == test_wday)
return TRUE;
if (start_wday == end_wday)
break;
start_wday = e_weekday_get_next (start_wday);
}
return FALSE;
}
static void
cal_shell_content_datepicker_selection_changed_cb (ECalendarItem *calitem,
ECalShellContent *cal_shell_content)
{
GDate sel_start, sel_end;
guint32 selected_days, start_julian, end_julian;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
g_date_clear (&sel_start, 1);
g_date_clear (&sel_end, 1);
e_calendar_item_get_selection (calitem, &sel_start, &sel_end);
start_julian = g_date_get_julian (&sel_start);
end_julian = g_date_get_julian (&sel_end);
g_return_if_fail (start_julian <= end_julian);
if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) == 0 &&
g_date_compare (&cal_shell_content->priv->view_end, &sel_end) == 0) {
/* No change in the selection range */
return;
}
selected_days = end_julian - start_julian + 1;
if (selected_days == 1) {
GDateWeekday sel_start_wday, sel_end_wday, cur_start_wday, cur_end_wday;
/* Clicked inside currently selected view range; do not do anything,
just make sure the days are selected again */
if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) <= 0 &&
g_date_compare (&sel_start, &cal_shell_content->priv->view_end) <= 0) {
sel_start = cal_shell_content->priv->view_start;
sel_end = cal_shell_content->priv->view_end;
e_calendar_item_set_selection (calitem, &sel_start, &sel_end);
return;
}
sel_start_wday = g_date_get_weekday (&sel_start);
sel_end_wday = g_date_get_weekday (&sel_end);
cur_start_wday = g_date_get_weekday (&cal_shell_content->priv->view_start);
cur_end_wday = g_date_get_weekday (&cal_shell_content->priv->view_end);
if ((cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK ||
(cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY &&
e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) != 1)) &&
cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday)) {
if (cur_start_wday < sel_start_wday) {
g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday);
} else if (cur_start_wday > sel_start_wday) {
g_date_subtract_days (&sel_start, 7 - (cur_start_wday - sel_start_wday));
}
sel_end = sel_start;
if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY)
g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) - 1);
else
g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1);
e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE);
} else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WEEK &&
cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday) &&
cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_end_wday)) {
if (cur_start_wday < sel_start_wday)
g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday);
sel_end = sel_start;
cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end);
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, &sel_end, FALSE);
} else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH ||
cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) {
/* whole month */
g_date_set_day (&sel_start, 1);
sel_end = sel_start;
g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), g_date_get_year (&sel_start)) - 1);
cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end);
e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE);
} else {
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE);
}
} else if (selected_days < 7) {
GDateWeekday first_work_wday;
first_work_wday = e_cal_model_get_work_day_first (e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)));
if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK &&
first_work_wday == g_date_get_weekday (&sel_start) &&
selected_days == e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])))
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WORKWEEK, &sel_start, &sel_end, FALSE);
else
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE);
} else if (selected_days == 7) {
GDateWeekday sel_start_wday;
sel_start_wday = g_date_get_weekday (&sel_start);
if (sel_start_wday == calitem->week_start_day &&
cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY &&
e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) == 7) {
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE);
} else {
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, &sel_end, FALSE);
}
} else {
if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) {
/* whole month */
g_date_set_day (&sel_start, 1);
sel_end = sel_start;
g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), g_date_get_year (&sel_start)));
cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end);
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_LIST, &sel_start, &sel_end, FALSE);
} else {
cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end);
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_MONTH, &sel_start, &sel_end, FALSE);
}
}
}
static void
cal_shell_content_datepicker_range_moved_cb (ECalendarItem *calitem,
ECalShellContent *cal_shell_content)
{
gint start_year, start_month, start_day, end_year, end_month, end_day;
GDate sel_start_date, sel_end_date, range_start_date;
g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
if (!e_calendar_item_get_date_range (calitem, &start_year, &start_month, &start_day, &end_year, &end_month, &end_day))
return;
g_date_set_dmy (&range_start_date, start_day, start_month + 1, start_year);
if (g_date_valid (&cal_shell_content->priv->last_range_start) &&
g_date_compare (&cal_shell_content->priv->last_range_start, &range_start_date) == 0) {
return;
}
cal_shell_content->priv->last_range_start = range_start_date;
g_date_clear (&sel_start_date, 1);
g_date_clear (&sel_end_date, 1);
if (cal_shell_content->priv->view_start_range_day_offset == (guint32) -1) {
sel_start_date = cal_shell_content->priv->view_start;
sel_end_date = cal_shell_content->priv->view_end;
cal_shell_content->priv->view_start_range_day_offset =
g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian (&range_start_date);
} else {
gint view_days;
view_days = g_date_get_julian (&cal_shell_content->priv->view_end) - g_date_get_julian (&cal_shell_content->priv->view_start);
sel_start_date = range_start_date;
g_date_add_days (&sel_start_date, cal_shell_content->priv->view_start_range_day_offset);
sel_end_date = sel_start_date;
g_date_add_days (&sel_end_date, view_days);
}
g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
e_calendar_item_set_selection (calitem, &sel_start_date, &sel_end_date);
g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
}
static gboolean
cal_shell_content_datepicker_button_press_cb (ECalendar *calendar,
GdkEvent *event,
ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), FALSE);
if (!event)
return FALSE;
if (event->type == GDK_2BUTTON_PRESS) {
ECalendarItem *calitem = calendar->calitem;
GDate sel_start, sel_end;
g_date_clear (&sel_start, 1);
g_date_clear (&sel_end, 1);
e_calendar_item_get_selection (calitem, &sel_start, &sel_end);
/* Switch to a day view on a double-click */
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_start, FALSE);
}
return FALSE;
}
static void
cal_shell_content_current_view_id_changed_cb (ECalShellContent *cal_shell_content)
{
GDate sel_start, sel_end;
GDateWeekday work_day_first, week_start_day;
ECalModel *model;
gint ii;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
work_day_first = e_cal_model_get_work_day_first (model);
week_start_day = e_cal_model_get_week_start_day (model);
sel_start = cal_shell_content->priv->view_start;
sel_end = cal_shell_content->priv->view_end;
switch (cal_shell_content->priv->current_view) {
case E_CAL_VIEW_KIND_DAY:
/* Left the start & end being the current view start */
sel_end = sel_start;
break;
case E_CAL_VIEW_KIND_WORKWEEK:
cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
ii = 0;
while (g_date_get_weekday (&sel_start) != work_day_first && ii < 7) {
g_date_add_days (&sel_start, 1);
ii++;
}
sel_end = sel_start;
g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1);
break;
case E_CAL_VIEW_KIND_WEEK:
sel_end = sel_start;
cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
break;
case E_CAL_VIEW_KIND_MONTH:
case E_CAL_VIEW_KIND_LIST:
if (g_date_get_day (&sel_start) != 1 &&
(g_date_get_julian (&sel_end) - g_date_get_julian (&sel_start) + 1) / 7 >= 3 &&
g_date_get_month (&sel_start) != g_date_get_month (&sel_end)) {
g_date_set_day (&sel_start, 1);
g_date_add_months (&sel_start, 1);
} else {
g_date_set_day (&sel_start, 1);
}
sel_end = sel_start;
g_date_add_months (&sel_end, 1);
g_date_subtract_days (&sel_end, 1);
cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
break;
default:
g_warn_if_reached ();
return;
}
/* Ensure a change */
e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, TRUE);
}
static void
cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
GalView *gal_view)
{
ECalViewKind view_kind;
GType gal_view_type;
gal_view_type = G_OBJECT_TYPE (gal_view);
if (gal_view_type == GAL_TYPE_VIEW_ETABLE) {
ECalendarView *calendar_view;
view_kind = E_CAL_VIEW_KIND_LIST;
calendar_view = cal_shell_content->priv->views[view_kind];
gal_view_etable_attach_table (
GAL_VIEW_ETABLE (gal_view),
E_CAL_LIST_VIEW (calendar_view)->table);
} else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_DAY) {
view_kind = E_CAL_VIEW_KIND_DAY;
} else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WORK_WEEK) {
view_kind = E_CAL_VIEW_KIND_WORKWEEK;
} else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WEEK) {
view_kind = E_CAL_VIEW_KIND_WEEK;
} else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_MONTH) {
view_kind = E_CAL_VIEW_KIND_MONTH;
} else {
g_return_if_reached ();
}
e_cal_shell_content_set_current_view_id (cal_shell_content, view_kind);
}
static void
cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
{
EShellContent *shell_content;
EShellView *shell_view;
GSettings *settings;
GtkWidget *paned;
const gchar *key;
const gchar *view_id;
settings = g_settings_new ("org.gnome.evolution.calendar");
paned = cal_shell_content->priv->hpaned;
shell_content = E_SHELL_CONTENT (cal_shell_content);
shell_view = e_shell_content_get_shell_view (shell_content);
view_id = e_shell_view_get_view_id (shell_view);
if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
key = "month-hpane-position";
else
key = "hpane-position";
g_settings_unbind (paned, "hposition");
g_settings_bind (
settings, key,
paned, "hposition",
G_SETTINGS_BIND_DEFAULT);
g_object_unref (settings);
}
static void
cal_shell_content_is_editing_changed_cb (gpointer cal_view_tasks_memos_table,
GParamSpec *param,
EShellView *shell_view)
{
g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
e_shell_view_update_actions (shell_view);
}
static gchar *
cal_shell_content_get_pad_state_filename (EShellContent *shell_content,
ETable *table)
{
EShellBackend *shell_backend;
EShellView *shell_view;
const gchar *config_dir, *nick = NULL;
g_return_val_if_fail (shell_content != NULL, NULL);
g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
g_return_val_if_fail (table != NULL, NULL);
g_return_val_if_fail (E_IS_TABLE (table), NULL);
if (E_IS_TASK_TABLE (table))
nick = "TaskPad";
else if (E_IS_MEMO_TABLE (table))
nick = "MemoPad";
g_return_val_if_fail (nick != NULL, NULL);
shell_view = e_shell_content_get_shell_view (shell_content);
shell_backend = e_shell_view_get_shell_backend (shell_view);
config_dir = e_shell_backend_get_config_dir (shell_backend);
return g_build_filename (config_dir, nick, NULL);
}
static void
cal_shell_content_save_table_state (EShellContent *shell_content,
ETable *table)
{
gchar *filename;
filename = cal_shell_content_get_pad_state_filename (
shell_content, table);
g_return_if_fail (filename != NULL);
e_table_save_state (table, filename);
g_free (filename);
}
static void
cal_shell_content_load_table_state (EShellContent *shell_content,
ETable *table)
{
gchar *filename;
filename = cal_shell_content_get_pad_state_filename (shell_content, table);
g_return_if_fail (filename != NULL);
e_table_load_state (table, filename);
g_free (filename);
}
static icalproperty *
cal_shell_content_get_attendee_prop (icalcomponent *icalcomp,
const gchar *address)
{
icalproperty *prop;
if (address == NULL || *address == '\0')
return NULL;
prop = icalcomponent_get_first_property (
icalcomp, ICAL_ATTENDEE_PROPERTY);
while (prop != NULL) {
const gchar *attendee;
attendee = icalproperty_get_attendee (prop);
if (g_str_equal (itip_strip_mailto (attendee), address))
return prop;
prop = icalcomponent_get_next_property (
icalcomp, ICAL_ATTENDEE_PROPERTY);
}
return NULL;
}
static gboolean
cal_shell_content_icalcomp_is_delegated (icalcomponent *icalcomp,
const gchar *user_email)
{
icalproperty *prop;
icalparameter *param;
const gchar *delto = NULL;
gboolean is_delegated = FALSE;
prop = cal_shell_content_get_attendee_prop (icalcomp, user_email);
if (prop != NULL) {
param = icalproperty_get_first_parameter (
prop, ICAL_DELEGATEDTO_PARAMETER);
if (param != NULL) {
delto = icalparameter_get_delegatedto (param);
delto = itip_strip_mailto (delto);
}
} else
return FALSE;
prop = cal_shell_content_get_attendee_prop (icalcomp, delto);
if (prop != NULL) {
const gchar *delfrom = NULL;
icalparameter_partstat status = ICAL_PARTSTAT_NONE;
param = icalproperty_get_first_parameter (
prop, ICAL_DELEGATEDFROM_PARAMETER);
if (param != NULL) {
delfrom = icalparameter_get_delegatedfrom (param);
delfrom = itip_strip_mailto (delfrom);
}
param = icalproperty_get_first_parameter (
prop, ICAL_PARTSTAT_PARAMETER);
if (param != NULL)
status = icalparameter_get_partstat (param);
is_delegated =
(status != ICAL_PARTSTAT_DECLINED) &&
(g_strcmp0 (delfrom, user_email) == 0);
}
return is_delegated;
}
static guint32
cal_shell_content_check_state (EShellContent *shell_content)
{
EShell *shell;
EShellView *shell_view;
EShellBackend *shell_backend;
ESourceRegistry *registry;
ECalShellContent *cal_shell_content;
ECalendarView *calendar_view;
gboolean selection_is_editable = FALSE;
gboolean selection_is_instance = FALSE;
gboolean selection_is_meeting = FALSE;
gboolean selection_is_organizer = FALSE;
gboolean selection_is_recurring = FALSE;
gboolean selection_can_delegate = FALSE;
guint32 state = 0;
GList *selected;
GList *link;
guint n_selected;
cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
shell_view = e_shell_content_get_shell_view (shell_content);
shell_backend = e_shell_view_get_shell_backend (shell_view);
shell = e_shell_backend_get_shell (shell_backend);
registry = e_shell_get_registry (shell);
calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
selected = e_calendar_view_get_selected_events (calendar_view);
n_selected = g_list_length (selected);
/* If we have a selection, assume it's
* editable until we learn otherwise. */
if (n_selected > 0)
selection_is_editable = TRUE;
for (link = selected; link != NULL; link = g_list_next (link)) {
ECalendarViewEvent *event = link->data;
ECalClient *client;
ECalComponent *comp;
gchar *user_email;
icalcomponent *icalcomp;
const gchar *capability;
gboolean cap_delegate_supported;
gboolean cap_delegate_to_many;
gboolean icalcomp_is_delegated;
gboolean read_only;
if (!is_comp_data_valid (event))
continue;
client = event->comp_data->client;
icalcomp = event->comp_data->icalcomp;
read_only = e_client_is_readonly (E_CLIENT (client));
selection_is_editable &= !read_only;
selection_is_instance |=
e_cal_util_component_is_instance (icalcomp);
selection_is_meeting =
(n_selected == 1) &&
e_cal_util_component_has_attendee (icalcomp);
selection_is_recurring |=
e_cal_util_component_is_instance (icalcomp) ||
e_cal_util_component_has_recurrences (icalcomp);
/* XXX The rest of this is rather expensive and
* only applies if a single event is selected,
* so continue with the loop iteration if the
* rest of this is not applicable. */
if (n_selected > 1)
continue;
/* XXX This probably belongs in comp-util.c. */
comp = e_cal_component_new ();
e_cal_component_set_icalcomponent (
comp, icalcomponent_new_clone (icalcomp));
user_email = itip_get_comp_attendee (
registry, comp, client);
selection_is_organizer =
e_cal_util_component_has_organizer (icalcomp) &&
itip_organizer_is_user (registry, comp, client);
capability = CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED;
cap_delegate_supported =
e_client_check_capability (
E_CLIENT (client), capability);
capability = CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY;
cap_delegate_to_many =
e_client_check_capability (
E_CLIENT (client), capability);
icalcomp_is_delegated =
(user_email != NULL) &&
cal_shell_content_icalcomp_is_delegated (
icalcomp, user_email);
selection_can_delegate =
cap_delegate_supported &&
(cap_delegate_to_many ||
(!selection_is_organizer &&
!icalcomp_is_delegated));
g_free (user_email);
g_object_unref (comp);
}
g_list_free (selected);
if (n_selected == 1)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE;
if (n_selected > 1)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE;
if (selection_is_editable)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE;
if (selection_is_instance)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE;
if (selection_is_meeting)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING;
if (selection_is_organizer)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_ORGANIZER;
if (selection_is_recurring)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING;
if (selection_can_delegate)
state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE;
return state;
}
static void
cal_shell_content_focus_search_results (EShellContent *shell_content)
{
ECalendarView *calendar_view;
calendar_view = e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (shell_content));
gtk_widget_grab_focus (GTK_WIDGET (calendar_view));
}
static time_t
cal_shell_content_get_default_time (ECalModel *model,
gpointer user_data)
{
ECalShellContent *cal_shell_content = user_data;
g_return_val_if_fail (model != NULL, 0);
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), 0);
return cal_comp_gdate_to_timet (&cal_shell_content->priv->view_start,
e_cal_model_get_timezone (model));
}
static void
update_adjustment (ECalShellContent *cal_shell_content,
GtkAdjustment *adjustment,
EWeekView *week_view,
gboolean move_by_week)
{
GDate start_date, end_date;
GDate first_day_shown;
ECalModel *model;
gint week_offset;
struct icaltimetype start_tt = icaltime_null_time ();
time_t lower;
guint32 old_first_day_julian, new_first_day_julian;
icaltimezone *timezone;
gdouble value;
e_week_view_get_first_day_shown (week_view, &first_day_shown);
/* If we don't have a valid date set yet, just return. */
if (!g_date_valid (&first_day_shown))
return;
value = gtk_adjustment_get_value (adjustment);
/* Determine the first date shown. */
start_date = week_view->base_date;
week_offset = floor (value + 0.5);
g_date_add_days (&start_date, week_offset * 7);
/* Convert the old & new first days shown to julian values. */
old_first_day_julian = g_date_get_julian (&first_day_shown);
new_first_day_julian = g_date_get_julian (&start_date);
/* If we are already showing the date, just return. */
if (old_first_day_julian == new_first_day_julian)
return;
/* Convert it to a time_t. */
start_tt.year = g_date_get_year (&start_date);
start_tt.month = g_date_get_month (&start_date);
start_tt.day = g_date_get_day (&start_date);
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
timezone = e_cal_model_get_timezone (model);
lower = icaltime_as_timet_with_zone (start_tt, timezone);
end_date = start_date;
if (move_by_week) {
g_date_add_days (&end_date, 7 - 1);
} else {
g_date_add_days (&end_date, 7 * e_week_view_get_weeks_shown (week_view) - 1);
}
e_week_view_set_update_base_date (week_view, FALSE);
e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &start_date, &end_date, FALSE);
e_calendar_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), lower, lower);
e_week_view_set_update_base_date (week_view, TRUE);
}
static void
week_view_adjustment_changed_cb (GtkAdjustment *adjustment,
ECalShellContent *cal_shell_content)
{
ECalendarView *view;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK];
update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), TRUE);
}
static void
month_view_adjustment_changed_cb (GtkAdjustment *adjustment,
ECalShellContent *cal_shell_content)
{
ECalendarView *view;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH];
update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), FALSE);
}
static void
cal_shell_content_notify_work_day_cb (ECalModel *model,
GParamSpec *param,
ECalShellContent *cal_shell_content)
{
GDateWeekday work_day_first, work_day_last;
g_return_if_fail (E_IS_CAL_MODEL (model));
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
if (cal_shell_content->priv->current_view != E_CAL_VIEW_KIND_WORKWEEK)
return;
work_day_first = e_cal_model_get_work_day_first (model);
work_day_last = e_cal_model_get_work_day_last (model);
if (work_day_first == g_date_get_weekday (&cal_shell_content->priv->view_start) &&
work_day_last == g_date_get_weekday (&cal_shell_content->priv->view_end))
return;
/* This makes sure that the selection in the datepicker corresponds
to the time range used in the Work Week view */
cal_shell_content_current_view_id_changed_cb (cal_shell_content);
}
static void
cal_shell_content_notify_week_start_day_cb (ECalModel *model,
GParamSpec *param,
ECalShellContent *cal_shell_content)
{
g_return_if_fail (E_IS_CAL_MODEL (model));
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
/* This makes sure that the selection in the datepicker corresponds
to the time range used in the current view */
cal_shell_content_current_view_id_changed_cb (cal_shell_content);
}
static void
cal_shell_content_move_view_range_cb (ECalendarView *cal_view,
ECalendarViewMoveType move_type,
gint64 exact_date,
ECalShellContent *cal_shell_content)
{
g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
if (!cal_view->in_focus)
return;
e_cal_shell_content_move_view_range (cal_shell_content, move_type, (time_t) exact_date);
}
static void
cal_shell_content_foreign_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
ECalClient *client,
ECalModel *model)
{
g_return_if_fail (E_IS_CAL_CLIENT (client));
g_return_if_fail (E_IS_CAL_MODEL (model));
e_cal_data_model_add_client (e_cal_model_get_data_model (model), client);
}
static void
cal_shell_content_foreign_client_closed_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
ESource *source,
ECalModel *model)
{
g_return_if_fail (E_IS_SOURCE (source));
g_return_if_fail (E_IS_CAL_MODEL (model));
e_cal_data_model_remove_client (e_cal_model_get_data_model (model), e_source_get_uid (source));
}
static void
cal_shell_content_setup_foreign_sources (EShellView *foreign_view,
ECalModel *model)
{
EShellSidebar *foreign_sidebar;
EShellContent *foreign_content;
ECalModel *foreign_model;
g_return_if_fail (E_IS_SHELL_VIEW (foreign_view));
g_return_if_fail (E_IS_CAL_MODEL (model));
foreign_sidebar = e_shell_view_get_shell_sidebar (foreign_view);
g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar));
g_signal_connect_object (foreign_sidebar, "client-opened",
G_CALLBACK (cal_shell_content_foreign_client_opened_cb), model, 0);
g_signal_connect_object (foreign_sidebar, "client-closed",
G_CALLBACK (cal_shell_content_foreign_client_closed_cb), model, 0);
foreign_content = e_shell_view_get_shell_content (foreign_view);
foreign_model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (foreign_content));
g_object_bind_property (
foreign_model, "default-source-uid",
model, "default-source-uid",
G_BINDING_SYNC_CREATE);
g_signal_connect_object (model, "row-appended",
G_CALLBACK (e_cal_base_shell_view_model_row_appended), foreign_view, G_CONNECT_SWAPPED);
/* This makes sure that the local models for memos and tasks
in the calendar view get populated with the same sources
as those in the respective views. */
e_cal_base_shell_sidebar_ensure_sources_open (E_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar));
}
static void
cal_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content)
{
ECalShellContent *cal_shell_content;
EShellView *shell_view;
EShellView *foreign_view;
EShellWindow *shell_window;
EShellSidebar *shell_sidebar;
GalViewInstance *view_instance;
ECalendar *calendar;
ECalModel *model;
ECalDataModel *data_model;
GDate date;
time_t today;
cal_shell_content = E_CAL_SHELL_CONTENT (cal_base_shell_content);
cal_shell_content->priv->current_view = E_CAL_VIEW_KIND_DAY;
today = time (NULL);
g_date_clear (&date, 1);
g_date_set_time_t (&date, today);
shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
shell_window = e_shell_view_get_shell_window (shell_view);
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
g_return_if_fail (E_IS_CALENDAR (calendar));
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
e_calendar_item_set_selection (calendar->calitem, &date, &date);
e_cal_model_set_time_range (model, today, today);
/* Show everything known by default in the task and memo pads */
e_cal_model_set_time_range (cal_shell_content->priv->memo_model, 0, 0);
e_cal_model_set_time_range (cal_shell_content->priv->task_model, 0, 0);
cal_shell_content->priv->datepicker_selection_changed_id =
g_signal_connect (calendar->calitem, "selection-changed",
G_CALLBACK (cal_shell_content_datepicker_selection_changed_cb), cal_shell_content);
cal_shell_content->priv->datepicker_range_moved_id =
g_signal_connect (calendar->calitem, "date-range-moved",
G_CALLBACK (cal_shell_content_datepicker_range_moved_cb), cal_shell_content);
g_signal_connect_after (calendar, "button-press-event",
G_CALLBACK (cal_shell_content_datepicker_button_press_cb), cal_shell_content);
data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
cal_shell_content->priv->tag_calendar = e_tag_calendar_new (calendar);
e_tag_calendar_subscribe (cal_shell_content->priv->tag_calendar, data_model);
/* Intentionally not using e_signal_connect_notify() here, no need to filter
out "false" notifications, it's dealt with them in another way */
cal_shell_content->priv->current_view_id_changed_id = g_signal_connect (
cal_shell_content, "notify::current-view-id",
G_CALLBACK (cal_shell_content_current_view_id_changed_cb), NULL);
/* List of selected Task/Memo sources is taken from respective views,
which are loaded if necessary. */
foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
cal_shell_content_setup_foreign_sources (foreign_view,
cal_shell_content->priv->memo_model);
foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
cal_shell_content_setup_foreign_sources (foreign_view,
cal_shell_content->priv->task_model);
/* Finally load the view instance */
view_instance = e_shell_view_get_view_instance (shell_view);
gal_view_instance_load (view_instance);
/* Keep the toolbar view buttons in sync with the calendar. */
g_object_bind_property (
cal_shell_content, "current-view-id",
ACTION (CALENDAR_VIEW_DAY), "current-value",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
e_signal_connect_notify (
model, "notify::work-day-monday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-tuesday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-wednesday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-thursday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-friday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-saturday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::work-day-sunday",
G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
e_signal_connect_notify (
model, "notify::week-start-day",
G_CALLBACK (cal_shell_content_notify_week_start_day_cb), cal_shell_content);
}
static void
e_cal_shell_content_create_calendar_views (ECalShellContent *cal_shell_content)
{
EShellView *shell_view;
ECalModel *model;
ECalendarView *calendar_view;
GtkAdjustment *adjustment;
time_t today;
gint ii;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (cal_shell_content->priv->calendar_notebook != NULL);
g_return_if_fail (cal_shell_content->priv->views[0] == NULL);
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
/* Day View */
calendar_view = e_day_view_new (model);
cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY] = calendar_view;
g_object_ref_sink (calendar_view);
/* Work Week View */
calendar_view = e_day_view_new (model);
e_day_view_set_work_week_view (E_DAY_VIEW (calendar_view), TRUE);
e_day_view_set_days_shown (E_DAY_VIEW (calendar_view), 5);
cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK] = calendar_view;
g_object_ref_sink (calendar_view);
/* Week View */
calendar_view = e_week_view_new (model);
cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK] = calendar_view;
g_object_ref_sink (calendar_view);
adjustment = gtk_range_get_adjustment (
GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
g_signal_connect (
adjustment, "value-changed",
G_CALLBACK (week_view_adjustment_changed_cb), cal_shell_content);
/* Month View */
calendar_view = e_month_view_new (model);
e_week_view_set_multi_week_view (E_WEEK_VIEW (calendar_view), TRUE);
e_week_view_set_weeks_shown (E_WEEK_VIEW (calendar_view), 6);
cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH] = calendar_view;
g_object_ref_sink (calendar_view);
adjustment = gtk_range_get_adjustment (
GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
g_signal_connect (
adjustment, "value-changed",
G_CALLBACK (month_view_adjustment_changed_cb), cal_shell_content);
/* List View */
calendar_view = e_cal_list_view_new (model);
cal_shell_content->priv->views[E_CAL_VIEW_KIND_LIST] = calendar_view;
g_object_ref_sink (calendar_view);
shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
today = time (NULL);
for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
calendar_view = cal_shell_content->priv->views[ii];
calendar_view->in_focus = ii == cal_shell_content->priv->current_view;
e_calendar_view_set_selected_time_range (calendar_view, today, today);
e_signal_connect_notify (
calendar_view, "notify::is-editing",
G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
g_signal_connect (
calendar_view, "move-view-range",
G_CALLBACK (cal_shell_content_move_view_range_cb), cal_shell_content);
gtk_notebook_append_page (
GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook),
GTK_WIDGET (calendar_view), NULL);
gtk_widget_show (GTK_WIDGET (calendar_view));
}
}
static void
cal_shell_content_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_CURRENT_VIEW_ID:
e_cal_shell_content_set_current_view_id (E_CAL_SHELL_CONTENT (object),
g_value_get_int (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
cal_shell_content_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_CALENDAR_NOTEBOOK:
g_value_set_object (
value, e_cal_shell_content_get_calendar_notebook (
E_CAL_SHELL_CONTENT (object)));
return;
case PROP_MEMO_TABLE:
g_value_set_object (
value, e_cal_shell_content_get_memo_table (
E_CAL_SHELL_CONTENT (object)));
return;
case PROP_TASK_TABLE:
g_value_set_object (
value, e_cal_shell_content_get_task_table (
E_CAL_SHELL_CONTENT (object)));
return;
case PROP_CURRENT_VIEW_ID:
g_value_set_int (value,
e_cal_shell_content_get_current_view_id (E_CAL_SHELL_CONTENT (object)));
return;
case PROP_CURRENT_VIEW:
g_value_set_object (value,
e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
cal_shell_content_dispose (GObject *object)
{
ECalShellContent *cal_shell_content = E_CAL_SHELL_CONTENT (object);
gint ii;
if (cal_shell_content->priv->task_data_model) {
e_cal_data_model_set_disposing (cal_shell_content->priv->task_data_model, TRUE);
e_cal_data_model_unsubscribe (cal_shell_content->priv->task_data_model,
E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->task_model));
}
if (cal_shell_content->priv->memo_data_model) {
e_cal_data_model_set_disposing (cal_shell_content->priv->memo_data_model, TRUE);
e_cal_data_model_unsubscribe (cal_shell_content->priv->memo_data_model,
E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->memo_model));
}
if (cal_shell_content->priv->tag_calendar) {
ECalDataModel *data_model;
data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
e_cal_data_model_set_disposing (data_model, TRUE);
e_tag_calendar_unsubscribe (cal_shell_content->priv->tag_calendar, data_model);
g_clear_object (&cal_shell_content->priv->tag_calendar);
}
for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
g_clear_object (&(cal_shell_content->priv->views[ii]));
}
g_clear_object (&cal_shell_content->priv->hpaned);
g_clear_object (&cal_shell_content->priv->vpaned);
g_clear_object (&cal_shell_content->priv->calendar_notebook);
g_clear_object (&cal_shell_content->priv->task_table);
g_clear_object (&cal_shell_content->priv->task_model);
g_clear_object (&cal_shell_content->priv->task_data_model);
g_clear_object (&cal_shell_content->priv->memo_table);
g_clear_object (&cal_shell_content->priv->memo_model);
g_clear_object (&cal_shell_content->priv->memo_data_model);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
}
static void
cal_shell_content_constructed (GObject *object)
{
ECalShellContent *cal_shell_content;
EShellContent *shell_content;
EShellView *shell_view;
EShellWindow *shell_window;
EShell *shell;
GalViewInstance *view_instance;
GSettings *settings;
GtkWidget *container;
GtkWidget *widget;
gchar *markup;
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object);
cal_shell_content = E_CAL_SHELL_CONTENT (object);
shell_content = E_SHELL_CONTENT (cal_shell_content);
shell_view = e_shell_content_get_shell_view (shell_content);
shell_window = e_shell_view_get_shell_window (shell_view);
shell = e_shell_window_get_shell (shell_window);
cal_shell_content->priv->memo_data_model =
e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
cal_shell_content->priv->memo_model =
e_cal_model_memos_new (cal_shell_content->priv->memo_data_model, e_shell_get_registry (shell), shell);
cal_shell_content->priv->task_data_model =
e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
cal_shell_content->priv->task_model =
e_cal_model_tasks_new (cal_shell_content->priv->task_data_model, e_shell_get_registry (shell), shell);
g_object_bind_property (
cal_shell_content->priv->memo_model, "timezone",
cal_shell_content->priv->memo_data_model, "timezone",
G_BINDING_SYNC_CREATE);
g_object_bind_property (
cal_shell_content->priv->task_model, "timezone",
cal_shell_content->priv->task_data_model, "timezone",
G_BINDING_SYNC_CREATE);
/* Build content widgets. */
container = GTK_WIDGET (object);
widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (container), widget);
cal_shell_content->priv->hpaned = g_object_ref (widget);
gtk_widget_show (widget);
container = cal_shell_content->priv->hpaned;
widget = gtk_notebook_new ();
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
cal_shell_content->priv->calendar_notebook = g_object_ref (widget);
gtk_widget_show (widget);
widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
e_paned_set_fixed_resize (E_PANED (widget), FALSE);
gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE);
cal_shell_content->priv->vpaned = g_object_ref (widget);
gtk_widget_show (widget);
container = cal_shell_content->priv->calendar_notebook;
e_cal_shell_content_create_calendar_views (cal_shell_content);
g_object_bind_property (
cal_shell_content, "current-view-id",
cal_shell_content->priv->calendar_notebook, "page",
G_BINDING_SYNC_CREATE);
container = cal_shell_content->priv->vpaned;
widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
gtk_widget_show (widget);
container = widget;
widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
gtk_widget_show (widget);
widget = gtk_label_new (NULL);
markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
gtk_label_set_markup (GTK_LABEL (widget), markup);
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
gtk_widget_show (widget);
g_free (markup);
widget = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (
GTK_SCROLLED_WINDOW (widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (
GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
container = widget;
widget = e_task_table_new (shell_view, cal_shell_content->priv->task_model);
gtk_container_add (GTK_CONTAINER (container), widget);
cal_shell_content->priv->task_table = g_object_ref (widget);
gtk_widget_show (widget);
cal_shell_content_load_table_state (shell_content, E_TABLE (widget));
g_signal_connect_swapped (
widget, "open-component",
G_CALLBACK (e_cal_shell_view_taskpad_open_task),
shell_view);
e_signal_connect_notify (
widget, "notify::is-editing",
G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
container = cal_shell_content->priv->vpaned;
widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
gtk_widget_show (widget);
container = widget;
widget = gtk_label_new (NULL);
markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
gtk_label_set_markup (GTK_LABEL (widget), markup);
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
gtk_widget_show (widget);
g_free (markup);
widget = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (
GTK_SCROLLED_WINDOW (widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (
GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
container = widget;
widget = e_memo_table_new (shell_view, cal_shell_content->priv->memo_model);
gtk_container_add (GTK_CONTAINER (container), widget);
cal_shell_content->priv->memo_table = g_object_ref (widget);
gtk_widget_show (widget);
cal_shell_content_load_table_state (shell_content, E_TABLE (widget));
e_cal_model_set_default_time_func (cal_shell_content->priv->memo_model, cal_shell_content_get_default_time, cal_shell_content);
g_signal_connect_swapped (
widget, "open-component",
G_CALLBACK (e_cal_shell_view_memopad_open_memo),
shell_view);
e_signal_connect_notify (
widget, "notify::is-editing",
G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
/* Prepare the view instance. */
view_instance = e_shell_view_new_view_instance (shell_view, NULL);
g_signal_connect_swapped (
view_instance, "display-view",
G_CALLBACK (cal_shell_content_display_view_cb),
object);
/* Actual load happens at cal_shell_content_view_created() */
e_shell_view_set_view_instance (shell_view, view_instance);
g_object_unref (view_instance);
e_signal_connect_notify_swapped (
shell_view, "notify::view-id",
G_CALLBACK (cal_shell_content_notify_view_id_cb),
cal_shell_content);
settings = g_settings_new ("org.gnome.evolution.calendar");
g_settings_bind (
settings, "tag-vpane-position",
cal_shell_content->priv->vpaned, "proportion",
G_SETTINGS_BIND_DEFAULT);
g_object_unref (settings);
/* Cannot access shell sidebar here, thus rely on cal_shell_content_view_created()
with exact widget settings which require it */
}
static void
e_cal_shell_content_class_init (ECalShellContentClass *class)
{
GObjectClass *object_class;
EShellContentClass *shell_content_class;
ECalBaseShellContentClass *cal_base_shell_content_class;
g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->set_property = cal_shell_content_set_property;
object_class->get_property = cal_shell_content_get_property;
object_class->dispose = cal_shell_content_dispose;
object_class->constructed = cal_shell_content_constructed;
shell_content_class = E_SHELL_CONTENT_CLASS (class);
shell_content_class->check_state = cal_shell_content_check_state;
shell_content_class->focus_search_results = cal_shell_content_focus_search_results;
cal_base_shell_content_class = E_CAL_BASE_SHELL_CONTENT_CLASS (class);
cal_base_shell_content_class->new_cal_model = e_cal_model_calendar_new;
cal_base_shell_content_class->view_created = cal_shell_content_view_created;
g_object_class_install_property (
object_class,
PROP_CALENDAR_NOTEBOOK,
g_param_spec_object (
"calendar-notebook",
NULL,
NULL,
GTK_TYPE_NOTEBOOK,
G_PARAM_READABLE));
g_object_class_install_property (
object_class,
PROP_MEMO_TABLE,
g_param_spec_object (
"memo-table",
NULL,
NULL,
E_TYPE_MEMO_TABLE,
G_PARAM_READABLE));
g_object_class_install_property (
object_class,
PROP_TASK_TABLE,
g_param_spec_object (
"task-table",
NULL,
NULL,
E_TYPE_TASK_TABLE,
G_PARAM_READABLE));
g_object_class_install_property (
object_class,
PROP_CURRENT_VIEW_ID,
g_param_spec_int (
"current-view-id",
"Current Calendar View ID",
NULL,
E_CAL_VIEW_KIND_DAY,
E_CAL_VIEW_KIND_LAST - 1,
E_CAL_VIEW_KIND_DAY,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_CURRENT_VIEW,
g_param_spec_object (
"current-view",
"Current Calendar View",
NULL,
E_TYPE_CALENDAR_VIEW,
G_PARAM_READABLE));
}
static void
e_cal_shell_content_class_finalize (ECalShellContentClass *class)
{
}
static void
e_cal_shell_content_init (ECalShellContent *cal_shell_content)
{
time_t now;
cal_shell_content->priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
g_date_clear (&cal_shell_content->priv->view_start, 1);
g_date_clear (&cal_shell_content->priv->view_end, 1);
g_date_clear (&cal_shell_content->priv->last_range_start, 1);
now = time (NULL);
g_date_set_time_t (&cal_shell_content->priv->view_start, now);
g_date_set_time_t (&cal_shell_content->priv->view_end, now);
cal_shell_content->priv->view_start_range_day_offset = (guint32) -1;
}
void
e_cal_shell_content_type_register (GTypeModule *type_module)
{
/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
* function, so we have to wrap it with a public function in
* order to register types from a separate compilation unit. */
e_cal_shell_content_register_type (type_module);
}
GtkWidget *
e_cal_shell_content_new (EShellView *shell_view)
{
g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
return g_object_new (
E_TYPE_CAL_SHELL_CONTENT,
"shell-view", shell_view, NULL);
}
GtkNotebook *
e_cal_shell_content_get_calendar_notebook (ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
return GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook);
}
EMemoTable *
e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
}
ETaskTable *
e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
return E_TASK_TABLE (cal_shell_content->priv->task_table);
}
EShellSearchbar *
e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content)
{
EShellView *shell_view;
EShellContent *shell_content;
GtkWidget *widget;
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
shell_content = E_SHELL_CONTENT (cal_shell_content);
shell_view = e_shell_content_get_shell_view (shell_content);
widget = e_shell_view_get_searchbar (shell_view);
return E_SHELL_SEARCHBAR (widget);
}
static void
cal_shell_content_resubscribe (ECalendarView *cal_view,
ECalModel *model)
{
ECalDataModel *data_model;
ECalDataModelSubscriber *subscriber;
time_t range_start, range_end;
gboolean is_tasks_or_memos;
g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
g_return_if_fail (E_IS_CAL_MODEL (model));
data_model = e_cal_model_get_data_model (model);
subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (model);
is_tasks_or_memos = e_cal_model_get_component_kind (model) == ICAL_VJOURNAL_COMPONENT ||
e_cal_model_get_component_kind (model) == ICAL_VTODO_COMPONENT;
if ((!is_tasks_or_memos && e_calendar_view_get_visible_time_range (cal_view, &range_start, &range_end)) ||
e_cal_data_model_get_subscriber_range (data_model, subscriber, &range_start, &range_end)) {
e_cal_data_model_unsubscribe (data_model, subscriber);
e_cal_model_remove_all_objects (model);
if (is_tasks_or_memos)
e_cal_data_model_subscribe (data_model, subscriber, range_start, range_end);
}
}
void
e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
ECalViewKind view_kind)
{
gint ii;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST);
if (cal_shell_content->priv->current_view == view_kind)
return;
for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
ECalendarView *cal_view = cal_shell_content->priv->views[ii];
gboolean in_focus = ii == view_kind;
gboolean focus_changed;
if (!cal_view) {
g_warn_if_reached ();
continue;
}
focus_changed = (cal_view->in_focus ? 1 : 0) != (in_focus ? 1 : 0);
cal_view->in_focus = in_focus;
if (focus_changed && in_focus) {
/* Currently focused view changed. Any events within the common time
range are not shown in the newly focused view, thus make sure it'll
contain all what it should have. */
ECalModel *model;
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
/* This may not cause any queries to backends with events,
because the time range should be always within the one
shown in the date picker. */
cal_shell_content_resubscribe (cal_view, model);
if (cal_shell_content->priv->task_table) {
ETaskTable *task_table;
task_table = E_TASK_TABLE (cal_shell_content->priv->task_table);
cal_shell_content_resubscribe (cal_view, e_task_table_get_model (task_table));
}
if (cal_shell_content->priv->memo_table) {
EMemoTable *memo_table;
memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
cal_shell_content_resubscribe (cal_view, e_memo_table_get_model (memo_table));
}
}
}
cal_shell_content->priv->current_view = view_kind;
g_object_notify (G_OBJECT (cal_shell_content), "current-view-id");
gtk_widget_queue_draw (GTK_WIDGET (cal_shell_content->priv->views[cal_shell_content->priv->current_view]));
}
ECalViewKind
e_cal_shell_content_get_current_view_id (ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), E_CAL_VIEW_KIND_LAST);
return cal_shell_content->priv->current_view;
}
ECalendarView *
e_cal_shell_content_get_calendar_view (ECalShellContent *cal_shell_content,
ECalViewKind view_kind)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
g_return_val_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST, NULL);
return cal_shell_content->priv->views[view_kind];
}
ECalendarView *
e_cal_shell_content_get_current_calendar_view (ECalShellContent *cal_shell_content)
{
g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
return e_cal_shell_content_get_calendar_view (cal_shell_content,
e_cal_shell_content_get_current_view_id (cal_shell_content));
}
void
e_cal_shell_content_save_state (ECalShellContent *cal_shell_content)
{
ECalShellContentPrivate *priv;
g_return_if_fail (cal_shell_content != NULL);
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
priv = cal_shell_content->priv;
if (priv->task_table != NULL)
cal_shell_content_save_table_state (
E_SHELL_CONTENT (cal_shell_content),
E_TABLE (priv->task_table));
if (priv->memo_table != NULL)
cal_shell_content_save_table_state (
E_SHELL_CONTENT (cal_shell_content),
E_TABLE (priv->memo_table));
}
void
e_cal_shell_content_get_current_range (ECalShellContent *cal_shell_content,
time_t *range_start,
time_t *range_end)
{
icaltimezone *zone;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (range_start != NULL);
g_return_if_fail (range_end != NULL);
zone = e_cal_data_model_get_timezone (e_cal_base_shell_content_get_data_model (
E_CAL_BASE_SHELL_CONTENT (cal_shell_content)));
*range_start = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_start), zone);
*range_end = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_end), zone);
}
void
e_cal_shell_content_get_current_range_dates (ECalShellContent *cal_shell_content,
GDate *range_start,
GDate *range_end)
{
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (range_start != NULL);
g_return_if_fail (range_end != NULL);
*range_start = cal_shell_content->priv->view_start;
*range_end = cal_shell_content->priv->view_end;
}
static void
cal_shell_content_move_view_range_relative (ECalShellContent *cal_shell_content,
gint direction)
{
GDate start, end;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
g_return_if_fail (direction != 0);
start = cal_shell_content->priv->view_start;
end = cal_shell_content->priv->view_end;
switch (cal_shell_content->priv->current_view) {
case E_CAL_VIEW_KIND_DAY:
if (direction > 0) {
g_date_add_days (&start, direction);
g_date_add_days (&end, direction);
} else {
g_date_subtract_days (&start, direction * -1);
g_date_subtract_days (&end, direction * -1);
}
break;
case E_CAL_VIEW_KIND_WORKWEEK:
case E_CAL_VIEW_KIND_WEEK:
if (direction > 0) {
g_date_add_days (&start, direction * 7);
g_date_add_days (&end, direction * 7);
} else {
g_date_subtract_days (&start, direction * -7);
g_date_subtract_days (&end, direction * -7);
}
break;
case E_CAL_VIEW_KIND_MONTH:
case E_CAL_VIEW_KIND_LIST:
if (direction > 0) {
g_date_add_months (&start, direction);
g_date_add_months (&end, direction);
} else {
g_date_subtract_months (&start, direction * -1);
g_date_subtract_months (&end, direction * -1);
}
break;
case E_CAL_VIEW_KIND_LAST:
return;
}
e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &start, &end, FALSE);
}
void
e_cal_shell_content_move_view_range (ECalShellContent *cal_shell_content,
ECalendarViewMoveType move_type,
time_t exact_date)
{
ECalendar *calendar;
ECalDataModel *data_model;
EShellSidebar *shell_sidebar;
EShellView *shell_view;
struct icaltimetype tt;
icaltimezone *zone;
GDate date;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
g_return_if_fail (E_IS_CALENDAR (calendar));
g_return_if_fail (calendar->calitem != NULL);
data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
zone = e_cal_data_model_get_timezone (data_model);
switch (move_type) {
case E_CALENDAR_VIEW_MOVE_PREVIOUS:
cal_shell_content_move_view_range_relative (cal_shell_content, -1);
break;
case E_CALENDAR_VIEW_MOVE_NEXT:
cal_shell_content_move_view_range_relative (cal_shell_content, +1);
break;
case E_CALENDAR_VIEW_MOVE_TO_TODAY:
tt = icaltime_current_time_with_zone (zone);
g_date_set_dmy (&date, tt.day, tt.month, tt.year);
/* one-day selection takes care of the view range move with left view kind */
e_calendar_item_set_selection (calendar->calitem, &date, &date);
break;
case E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY:
time_to_gdate_with_zone (&date, exact_date, zone);
e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &date, &date, FALSE);
break;
}
}
static void
cal_shell_content_update_model_filter (ECalDataModel *data_model,
ECalModel *model,
const gchar *filter,
time_t range_start,
time_t range_end)
{
time_t tmp_start, tmp_end;
g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
g_return_if_fail (E_IS_CAL_MODEL (model));
e_cal_data_model_freeze_views_update (data_model);
if (filter != NULL)
e_cal_data_model_set_filter (data_model, filter);
e_cal_model_set_time_range (model, range_start, range_end);
if (!e_cal_data_model_get_subscriber_range (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), &tmp_start, &tmp_end)) {
e_cal_data_model_subscribe (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), range_start, range_end);
}
e_cal_data_model_thaw_views_update (data_model);
}
void
e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
const gchar *cal_filter,
time_t start_range,
time_t end_range)
{
ECalDataModel *data_model;
ECalModel *model;
g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
if (!cal_filter)
return;
data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
cal_shell_content_update_model_filter (data_model, model, cal_filter, start_range, end_range);
if (cal_shell_content->priv->task_table) {
ETaskTable *task_table;
gchar *hide_completed_tasks_sexp;
/* Set the query on the task pad. */
task_table = E_TASK_TABLE (cal_shell_content->priv->task_table);
model = e_task_table_get_model (task_table);
data_model = e_cal_model_get_data_model (model);
hide_completed_tasks_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
if (hide_completed_tasks_sexp != NULL) {
if (cal_filter != NULL) {
gchar *filter;
filter = g_strdup_printf ("(and %s %s)", hide_completed_tasks_sexp, cal_filter);
cal_shell_content_update_model_filter (data_model, model, filter, 0, 0);
g_free (filter);
} else {
cal_shell_content_update_model_filter (data_model, model, hide_completed_tasks_sexp, 0, 0);
}
} else {
cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : "#t", 0, 0);
}
g_free (hide_completed_tasks_sexp);
}
if (cal_shell_content->priv->memo_table) {
EMemoTable *memo_table;
/* Set the query on the memo pad. */
memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
model = e_memo_table_get_model (memo_table);
data_model = e_cal_model_get_data_model (model);
if (start_range != 0 && end_range != 0) {
icaltimezone *zone;
const gchar *default_tzloc = NULL;
time_t end = end_range;
gchar *filter;
gchar *iso_start;
gchar *iso_end;
zone = e_cal_data_model_get_timezone (data_model);
if (zone && zone != icaltimezone_get_utc_timezone ())
default_tzloc = icaltimezone_get_location (zone);
if (!default_tzloc)
default_tzloc = "";
if (start_range != (time_t) 0 && end_range != (time_t) 0) {
end = time_day_end_with_zone (end_range, zone);
}
iso_start = isodate_from_time_t (start_range);
iso_end = isodate_from_time_t (end);
filter = g_strdup_printf (
"(and (or (not (has-start?)) "
"(occur-in-time-range? (make-time \"%s\") "
"(make-time \"%s\") \"%s\")) %s)",
iso_start, iso_end, default_tzloc, cal_filter ? cal_filter : "");
cal_shell_content_update_model_filter (data_model, model, filter, 0, 0);
g_free (filter);
g_free (iso_start);
g_free (iso_end);
} else {
cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : "#t", 0, 0);
}
}
}