/*
* 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; either
* version 2 of the License, or (at your option) version 3.
*
* 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 the program; if not, see
*
*
* Authors:
* Damon Chaplin
* Rodrigo Moya
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
/*
* EWeekView - displays the Week & Month views of the calendar.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include "e-week-view.h"
#include "ea-calendar.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "dialogs/delete-comp.h"
#include "dialogs/delete-error.h"
#include "dialogs/send-comp.h"
#include "dialogs/cancel-comp.h"
#include "dialogs/recur-comp.h"
#include "comp-util.h"
#include "itip-utils.h"
#include
#include "calendar-config.h"
#include "print.h"
#include "goto.h"
#include "e-cal-model-calendar.h"
#include "e-week-view-event-item.h"
#include "e-week-view-layout.h"
#include "e-week-view-main-item.h"
#include "e-week-view-titles-item.h"
#include "misc.h"
#include
/* Images */
#include "art/jump.xpm"
#define E_WEEK_VIEW_SMALL_FONT_PTSIZE 7
#define E_WEEK_VIEW_JUMP_BUTTON_WIDTH 16
#define E_WEEK_VIEW_JUMP_BUTTON_HEIGHT 8
#define E_WEEK_VIEW_JUMP_BUTTON_X_PAD 3
#define E_WEEK_VIEW_JUMP_BUTTON_Y_PAD 3
#define E_WEEK_VIEW_JUMP_BUTTON_NO_FOCUS -1
/* The timeout before we do a layout, so we don't do a layout for each event
we get from the server. */
#define E_WEEK_VIEW_LAYOUT_TIMEOUT 100
typedef struct {
EWeekView *week_view;
ECalModelComponent *comp_data;
} AddEventData;
static void e_week_view_dispose (GObject *object);
static void e_week_view_realize (GtkWidget *widget);
static void e_week_view_set_colors (EWeekView *week_view, GtkWidget *widget);
static void e_week_view_unrealize (GtkWidget *widget);
static void e_week_view_style_set (GtkWidget *widget,
GtkStyle *previous_style);
static void e_week_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void e_week_view_recalc_cell_sizes (EWeekView *week_view);
static gint e_week_view_focus_in (GtkWidget *widget,
GdkEventFocus *event);
static gint e_week_view_focus_out (GtkWidget *widget,
GdkEventFocus *event);
static gboolean e_week_view_get_next_tab_event (EWeekView *week_view,
GtkDirectionType direction,
gint current_event_num,
gint current_span_num,
gint *next_event_num,
gint *next_span_num);
static gboolean e_week_view_focus (GtkWidget *widget,
GtkDirectionType direction);
static GList *e_week_view_get_selected_events (ECalendarView *cal_view);
static gboolean e_week_view_get_selected_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time);
static void e_week_view_set_selected_time_range (ECalendarView *cal_view, time_t start_time, time_t end_time);
static gboolean e_week_view_get_visible_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time);
static void e_week_view_paste_text (ECalendarView *week_view);
static void e_week_view_update_query (EWeekView *week_view);
static gboolean e_week_view_on_button_press (GtkWidget *widget,
GdkEventButton *event,
EWeekView *week_view);
static gboolean e_week_view_on_button_release (GtkWidget *widget,
GdkEventButton *event,
EWeekView *week_view);
static gboolean e_week_view_on_scroll (GtkWidget *widget,
GdkEventScroll *scroll,
EWeekView *week_view);
static gboolean e_week_view_on_motion (GtkWidget *widget,
GdkEventMotion *event,
EWeekView *week_view);
static gint e_week_view_convert_position_to_day (EWeekView *week_view,
gint x,
gint y);
static void e_week_view_update_selection (EWeekView *week_view,
gint day);
static void e_week_view_free_events (EWeekView *week_view);
static gboolean e_week_view_add_event (ECalComponent *comp,
time_t start,
time_t end,
gboolean prepend,
gpointer data);
static void e_week_view_check_layout (EWeekView *week_view);
static void e_week_view_ensure_events_sorted (EWeekView *week_view);
static void e_week_view_reshape_events (EWeekView *week_view);
static void e_week_view_reshape_event_span (EWeekView *week_view,
gint event_num,
gint span_num);
static void e_week_view_recalc_day_starts (EWeekView *week_view,
time_t lower);
static void e_week_view_on_editing_started (EWeekView *week_view,
GnomeCanvasItem *item);
static void e_week_view_on_editing_stopped (EWeekView *week_view,
GnomeCanvasItem *item);
static gboolean e_week_view_find_event_from_uid (EWeekView *week_view,
ECal *client,
const gchar *uid,
const gchar *rid,
gint *event_num_return);
typedef gboolean (* EWeekViewForeachEventCallback) (EWeekView *week_view,
gint event_num,
gpointer data);
static void e_week_view_foreach_event_with_uid (EWeekView *week_view,
const gchar *uid,
EWeekViewForeachEventCallback callback,
gpointer data);
static gboolean e_week_view_on_text_item_event (GnomeCanvasItem *item,
GdkEvent *event,
EWeekView *week_view);
static gboolean e_week_view_event_move (ECalendarView *cal_view, ECalViewMoveDirection direction);
static gint e_week_view_get_day_offset_of_event (EWeekView *week_view, time_t event_time);
static void e_week_view_change_event_time (EWeekView *week_view, time_t start_dt, time_t end_dt, gboolean is_all_day);
static gboolean e_week_view_on_jump_button_event (GnomeCanvasItem *item,
GdkEvent *event,
EWeekView *week_view);
static gboolean e_week_view_key_press (GtkWidget *widget, GdkEventKey *event);
static gboolean e_week_view_do_key_press (GtkWidget *widget,
GdkEventKey *event);
static gint e_week_view_get_adjust_days_for_move_up (EWeekView *week_view, gint
current_day);
static gint e_week_view_get_adjust_days_for_move_down (EWeekView *week_view,gint current_day);
static gint e_week_view_get_adjust_days_for_move_left (EWeekView *week_view,gint current_day);
static gint e_week_view_get_adjust_days_for_move_right (EWeekView *week_view,gint current_day);
static gboolean e_week_view_popup_menu (GtkWidget *widget);
static gboolean e_week_view_remove_event_cb (EWeekView *week_view,
gint event_num,
gpointer data);
static gboolean e_week_view_recalc_display_start_day (EWeekView *week_view);
static void e_week_view_queue_layout (EWeekView *week_view);
static void e_week_view_cancel_layout (EWeekView *week_view);
static gboolean e_week_view_layout_timeout_cb (gpointer data);
G_DEFINE_TYPE (EWeekView, e_week_view, E_TYPE_CALENDAR_VIEW)
enum {
PROP_0,
PROP_COMPRESS_WEEKEND,
PROP_SHOW_EVENT_END_TIMES
};
static gint map_left[] = {0, 1, 2, 0, 1, 2, 2};
static gint map_right[] = {3, 4, 5, 3, 4, 5, 6};
static void
week_view_process_component (EWeekView *week_view,
ECalModelComponent *comp_data)
{
ECalComponent *comp = NULL;
AddEventData add_event_data;
/* rid is never used in this function? */
const gchar *uid;
gchar *rid = NULL;
/* If we don't have a valid date set yet, just return. */
if (!g_date_valid (&week_view->first_day_shown))
return;
comp = e_cal_component_new ();
if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) {
g_object_unref (comp);
g_message (G_STRLOC ": Could not set icalcomponent on ECalComponent");
return;
}
e_cal_component_get_uid (comp, &uid);
if (e_cal_component_is_instance (comp))
rid = e_cal_component_get_recurid_as_string (comp);
else
rid = NULL;
/* Add the object */
add_event_data.week_view = week_view;
add_event_data.comp_data = comp_data;
e_week_view_add_event (comp, comp_data->instance_start, comp_data->instance_end, FALSE, &add_event_data);
g_object_unref (comp);
g_free (rid);
}
static void
week_view_update_row (EWeekView *week_view, gint row)
{
ECalModelComponent *comp_data;
ECalModel *model;
gint event_num;
const gchar *uid;
gchar *rid = NULL;
model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
comp_data = e_cal_model_get_component_at (model, row);
g_return_if_fail (comp_data != NULL);
uid = icalcomponent_get_uid (comp_data->icalcomp);
if (e_cal_util_component_is_instance (comp_data->icalcomp)) {
icalproperty *prop;
prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY);
if (prop)
rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp));
}
if (e_week_view_find_event_from_uid (week_view, comp_data->client, uid, rid, &event_num))
e_week_view_remove_event_cb (week_view, event_num, NULL);
g_free (rid);
week_view_process_component (week_view, comp_data);
gtk_widget_queue_draw (week_view->main_canvas);
e_week_view_queue_layout (week_view);
}
static void
week_view_model_cell_changed_cb (EWeekView *week_view,
gint col,
gint row)
{
if (!E_CALENDAR_VIEW (week_view)->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
week_view_update_row (week_view, row);
}
static void
week_view_model_comps_deleted_cb (EWeekView *week_view,
gpointer data)
{
GSList *l, *list = data;
/* FIXME Stop editing? */
if (!E_CALENDAR_VIEW (week_view)->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
for (l = list; l != NULL; l = g_slist_next (l)) {
gint event_num;
const gchar *uid;
gchar *rid = NULL;
ECalModelComponent *comp_data = l->data;
uid = icalcomponent_get_uid (comp_data->icalcomp);
if (e_cal_util_component_is_instance (comp_data->icalcomp)) {
icalproperty *prop;
prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY);
if (prop)
rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp));
}
if (e_week_view_find_event_from_uid (week_view, comp_data->client, uid, rid, &event_num))
e_week_view_remove_event_cb (week_view, event_num, NULL);
g_free (rid);
}
gtk_widget_queue_draw (week_view->main_canvas);
e_week_view_queue_layout (week_view);
}
static void
week_view_model_row_changed_cb (EWeekView *week_view,
gint row)
{
if (!E_CALENDAR_VIEW (week_view)->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
week_view_update_row (week_view, row);
}
static void
week_view_model_rows_inserted_cb (EWeekView *week_view,
gint row,
gint count)
{
ECalModel *model;
gint i;
if (!E_CALENDAR_VIEW (week_view)->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
for (i = 0; i < count; i++) {
ECalModelComponent *comp_data;
comp_data = e_cal_model_get_component_at (model, row + i);
if (comp_data == NULL) {
g_warning ("comp_data is NULL\n");
continue;
}
week_view_process_component (week_view, comp_data);
}
gtk_widget_queue_draw (week_view->main_canvas);
e_week_view_queue_layout (week_view);
}
static void
week_view_time_range_changed_cb (EWeekView *week_view,
time_t start_time,
time_t end_time,
ECalModel *model)
{
GDate date, base_date;
gint day_offset, weekday, week_start_offset;
gboolean update_adjustment_value = FALSE;
g_return_if_fail (E_IS_WEEK_VIEW (week_view));
time_to_gdate_with_zone (&date, start_time, e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
/* Calculate the weekday of the given date, 0 = Mon. */
weekday = g_date_get_weekday (&date) - 1;
/* Convert it to an offset from the start of the display. */
week_start_offset = (weekday + 7 - week_view->display_start_day) % 7;
/* Set the day_offset to the result, so we move back to the
start of the week. */
day_offset = week_start_offset;
/* Calculate the base date, i.e. the first day shown when the
scrollbar adjustment value is 0. */
base_date = date;
g_date_subtract_days (&base_date, day_offset);
/* See if we need to update the base date. */
if (!g_date_valid (&week_view->base_date)
|| week_view->update_base_date) {
week_view->base_date = base_date;
update_adjustment_value = TRUE;
}
/* See if we need to update the first day shown. */
if (!g_date_valid (&week_view->first_day_shown)
|| g_date_compare (&week_view->first_day_shown, &base_date)) {
week_view->first_day_shown = base_date;
start_time = time_add_day_with_zone (start_time, -day_offset,
e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
start_time = time_day_begin_with_zone (start_time,
e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
e_week_view_recalc_day_starts (week_view, start_time);
}
/* Reset the adjustment value to 0 if the base address has changed.
Note that we do this after updating first_day_shown so that our
signal handler will not try to reload the events. */
if (update_adjustment_value) {
GtkRange *range;
GtkAdjustment *adjustment;
range = GTK_RANGE (week_view->vscrollbar);
adjustment = gtk_range_get_adjustment (range);
gtk_adjustment_set_value (adjustment, 0);
}
if (!E_CALENDAR_VIEW (week_view)->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
gtk_widget_queue_draw (week_view->main_canvas);
/* FIXME Preserve selection if possible */
if (week_view->selection_start_day == -1 ||
(week_view->multi_week_view ? week_view->weeks_shown * 7 : 7) <= week_view->selection_start_day)
e_week_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), start_time, start_time);
}
static void
timezone_changed_cb (ECalModel *cal_model,
icaltimezone *old_zone,
icaltimezone *new_zone,
gpointer user_data)
{
ECalendarView *cal_view = (ECalendarView *) user_data;
struct icaltimetype tt = icaltime_null_time ();
time_t lower;
EWeekView *week_view = (EWeekView *) cal_view;
g_return_if_fail (E_IS_WEEK_VIEW (week_view));
if (!cal_view->in_focus) {
e_week_view_free_events (week_view);
week_view->requires_update = TRUE;
return;
}
/* If we don't have a valid date set yet, just return. */
if (!g_date_valid (&week_view->first_day_shown))
return;
/* Recalculate the new start of the first week. We just use exactly
the same time, but with the new timezone. */
tt.year = g_date_get_year (&week_view->first_day_shown);
tt.month = g_date_get_month (&week_view->first_day_shown);
tt.day = g_date_get_day (&week_view->first_day_shown);
lower = icaltime_as_timet_with_zone (tt, new_zone);
e_week_view_recalc_day_starts (week_view, lower);
e_week_view_update_query (week_view);
}
static void
week_view_notify_week_start_day_cb (EWeekView *week_view)
{
GDate *first_day_shown;
first_day_shown = &week_view->first_day_shown;
e_week_view_recalc_display_start_day (week_view);
/* Recalculate the days shown and reload if necessary. */
if (g_date_valid (first_day_shown))
e_week_view_set_first_day_shown (week_view, first_day_shown);
gtk_widget_queue_draw (week_view->titles_canvas);
gtk_widget_queue_draw (week_view->main_canvas);
}
static void
week_view_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_COMPRESS_WEEKEND:
e_week_view_set_compress_weekend (
E_WEEK_VIEW (object),
g_value_get_boolean (value));
return;
case PROP_SHOW_EVENT_END_TIMES:
e_week_view_set_show_event_end_times (
E_WEEK_VIEW (object),
g_value_get_boolean (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
week_view_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_COMPRESS_WEEKEND:
g_value_set_boolean (
value,
e_week_view_get_compress_weekend (
E_WEEK_VIEW (object)));
return;
case PROP_SHOW_EVENT_END_TIMES:
g_value_set_boolean (
value,
e_week_view_get_show_event_end_times (
E_WEEK_VIEW (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
week_view_constructed (GObject *object)
{
ECalModel *model;
ECalendarView *calendar_view;
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_week_view_parent_class)->constructed (object);
calendar_view = E_CALENDAR_VIEW (object);
model = e_calendar_view_get_model (calendar_view);
e_week_view_recalc_display_start_day (E_WEEK_VIEW (object));
g_signal_connect_swapped (
model, "notify::week-start-day",
G_CALLBACK (week_view_notify_week_start_day_cb), object);
g_signal_connect_swapped (
model, "comps-deleted",
G_CALLBACK (week_view_model_comps_deleted_cb), object);
g_signal_connect_swapped (
model, "model-cell-changed",
G_CALLBACK (week_view_model_cell_changed_cb), object);
g_signal_connect_swapped (
model, "model-row-changed",
G_CALLBACK (week_view_model_row_changed_cb), object);
g_signal_connect_swapped (
model, "model-rows-inserted",
G_CALLBACK (week_view_model_rows_inserted_cb), object);
g_signal_connect_swapped (
model, "time-range-changed",
G_CALLBACK (week_view_time_range_changed_cb), object);
}
static void
week_view_cursor_key_up (EWeekView *week_view)
{
if (week_view->selection_start_day == -1)
return;
week_view->selection_start_day--;
if (week_view->selection_start_day < 0) {
e_week_view_scroll_a_step (week_view, E_CAL_VIEW_MOVE_UP);
week_view->selection_start_day = 6;
}
week_view->selection_end_day = week_view->selection_start_day;
g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
static void
week_view_cursor_key_down (EWeekView *week_view)
{
if (week_view->selection_start_day == -1)
return;
week_view->selection_start_day++;
if (week_view->selection_start_day > 6) {
e_week_view_scroll_a_step (week_view, E_CAL_VIEW_MOVE_DOWN);
week_view->selection_start_day = 0;
}
week_view->selection_end_day = week_view->selection_start_day;
g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
static void
week_view_cursor_key_left (EWeekView *week_view)
{
if (week_view->selection_start_day == -1)
return;
week_view->selection_start_day = map_left[week_view->selection_start_day];
week_view->selection_end_day = week_view->selection_start_day;
g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
static void
week_view_cursor_key_right (EWeekView *week_view)
{
if (week_view->selection_start_day == -1)
return;
week_view->selection_start_day = map_right[week_view->selection_start_day];
week_view->selection_end_day = week_view->selection_start_day;
g_signal_emit_by_name (week_view, "selected_time_changed");
gtk_widget_queue_draw (week_view->main_canvas);
}
static void
e_week_view_class_init (EWeekViewClass *class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
ECalendarViewClass *view_class;
object_class = G_OBJECT_CLASS (class);
object_class->set_property = week_view_set_property;
object_class->get_property = week_view_get_property;
object_class->constructed = week_view_constructed;
object_class->dispose = e_week_view_dispose;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->realize = e_week_view_realize;
widget_class->unrealize = e_week_view_unrealize;
widget_class->style_set = e_week_view_style_set;
widget_class->size_allocate = e_week_view_size_allocate;
widget_class->focus_in_event = e_week_view_focus_in;
widget_class->focus_out_event = e_week_view_focus_out;
widget_class->key_press_event = e_week_view_key_press;
widget_class->popup_menu = e_week_view_popup_menu;
widget_class->focus = e_week_view_focus;
view_class = E_CALENDAR_VIEW_CLASS (class);
view_class->get_selected_events = e_week_view_get_selected_events;
view_class->get_selected_time_range = e_week_view_get_selected_time_range;
view_class->set_selected_time_range = e_week_view_set_selected_time_range;
view_class->get_visible_time_range = e_week_view_get_visible_time_range;
view_class->paste_text = e_week_view_paste_text;
class->cursor_key_up = week_view_cursor_key_up;
class->cursor_key_down = week_view_cursor_key_down;
class->cursor_key_left = week_view_cursor_key_left;
class->cursor_key_right = week_view_cursor_key_right;
/* XXX This property really belongs in EMonthView,
* but too much drawing code is tied to it. */
g_object_class_install_property (
object_class,
PROP_COMPRESS_WEEKEND,
g_param_spec_boolean (
"compress-weekend",
"Compress Weekend",
NULL,
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (
object_class,
PROP_SHOW_EVENT_END_TIMES,
g_param_spec_boolean (
"show-event-end-times",
"Show Event End Times",
NULL,
TRUE,
G_PARAM_READWRITE));
/* init the accessibility support for e_week_view */
e_week_view_a11y_init ();
}
static void
e_week_view_init (EWeekView *week_view)
{
GnomeCanvasGroup *canvas_group;
GtkAdjustment *adjustment;
GdkPixbuf *pixbuf;
gint i;
gtk_widget_set_can_focus (GTK_WIDGET (week_view), TRUE);
week_view->query = NULL;
week_view->event_destroyed = FALSE;
week_view->events = g_array_new (FALSE, FALSE,
sizeof (EWeekViewEvent));
week_view->events_sorted = TRUE;
week_view->events_need_layout = FALSE;
week_view->events_need_reshape = FALSE;
week_view->layout_timeout_id = 0;
week_view->spans = NULL;
week_view->multi_week_view = FALSE;
week_view->month_scroll_by_week = FALSE;
week_view->scroll_by_week_notif_id = 0;
week_view->update_base_date = TRUE;
week_view->weeks_shown = 6;
week_view->rows = 6;
week_view->columns = 2;
week_view->compress_weekend = TRUE;
week_view->show_event_end_times = TRUE;
week_view->display_start_day = 0; /* Monday. */
g_date_clear (&week_view->base_date, 1);
g_date_clear (&week_view->first_day_shown, 1);
week_view->row_height = 10;
week_view->rows_per_cell = 1;
week_view->selection_start_day = -1;
week_view->selection_drag_pos = E_WEEK_VIEW_DRAG_NONE;
week_view->pressed_event_num = -1;
week_view->editing_event_num = -1;
week_view->last_edited_comp_string = NULL;
/* Create the small font. */
week_view->use_small_font = TRUE;
week_view->small_font_desc =
pango_font_description_copy (gtk_widget_get_style (GTK_WIDGET (week_view))->font_desc);
pango_font_description_set_size (week_view->small_font_desc,
E_WEEK_VIEW_SMALL_FONT_PTSIZE * PANGO_SCALE);
/* String to use in 12-hour time format for times in the morning. */
week_view->am_string = _("am");
/* String to use in 12-hour time format for times in the afternoon. */
week_view->pm_string = _("pm");
week_view->bc_event_time = 0;
week_view->before_click_dtstart = 0;
week_view->before_click_dtend = 0;
/*
* Titles Canvas. Note that we don't show it is only shown in the
* Month view.
*/
week_view->titles_canvas = e_canvas_new ();
gtk_table_attach (GTK_TABLE (week_view), week_view->titles_canvas,
1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
canvas_group = GNOME_CANVAS_GROUP (GNOME_CANVAS (week_view->titles_canvas)->root);
week_view->titles_canvas_item =
gnome_canvas_item_new (canvas_group,
e_week_view_titles_item_get_type (),
"EWeekViewTitlesItem::week_view", week_view,
NULL);
/*
* Main Canvas
*/
week_view->main_canvas = e_canvas_new ();
gtk_table_attach (GTK_TABLE (week_view), week_view->main_canvas,
1, 2, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 1, 1);
gtk_widget_show (week_view->main_canvas);
canvas_group = GNOME_CANVAS_GROUP (GNOME_CANVAS (week_view->main_canvas)->root);
week_view->main_canvas_item =
gnome_canvas_item_new (canvas_group,
e_week_view_main_item_get_type (),
"EWeekViewMainItem::week_view", week_view,
NULL);
g_signal_connect_after (week_view->main_canvas, "button_press_event",
G_CALLBACK (e_week_view_on_button_press), week_view);
g_signal_connect (week_view->main_canvas, "button_release_event",
G_CALLBACK (e_week_view_on_button_release), week_view);
g_signal_connect (week_view->main_canvas, "scroll_event",
G_CALLBACK (e_week_view_on_scroll), week_view);
g_signal_connect (week_view->main_canvas, "motion_notify_event",
G_CALLBACK (e_week_view_on_motion), week_view);
/* Create the buttons to jump to each days. */
pixbuf = gdk_pixbuf_new_from_xpm_data ((const gchar **) jump_xpm);
for (i = 0; i < E_WEEK_VIEW_MAX_WEEKS * 7; i++) {
week_view->jump_buttons[i] = gnome_canvas_item_new
(canvas_group,
gnome_canvas_pixbuf_get_type (),
"GnomeCanvasPixbuf::pixbuf", pixbuf,
NULL);
g_signal_connect (week_view->jump_buttons[i], "event",
G_CALLBACK (e_week_view_on_jump_button_event), week_view);
}
week_view->focused_jump_button = E_WEEK_VIEW_JUMP_BUTTON_NO_FOCUS;
g_object_unref (pixbuf);
/*
* Scrollbar.
*/
adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, -52, 52, 1, 1, 1));
week_view->vscrollbar = gtk_vscrollbar_new (adjustment);
gtk_table_attach (GTK_TABLE (week_view), week_view->vscrollbar,
2, 3, 1, 2, 0, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (week_view->vscrollbar);
/* Create the cursors. */
week_view->normal_cursor = gdk_cursor_new (GDK_LEFT_PTR);
week_view->move_cursor = gdk_cursor_new (GDK_FLEUR);
week_view->resize_width_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
week_view->last_cursor_set = NULL;
week_view->requires_update = FALSE;
}
/**
* e_week_view_new:
* @Returns: a new #EWeekView.
*
* Creates a new #EWeekView.
**/
ECalendarView *
e_week_view_new (ECalModel *model)
{
ECalendarView *view;
g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
view = g_object_new (E_TYPE_WEEK_VIEW, "model", model, NULL);
g_signal_connect (G_OBJECT (model), "timezone_changed",
G_CALLBACK (timezone_changed_cb), view);
return view;
}
static void
e_week_view_dispose (GObject *object)
{
EWeekView *week_view;
week_view = E_WEEK_VIEW (object);
e_week_view_cancel_layout (week_view);
if (week_view->events) {
e_week_view_free_events (week_view);
g_array_free (week_view->events, TRUE);
week_view->events = NULL;
}
if (week_view->query) {
g_signal_handlers_disconnect_matched (week_view->query, G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL, week_view);
g_object_unref (week_view->query);
week_view->query = NULL;
}
if (week_view->small_font_desc) {
pango_font_description_free (week_view->small_font_desc);
week_view->small_font_desc = NULL;
}
if (week_view->normal_cursor) {
g_object_unref (week_view->normal_cursor);
week_view->normal_cursor = NULL;
}
if (week_view->move_cursor) {
g_object_unref (week_view->move_cursor);
week_view->move_cursor = NULL;
}
if (week_view->resize_width_cursor) {
g_object_unref (week_view->resize_width_cursor);
week_view->resize_width_cursor = NULL;
}
if (week_view->scroll_by_week_notif_id) {
calendar_config_remove_notification (week_view->scroll_by_week_notif_id);
week_view->scroll_by_week_notif_id =
*o++ = '\r';
} else {
if (o[-1] == '\r')
o--;
}
} else if (flags & CAMEL_MIME_FILTER_CANON_CRLF) {
/* empty line */
*o++ = '\r';
}
*o++ = c;
start = inptr;
starto = o;
break;
} else
*o++ = c;
}
}
/* TODO: We should probably track if we end somewhere in the middle of a line,
otherwise we potentially backup a full line, which could be large */
/* we got to the end of the data without finding anything, backup to start and re-process next time around */
camel_mime_filter_backup(f, start, inend - start);
*out = f->outbuf;
*outlen = starto - f->outbuf;
*outprespace = f->outpre;
}
static void
complete(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
unsigned char *inptr, *inend;
char *o, *starto;
guint32 flags;
if (len)
filter(f, in, len, prespace, out, outlen, outprespace);
/* the data didn't contain an eol or was too short for "From ", we only need to check for "From" and add an eol */
if (f->backlen) {
inptr = (unsigned char *)f->backbuf;
inend = (unsigned char *)f->backbuf + f->backlen;
starto = o = *out + *outlen;
flags = ((CamelMimeFilterCanon *)f)->flags;
/* Check any embedded "From " */
if (f->backlen >= 5
&& (flags & CAMEL_MIME_FILTER_CANON_FROM)
&& strcmp(inptr, "From ") == 0) {
strcpy(o, "=46rom ");
o += 7;
inptr += 5;
}
/* copy the rest of it */
while (inptr < inend)
*o++ = *inptr++;
/* check to strip trailing space */
if (flags & CAMEL_MIME_FILTER_CANON_STRIP) {
while (o>starto && (o[-1] == ' ' || o[-1] == '\t' || o[-1]=='\r'))
o--;
}
/* check end of line canonicalisation */
if (o>starto) {
if (flags & CAMEL_MIME_FILTER_CANON_CRLF) {
if (o[-1] != '\r')
*o++ = '\r';
} else {
if (o[-1] == '\r')
o--;
}
}
/* and always finish with an eol */
*o++ = '\n';
*outlen = o - *out;
}
}
static void
reset (CamelMimeFilter *f)
{
/* no-op */
}
CamelMimeFilter *
camel_mime_filter_canon_new(guint32 flags)
{
CamelMimeFilterCanon *chomp = CAMEL_MIME_FILTER_CANON (camel_object_new (CAMEL_MIME_FILTER_CANON_TYPE));
chomp->flags = flags;
return (CamelMimeFilter *) chomp;
}