2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
4 * Copyright (c) 2007-2008 Juha Kautto (juha at xfce.org)
5 * Copyright (c) 2008 Colin Leroy (colin@colino.net)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "claws-features.h"
29 #include <glib/gi18n.h>
39 #include <glib/gprintf.h>
40 #include <gdk/gdkkeysyms.h>
44 #include "summaryview.h"
45 #include "vcalendar.h"
46 #include "vcal_folder.h"
47 #include "vcal_prefs.h"
48 #include "vcal_manager.h"
49 #include "common-views.h"
50 #include "vcal_meeting_gtk.h"
55 GtkAccelGroup *accel_group;
56 #if !GTK_CHECK_VERSION(2,12,0)
57 GtkTooltips *Tooltips;
64 GtkWidget *File_menu_new;
65 GtkWidget *File_menu_close;
67 GtkWidget *View_menu_refresh;
69 GtkWidget *Go_menu_today;
70 GtkWidget *Go_menu_prev;
71 GtkWidget *Go_menu_next;
74 GtkWidget *Create_toolbutton;
75 GtkWidget *Previous_toolbutton;
76 GtkWidget *Today_toolbutton;
77 GtkWidget *Next_toolbutton;
78 GtkWidget *Refresh_toolbutton;
79 GtkWidget *Close_toolbutton;
81 GtkWidget *StartDate_button;
82 GtkRequisition StartDate_button_req;
85 GtkWidget *day_view_vbox;
86 GtkWidget *scroll_win_h;
87 GtkWidget *dtable_h; /* header of day table */
88 GtkWidget *scroll_win;
89 GtkWidget *dtable; /* day table */
90 GtkRequisition hour_req;
92 GtkWidget *header[MAX_DAYS];
93 GtkWidget *element[24][MAX_DAYS];
94 GtkWidget *line[24][MAX_DAYS];
97 gdouble scroll_pos; /* remember the scroll position */
99 GdkColor bg1, bg2, line_color, bg_today, fg_sunday;
100 GList *apptw_list; /* keep track of appointments being updated */
104 GtkWidget *view_menu;
105 GtkWidget *event_menu;
106 GtkActionGroup *event_group;
107 GtkUIManager *ui_manager;
110 static gchar *get_locale_date(struct tm *tmdate)
112 gchar *d = g_malloc(100);
113 strftime(d, 99, "%x", tmdate);
117 static void set_scroll_position(day_win *dw)
119 GtkAdjustment *v_adj;
121 v_adj = gtk_scrolled_window_get_vadjustment(
122 GTK_SCROLLED_WINDOW(dw->scroll_win));
123 if (dw->scroll_pos > 0) /* we have old value */
124 gtk_adjustment_set_value(v_adj, dw->scroll_pos);
125 else if (dw->scroll_pos < 0)
126 /* default: let's try to start roughly from line 8 = 8 o'clock */
127 gtk_adjustment_set_value(v_adj, v_adj->upper/3);
128 gtk_adjustment_changed(v_adj);
131 static gboolean scroll_position_timer(gpointer user_data)
133 set_scroll_position((day_win *)user_data);
134 return(FALSE); /* only once */
137 static void get_scroll_position(day_win *dw)
139 GtkAdjustment *v_adj;
141 v_adj = gtk_scrolled_window_get_vadjustment(
142 GTK_SCROLLED_WINDOW(dw->scroll_win));
143 dw->scroll_pos = gtk_adjustment_get_value(v_adj);
146 void dw_close_window(day_win *dw)
148 vcal_view_set_summary_page(dw->Vbox, dw->selsig);
150 #if !(GTK_CHECK_VERSION(2,12,0))
151 gtk_object_destroy(G_OBJECT(dw->Tooltips));
157 static char *orage_tm_date_to_i18_date(struct tm *tm_date)
159 static char i18_date[32];
161 if (strftime(i18_date, 32, "%x", tm_date) == 0)
162 g_error("Orage: orage_tm_date_to_i18_date too long string in strftime");
166 static void changeSelectedDate(day_win *dw, gint day)
170 orage_move_day(&(dw->startdate), 1);
174 orage_move_day(&(dw->startdate), -1);
179 static gint on_Previous_clicked(GtkWidget *button, GdkEventButton *event,
182 int days = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dw->day_spin));
183 changeSelectedDate(dw, -days);
188 static gint on_Next_clicked(GtkWidget *button, GdkEventButton *event,
191 int days = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dw->day_spin));
192 changeSelectedDate(dw, +days);
197 static void dw_summary_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
198 gint column, day_win *dw)
200 MsgInfo *msginfo = gtk_cmctree_node_get_row_data(ctree, row);
201 int days = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dw->day_spin));
203 if (msginfo && msginfo->msgid) {
204 VCalEvent *event = vcal_manager_load_event(msginfo->msgid);
206 time_t t_first = mktime(&dw->startdate);
207 time_t t_start = icaltime_as_timet(icaltime_from_string(event->dtstart));
209 gboolean changed = FALSE;
210 GtkAdjustment *v_adj;
216 localtime_r(&t_start, &tm_start);
217 tm_start.tm_hour = tm_start.tm_min = tm_start.tm_sec = 0;
218 t_start = mktime(&tm_start);
220 while (t_start < t_first) {
221 changeSelectedDate(dw, -days);
222 t_first = mktime(&dw->startdate);
225 while (t_start > t_first + (days-1)*24*60*60) {
226 changeSelectedDate(dw, +days);
227 t_first = mktime(&dw->startdate);
231 t_start = icaltime_as_timet(icaltime_from_string(event->dtstart));
236 localtime_r(&t_start, &tm_start);
238 debug_print("changed from %s\n", event->summary);
239 v_adj = gtk_scrolled_window_get_vadjustment(
240 GTK_SCROLLED_WINDOW(dw->scroll_win));
245 localtime_r(&t_start, &tm_start);
246 if (tm_start.tm_hour > 2)
247 gtk_adjustment_set_value(v_adj,
248 (v_adj->upper-v_adj->page_size)/(24/(tm_start.tm_hour-2)));
250 gtk_adjustment_set_value(v_adj, 0);
251 gtk_adjustment_changed(v_adj);
255 vcal_manager_free_event(event);
259 static void day_view_new_meeting_cb(day_win *dw, gpointer data_i, gpointer data_s)
261 int offset = GPOINTER_TO_INT(data_i);
262 struct tm tm_date = dw->startdate;
263 int offset_h = offset % 1000;
264 int offset_d = (offset-offset_h) / 1000;
265 guint monthdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
266 int mon = tm_date.tm_mon;
268 if (((tm_date.tm_year%4) == 0) && (((tm_date.tm_year%100) != 0)
269 || ((tm_date.tm_year%400) == 0)))
272 if (offset_d > monthdays[mon]) {
273 while (tm_date.tm_mday > 1)
274 orage_move_day(&tm_date, 1);
275 offset_d -= monthdays[mon];
278 while (offset_d > tm_date.tm_mday) {
279 orage_move_day(&tm_date, 1);
281 while (offset_d < tm_date.tm_mday) {
282 orage_move_day(&tm_date, -1);
284 tm_date.tm_hour = offset_h;
285 vcal_meeting_create_with_start(NULL, &tm_date);
288 static void day_view_edit_meeting_cb(day_win *dw, gpointer data_i, gpointer data_s)
290 const gchar *uid = (gchar *)data_s;
291 vcal_view_select_event (uid, dw->item, TRUE,
292 G_CALLBACK(dw_summary_selected), dw);
295 static void day_view_cancel_meeting_cb(day_win *dw, gpointer data_i, gpointer data_s)
297 const gchar *uid = (gchar *)data_s;
298 vcalendar_cancel_meeting(dw->item, uid);
301 static void day_view_today_cb(day_win *dw, gpointer data_i, gpointer data_s)
303 time_t now = time(NULL);
305 localtime_r(&now, &tm_today);
307 while (tm_today.tm_wday != 1)
308 orage_move_day(&tm_today, -1);
310 dw->startdate = tm_today;
314 static void header_button_clicked_cb(GtkWidget *button, day_win *dw)
316 int offset = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "offset"));
318 day_view_new_meeting_cb(dw, GINT_TO_POINTER(offset), NULL);
321 static void on_button_press_event_cb(GtkWidget *widget
322 , GdkEventButton *event, gpointer *user_data)
324 day_win *dw = (day_win *)user_data;
325 gchar *uid = g_object_get_data(G_OBJECT(widget), "UID");
326 gpointer offset = g_object_get_data(G_OBJECT(widget), "offset");
328 if (event->button == 1) {
330 vcal_view_select_event (uid, dw->item, (event->type==GDK_2BUTTON_PRESS),
331 G_CALLBACK(dw_summary_selected), dw);
333 if (event->button == 3) {
334 g_object_set_data(G_OBJECT(dw->Vbox), "menu_win",
336 g_object_set_data(G_OBJECT(dw->Vbox), "menu_data_i",
338 g_object_set_data(G_OBJECT(dw->Vbox), "menu_data_s",
340 g_object_set_data(G_OBJECT(dw->Vbox), "new_meeting_cb",
341 day_view_new_meeting_cb);
342 g_object_set_data(G_OBJECT(dw->Vbox), "edit_meeting_cb",
343 day_view_edit_meeting_cb);
344 g_object_set_data(G_OBJECT(dw->Vbox), "cancel_meeting_cb",
345 day_view_cancel_meeting_cb);
346 g_object_set_data(G_OBJECT(dw->Vbox), "go_today_cb",
349 gtk_menu_popup(GTK_MENU(dw->event_menu),
350 NULL, NULL, NULL, NULL,
351 event->button, event->time);
353 gtk_menu_popup(GTK_MENU(dw->view_menu),
354 NULL, NULL, NULL, NULL,
355 event->button, event->time);
359 static void add_row(day_win *dw, VCalEvent *event, gint days)
361 gint row, start_row, end_row;
362 gint col, start_col, end_col, first_col, last_col;
363 gint height, start_height, end_height;
364 gchar *text, *tip, *start_date, *end_date;
365 GtkWidget *ev, *lab, *hb;
366 time_t t_start, t_end;
367 struct tm tm_first, tm_start, tm_end;
368 #if !(GTK_CHECK_VERSION(2,12,0))
369 GtkTooltips *tips = dw->Tooltips;
372 /* First clarify timings */
373 t_start = icaltime_as_timet(icaltime_from_string(event->dtstart));
374 if (event->dtend && *event->dtend)
375 t_end = icaltime_as_timet(icaltime_from_string(event->dtend));
385 localtime_r(&t_start, &tm_start);
386 localtime_r(&t_end, &tm_end);
387 tm_first = dw->startdate;
389 tm_first.tm_year += 1900;
390 tm_first.tm_mon += 1;
391 tm_start.tm_year += 1900;
392 tm_start.tm_mon += 1;
393 tm_end.tm_year += 1900;
396 start_col = orage_days_between(&tm_first, &tm_start)+1;
397 end_col = orage_days_between(&tm_first, &tm_end)+1;
401 if (start_col > days)
406 row = tm_start.tm_hour;
409 /* then add the appointment */
410 text = g_strdup(event->summary?event->summary : _("Unknown"));
411 ev = gtk_event_box_new();
412 lab = gtk_label_new(text);
413 gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.5);
414 gtk_label_set_ellipsize(GTK_LABEL(lab), PANGO_ELLIPSIZE_END);
415 gtk_container_add(GTK_CONTAINER(ev), lab);
418 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg1);
420 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg2);
421 if (dw->element[row][col] == NULL) {
422 hb = gtk_hbox_new(TRUE, 3);
423 dw->element[row][col] = hb;
426 hb = dw->element[row][col];
427 /* FIXME: set some real bar here to make it visible that we
428 * have more than 1 appointment here
431 if (orage_days_between(&tm_start, &tm_end) == 0)
432 tip = g_strdup_printf("%s\n%02d:%02d-%02d:%02d\n%s"
433 , text, tm_start.tm_hour, tm_start.tm_min
434 , tm_end.tm_hour, tm_end.tm_min, event->description);
436 /* we took the date in unnormalized format, so we need to do that now */
437 start_date = g_strdup(orage_tm_date_to_i18_date(&tm_start));
438 end_date = g_strdup(orage_tm_date_to_i18_date(&tm_end));
439 tip = g_strdup_printf("%s\n%s %02d:%02d - %s %02d:%02d\n%s"
441 , start_date, tm_start.tm_hour, tm_start.tm_min
442 , end_date, tm_end.tm_hour, tm_end.tm_min
443 , event->description);
447 CLAWS_SET_TIP(ev, tip);
449 gtk_box_pack_start(GTK_BOX(hb2), ev, FALSE, FALSE, 0);
450 gtk_box_pack_start(GTK_BOX(hb), hb2, TRUE, TRUE, 0);
452 gtk_box_pack_start(GTK_BOX(hb), ev, TRUE, TRUE, 0);
453 g_object_set_data_full(G_OBJECT(ev), "UID", g_strdup(event->uid), g_free);
454 g_object_set_data(G_OBJECT(ev), "offset", GINT_TO_POINTER(tm_start.tm_mday*1000 + tm_start.tm_hour));
455 g_signal_connect((gpointer)ev, "button-press-event"
456 , G_CALLBACK(on_button_press_event_cb), dw);
460 /* and finally draw the line to show how long the appointment is,
461 * but only if it is Busy type event (=availability != 0)
462 * and it is not whole day event */
464 height = dw->StartDate_button_req.height;
466 * same_date = !strncmp(start_ical_time, end_ical_time, 8);
471 first_col = start_col;
476 for (col = first_col; col <= last_col; col++) {
477 if (col == start_col)
478 start_row = tm_start.tm_hour;
482 end_row = tm_end.tm_hour;
485 for (row = start_row; row <= end_row; row++) {
486 if (row == tm_start.tm_hour && col == start_col)
487 start_height = tm_start.tm_min*height/60;
490 if (row == tm_end.tm_hour && col == end_col)
491 end_height = tm_end.tm_min*height/60;
494 dw->line[row][col] = build_line(1, start_height
495 , 2, end_height-start_height, dw->line[row][col]
502 static void app_rows(day_win *dw, FolderItem *item)
504 GSList *events = vcal_get_events_list(item);
506 int days = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dw->day_spin));
507 for (cur = events; cur ; cur = cur->next) {
508 VCalEvent *event = (VCalEvent *) (cur->data);
509 add_row(dw, event, days);
510 vcal_manager_free_event(event);
512 g_slist_free(events);
515 static void app_data(day_win *dw, FolderItem *item)
521 static void fill_days(day_win *dw, gint days, FolderItem *item, gint first_col_day)
523 gint row, col, height, width;
526 height = dw->StartDate_button_req.height;
527 width = dw->StartDate_button_req.width;
529 /* first clear the structure */
530 for (col = 1; col < days+1; col++) {
531 dw->header[col] = NULL;
532 for (row = 0; row < 24; row++) {
533 dw->element[row][col] = NULL;
534 /* gdk_draw_rectangle(, , , left_x, top_y, width, height); */
535 dw->line[row][col] = build_line(0, 0, 3, height, NULL
542 for (col = 1; col < days+1; col++) {
543 hb = gtk_hbox_new(FALSE, 0);
544 /* check if we have full day events and put them to header */
545 if (dw->header[col]) {
546 gtk_box_pack_start(GTK_BOX(hb), dw->header[col], TRUE, TRUE, 0);
547 gtk_widget_set_size_request(hb, width, -1);
550 ev = gtk_event_box_new();
551 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg2);
552 gtk_box_pack_start(GTK_BOX(hb), ev, TRUE, TRUE, 0);
554 gtk_table_attach(GTK_TABLE(dw->dtable_h), hb, col, col+1, 1, 2
555 , (GTK_FILL), (0), 0, 0);
558 for (row = 0; row < 24; row++) {
559 hb = gtk_hbox_new(FALSE, 0);
561 gtk_widget_set_size_request(hb, width, -1);
562 if (dw->element[row][col]) {
563 gtk_box_pack_start(GTK_BOX(hb), dw->line[row][col]
565 gtk_box_pack_start(GTK_BOX(hb), dw->element[row][col]
567 gtk_widget_set_size_request(hb, width, -1);
570 ev = gtk_event_box_new();
571 g_object_set_data(G_OBJECT(ev), "offset", GINT_TO_POINTER(first_col_day*1000 + row));
572 g_signal_connect((gpointer)ev, "button-press-event"
573 , G_CALLBACK(on_button_press_event_cb), dw);
575 name = gtk_label_new(" ");
576 gtk_container_add(GTK_CONTAINER(ev), name);
579 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg1);
581 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg2);
582 gtk_box_pack_start(GTK_BOX(hb), dw->line[row][col]
584 gtk_box_pack_start(GTK_BOX(hb), ev, TRUE, TRUE, 0);
586 gtk_table_attach(GTK_TABLE(dw->dtable), hb, col, col+1, row, row+1
587 , (GTK_FILL), (0), 0, 0);
593 static void build_day_view_header(day_win *dw, char *start_date)
595 GtkWidget *hbox, *label, *space_label;
596 SummaryView *summaryview = NULL;
597 int avail_w = 0, avail_d = 0;
599 hbox = gtk_hbox_new(FALSE, 0);
601 label = gtk_label_new(_("Start"));
602 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
604 /* start date button */
605 dw->StartDate_button = gtk_button_new();
606 gtk_box_pack_start(GTK_BOX(hbox), dw->StartDate_button, FALSE, FALSE, 0);
608 space_label = gtk_label_new(" ");
609 gtk_box_pack_start(GTK_BOX(hbox), space_label, FALSE, FALSE, 0);
611 space_label = gtk_label_new(" ");
612 gtk_box_pack_start(GTK_BOX(hbox), space_label, FALSE, FALSE, 0);
614 label = gtk_label_new(_("Show"));
615 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
617 /* show days spin = how many days to show */
618 dw->day_spin = gtk_spin_button_new_with_range(1, MAX_DAYS, 1);
619 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(dw->day_spin), TRUE);
620 gtk_widget_set_size_request(dw->day_spin, 40, -1);
621 gtk_box_pack_start(GTK_BOX(hbox), dw->day_spin, FALSE, FALSE, 0);
622 label = gtk_label_new(_("days"));
623 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
625 space_label = gtk_label_new(" ");
626 gtk_box_pack_start(GTK_BOX(hbox), space_label, FALSE, FALSE, 0);
629 gtk_button_set_label(GTK_BUTTON(dw->StartDate_button)
630 , (const gchar *)start_date);
631 gtk_widget_size_request(dw->StartDate_button, &dw->StartDate_button_req);
632 dw->StartDate_button_req.width += dw->StartDate_button_req.width/10;
633 label = gtk_label_new("00");
634 gtk_widget_size_request(label, &dw->hour_req);
636 if (mainwindow_get_mainwindow()) {
637 GtkAllocation allocation;
638 summaryview = mainwindow_get_mainwindow()->summaryview;
639 allocation = summaryview->mainwidget_book->allocation;
641 avail_w = allocation.width - 20 - 2*(dw->hour_req.width);
642 avail_d = avail_w / dw->StartDate_button_req.width;
646 gtk_widget_set_size_request(dw->StartDate_button, avail_w / avail_d, -1);
647 gtk_widget_size_request(dw->StartDate_button, &dw->StartDate_button_req);
652 gtk_spin_button_set_value(GTK_SPIN_BUTTON(dw->day_spin), avail_d);
656 static void build_day_view_colours(day_win *dw)
659 GdkColormap *pic1_cmap;
660 GtkWidget *ctree = NULL;
661 def_style = gtk_widget_get_default_style();
662 pic1_cmap = gdk_colormap_get_system();
664 if (mainwindow_get_mainwindow()) {
665 ctree = mainwindow_get_mainwindow()->summaryview->ctree;
668 dw->bg1 = ctree->style->bg[GTK_STATE_NORMAL];
669 dw->bg2 = ctree->style->bg[GTK_STATE_NORMAL];
671 dw->bg1 = def_style->bg[GTK_STATE_NORMAL];
672 dw->bg2 = def_style->bg[GTK_STATE_NORMAL];
674 dw->bg1.red += (dw->bg1.red < 63000 ? 2000 : -2000);
675 dw->bg1.green += (dw->bg1.green < 63000 ? 2000 : -2000);
676 dw->bg1.blue += (dw->bg1.blue < 63000 ? 2000 : -2000);
677 gdk_colormap_alloc_color(pic1_cmap, &dw->bg1, FALSE, TRUE);
679 dw->bg2.red += (dw->bg2.red > 1000 ? -1000 : 1000);
680 dw->bg2.green += (dw->bg2.green > 1000 ? -1000 : 1000);
681 dw->bg2.blue += (dw->bg2.blue > 1000 ? -1000 : 1000);
682 gdk_colormap_alloc_color(pic1_cmap, &dw->bg2, FALSE, TRUE);
684 if (!gdk_color_parse("white", &dw->line_color)) {
685 dw->line_color.red = 239 * (65535/255);
686 dw->line_color.green = 235 * (65535/255);
687 dw->line_color.blue = 230 * (65535/255);
690 if (!gdk_color_parse("blue", &dw->fg_sunday)) {
691 g_warning("color parse failed: red\n");
692 dw->fg_sunday.red = 10 * (65535/255);
693 dw->fg_sunday.green = 10 * (65535/255);
694 dw->fg_sunday.blue = 255 * (65535/255);
697 if (!gdk_color_parse("gold", &dw->bg_today)) {
698 g_warning("color parse failed: gold\n");
699 dw->bg_today.red = 255 * (65535/255);
700 dw->bg_today.green = 215 * (65535/255);
701 dw->bg_today.blue = 115 * (65535/255);
705 dw->fg_sunday.red = (dw->fg_sunday.red + ctree->style->fg[GTK_STATE_SELECTED].red)/2;
706 dw->fg_sunday.green = (dw->fg_sunday.green + ctree->style->fg[GTK_STATE_SELECTED].red)/2;
707 dw->fg_sunday.blue = (3*dw->fg_sunday.blue + ctree->style->fg[GTK_STATE_SELECTED].red)/4;
708 dw->bg_today.red = (3*dw->bg_today.red + ctree->style->bg[GTK_STATE_NORMAL].red)/4;
709 dw->bg_today.green = (3*dw->bg_today.green + ctree->style->bg[GTK_STATE_NORMAL].red)/4;
710 dw->bg_today.blue = (3*dw->bg_today.blue + ctree->style->bg[GTK_STATE_NORMAL].red)/4;
713 gdk_colormap_alloc_color(pic1_cmap, &dw->line_color, FALSE, TRUE);
714 gdk_colormap_alloc_color(pic1_cmap, &dw->fg_sunday, FALSE, TRUE);
715 gdk_colormap_alloc_color(pic1_cmap, &dw->bg_today, FALSE, TRUE);
718 static void fill_hour(day_win *dw, gint col, gint row, char *text)
720 GtkWidget *name, *ev;
722 ev = gtk_event_box_new();
723 name = gtk_label_new(text);
724 gtk_container_add(GTK_CONTAINER(ev), name);
726 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg1);
728 gtk_widget_modify_bg(ev, GTK_STATE_NORMAL, &dw->bg2);
729 gtk_widget_set_size_request(ev, dw->hour_req.width
730 , dw->StartDate_button_req.height);
732 gtk_table_attach(GTK_TABLE(dw->dtable), ev, col, col+1, row, row+1
733 , (GTK_FILL), (0), 0, 0);
734 else /* special, needed for header table full day events */
735 gtk_table_attach(GTK_TABLE(dw->dtable_h), ev, col, col+1, row, row+1
736 , (GTK_FILL), (0), 0, 0);
739 static void build_day_view_table(day_win *dw)
741 gint days; /* number of days to show */
742 int year, month, day;
744 GtkWidget *label, *button;
745 char text[5+1], *date, *today;
746 struct tm tm_date, tm_today;
747 guint monthdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
749 time_t t = time(NULL);
752 gint first_col_day = -1;
753 #if !(GTK_CHECK_VERSION(2,12,0))
754 GtkTooltips *tips = dw->Tooltips;
761 localtime_r(&t, &tm_today);
762 days = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dw->day_spin));
763 today = get_locale_date(&tm_today);
764 /****** header of day table = days columns ******/
765 dw->scroll_win_h = gtk_scrolled_window_new(NULL, NULL);
766 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dw->scroll_win_h)
767 , GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
768 gtk_box_pack_start(GTK_BOX(dw->Vbox), dw->scroll_win_h
770 dw->day_view_vbox = gtk_vbox_new(FALSE, 0);
771 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(dw->scroll_win_h)
772 , dw->day_view_vbox);
774 gtk_container_add(GTK_CONTAINER(dw->scroll_win_h), dw->day_view_vbox);
776 /* row 1= day header buttons
777 * row 2= full day events after the buttons */
778 dw->dtable_h = gtk_table_new(2 , days+2, FALSE);
779 gtk_box_pack_start(GTK_BOX(dw->day_view_vbox), dw->dtable_h
782 tm_date = dw->startdate;
784 year = tm_date.tm_year + 1900;
785 month = tm_date.tm_mon;
786 day = tm_date.tm_mday;
787 if (((tm_date.tm_year%4) == 0) && (((tm_date.tm_year%100) != 0)
788 || ((tm_date.tm_year%400) == 0)))
793 dw->Previous_toolbutton = gtk_event_box_new();
794 gtk_event_box_set_visible_window(GTK_EVENT_BOX(dw->Previous_toolbutton), FALSE);
795 gtk_container_set_border_width(GTK_CONTAINER(dw->Previous_toolbutton), 0);
796 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
797 gtk_container_add(GTK_CONTAINER(dw->Previous_toolbutton), arrow);
798 gtk_table_attach(GTK_TABLE(dw->dtable_h), dw->Previous_toolbutton, i, i+1, 0, 1
799 , (GTK_FILL), (0), 0, 0);
800 gtk_widget_show_all(dw->Previous_toolbutton);
801 g_signal_connect((gpointer)dw->Previous_toolbutton, "button_release_event"
802 , G_CALLBACK(on_Previous_clicked), dw);
803 tip = g_strdup_printf("Back %d days", days);
804 CLAWS_SET_TIP(dw->Previous_toolbutton, tip);
806 for (i = 1; i < days+1; i++) {
808 strftime(tip, 99, "%A %d %B %Y", &tm_date);
809 if (first_col_day == -1)
810 first_col_day = tm_date.tm_mday;
811 date = get_locale_date(&tm_date);
812 button = gtk_button_new();
813 gtk_button_set_label(GTK_BUTTON(button), date);
814 if (strcmp(today, date) == 0) {
815 gtk_widget_modify_bg(button, GTK_STATE_NORMAL, &dw->bg_today);
818 if (tm_date.tm_wday % 7 == 0) {
819 label = gtk_bin_get_child(GTK_BIN(button));
820 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &dw->fg_sunday);
822 CLAWS_SET_TIP(button, tip);
824 gtk_widget_set_size_request(button, dw->StartDate_button_req.width, -1);
825 g_signal_connect((gpointer)button, "clicked"
826 , G_CALLBACK(header_button_clicked_cb), dw);
827 g_object_set_data(G_OBJECT(button), "offset", GINT_TO_POINTER(tm_date.tm_mday*1000));
828 gtk_table_attach(GTK_TABLE(dw->dtable_h), button, i, i+1, 0, 1
829 , (GTK_FILL), (0), 0, 0);
831 if (++tm_date.tm_mday == (monthdays[tm_date.tm_mon]+1)) {
832 if (++tm_date.tm_mon == 12) {
838 ++tm_date.tm_wday; tm_date.tm_wday %=7;
842 dw->Next_toolbutton = gtk_event_box_new();
843 gtk_event_box_set_visible_window(GTK_EVENT_BOX(dw->Next_toolbutton), FALSE);
844 gtk_container_set_border_width(GTK_CONTAINER(dw->Next_toolbutton), 0);
845 arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
846 gtk_container_add(GTK_CONTAINER(dw->Next_toolbutton), arrow);
847 gtk_table_attach(GTK_TABLE(dw->dtable_h), dw->Next_toolbutton, i, i+1, 0, 1
848 , (GTK_FILL), (0), 0, 0);
849 gtk_widget_show_all(dw->Next_toolbutton);
850 g_signal_connect((gpointer)dw->Next_toolbutton, "button_release_event"
851 , G_CALLBACK(on_Next_clicked), dw);
852 tip = g_strdup_printf("Forward %d days", days);
853 CLAWS_SET_TIP(dw->Next_toolbutton, tip);
857 /****** body of day table ******/
858 dw->scroll_win = gtk_scrolled_window_new(NULL, NULL);
859 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dw->scroll_win)
861 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dw->scroll_win)
862 , GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
863 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(dw->scroll_win)
864 , GTK_CORNER_TOP_LEFT);
865 gtk_box_pack_start(GTK_BOX(dw->day_view_vbox), dw->scroll_win
867 vp = gtk_viewport_new(NULL, NULL);
868 gtk_viewport_set_shadow_type(GTK_VIEWPORT(vp), GTK_SHADOW_NONE);
869 gtk_container_add(GTK_CONTAINER(dw->scroll_win), vp);
870 dw->dtable = gtk_table_new(24, days+2, FALSE);
871 gtk_container_add(GTK_CONTAINER(vp), dw->dtable);
873 gtk_widget_show_all(dw->dtable_h);
874 /* hours column = hour rows */
875 for (i = 0; i < 24; i++) {
876 g_sprintf(text, "%02d", i);
877 /* ev is needed for background colour */
878 fill_hour(dw, 0, i, text);
879 fill_hour(dw, days+1, i, text);
881 fill_days(dw, days, dw->item, first_col_day);
884 void refresh_day_win(day_win *dw)
886 get_scroll_position(dw);
887 gtk_widget_destroy(dw->scroll_win_h);
888 build_day_view_table(dw);
889 gtk_widget_show_all(dw->scroll_win_h);
890 /* I was not able to get this work without the timer. Ugly yes, but
891 * it works and does not hurt - much */
892 g_timeout_add(100, (GSourceFunc)scroll_position_timer, (gpointer)dw);
895 day_win *create_day_win(FolderItem *item, struct tm tmdate)
898 char *start_date = get_locale_date(&tmdate);
900 /* initialisation + main window + base vbox */
901 dw = g_new0(day_win, 1);
902 dw->scroll_pos = -1; /* not set */
903 #if !(GTK_CHECK_VERSION(2,12,0))
906 dw->accel_group = gtk_accel_group_new();
908 while (tmdate.tm_wday != 1)
909 orage_move_day(&tmdate, -1);
911 dw->startdate = tmdate;
912 dw->startdate.tm_hour = 0;
913 dw->startdate.tm_min = 0;
914 dw->startdate.tm_sec = 0;
915 dw->Vbox = gtk_vbox_new(FALSE, 0);
918 build_day_view_colours(dw);
919 build_day_view_header(dw, start_date);
920 build_day_view_table(dw);
921 gtk_widget_show_all(dw->Vbox);
922 dw->selsig = vcal_view_set_calendar_page(dw->Vbox,
923 G_CALLBACK(dw_summary_selected), dw);
924 vcal_view_create_popup_menus(dw->Vbox, &dw->view_menu,
925 &dw->event_menu, &dw->event_group,
928 g_timeout_add(100, (GtkFunction)scroll_position_timer, (gpointer)dw);