/* * openmoko-dates -- OpenMoko Calendar Application * * Authored by Chris Lord * * Copyright (C) 2006-2007 OpenMoko Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser Public License as published by * the Free Software Foundation; version 2 of the license. * * 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 Public License for more details. * * Current Version: $Rev$ ($Date$) [$Author$] */ #include #include #include #include #include #include "dates.h" #include "dates-utils.h" #include "dates-list.h" #include "dates-week.h" #include "dates-month.h" #include "dates-view.h" static const GdkColor tango[] = { { 0, 0xed00, 0xd400, 0x0000 }, /* Butter */ { 0, 0xf500, 0x7900, 0x0000 }, /* Orange */ { 0, 0xc100, 0x7d00, 0x1100 }, /* Chocolate */ { 0, 0x7300, 0xd200, 0x1600 }, /* Chameleon */ { 0, 0x3400, 0x6500, 0xa400 }, /* Sky Blue */ { 0, 0x7500, 0x5000, 0x7b00 }, /* Plum */ { 0, 0xcc00, 0x0000, 0x0000 }, /* Scarlet Red */ { 0, 0xba00, 0xdb00, 0xb600 }, /* Aluminium */ }; static void dates_notebook_add_page_with_icon (GtkWidget *notebook, GtkWidget *child, const gchar *icon_name, int padding) { GtkWidget *icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); GtkWidget *align = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (align), padding, padding, padding, padding); gtk_container_add (GTK_CONTAINER (align), icon); gtk_widget_show_all (align); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child, align); gtk_container_child_set (GTK_CONTAINER (notebook), child, "tab-expand", TRUE, NULL); } static void delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { DatesData *data = (DatesData *)user_data; if (data->time_idle) { g_source_remove (data->time_idle); data->time_idle = 0; } while (data->models) { g_object_unref (G_OBJECT (data->models->data)); data->models = g_list_delete_link (data->models, data->models); } while (data->views) { g_object_unref (G_OBJECT (data->views->data)); data->views = g_list_delete_link (data->views, data->views); } while (data->stores) { g_object_unref (G_OBJECT (data->stores->data)); data->stores = g_list_delete_link (data->stores, data->stores); } if (data->start) { g_object_unref (data->start); data->start = NULL; } if (data->end) { g_object_unref (data->end); data->end = NULL; } if (data->location) { g_free (data->location); data->location = NULL; } gtk_main_quit (); } static gboolean repopulate_category_list (DatesData *data) { GList *models; /* Empty list */ while (data->category_list) { g_free (data->category_list->data); data->category_list = g_list_delete_link (data->category_list, data->category_list); } g_hash_table_remove_all (data->category_color_hash); /* Get categories from currently visible events (unfiltered) */ for (models = data->models; models; models = models->next) { GtkTreeIter iter; GtkTreeModel *model = (GtkTreeModel *)models->data; if (gtk_tree_model_get_iter_first (model, &iter)) do { gint cat_n; gchar **categories; gtk_tree_model_get (model, &iter, JANA_GTK_EVENT_STORE_COL_CATEGORIES, &categories, -1); if (!categories) continue; for (cat_n = 0; categories[cat_n]; cat_n++) { /* Don't add empty categories */ if (categories[cat_n][0] == '\0') continue; /* Check for category and add if we haven't * already. */ if (!g_list_find_custom (data->category_list, categories[cat_n], (GCompareFunc)strcmp)) { guint hash; GdkColor *color; data->category_list = g_list_insert_sorted ( data->category_list, g_strdup ( categories[cat_n]), (GCompareFunc) g_utf8_collate); /* Generate a unique colour to * represent the colour */ /* Start off by indexing into the Tango * palette, then use the string hash * as an offset for the RGB components */ color = gdk_color_copy ( &tango[g_unichar_tolower ( categories[cat_n][0]) % G_N_ELEMENTS (tango)]); hash = g_str_hash (categories[cat_n]); color->red += (hash & 0xFF0000) >> 17; color->green += (hash & 0xFF00) >> 1; color->blue += (hash & 0xFF) << 7; g_hash_table_insert ( data->category_color_hash, g_strdup (categories[cat_n]), color); } } g_strfreev (categories); } while (gtk_tree_model_iter_next (model, &iter)); } dates_utils_update_category_bars (data); data->category_idle = 0; /* Redraw widgets that show events (required for colours) */ gtk_widget_queue_draw (data->list_view); gtk_widget_queue_draw (data->week_view); gtk_widget_queue_draw (data->week_preview_box); gtk_widget_queue_draw (data->month_view); gtk_widget_queue_draw (data->month_list_view); return FALSE; } static void row_inserted_cb (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, DatesData *data) { if (!data->category_idle) data->category_idle = g_idle_add ((GSourceFunc)repopulate_category_list, data); } static void row_changed_cb (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, DatesData *data) { if (!data->category_idle) data->category_idle = g_idle_add ((GSourceFunc)repopulate_category_list, data); } static void row_deleted_cb (GtkTreeModel *tree_model, GtkTreePath *path, DatesData *data) { if (!data->category_idle) data->category_idle = g_idle_add ((GSourceFunc)repopulate_category_list, data); } static void opened_cb (JanaStore *store, DatesData *data) { JanaStoreView *store_view; JanaGtkEventStore *gtk_store; store_view = jana_store_get_view (store); jana_store_view_set_range (store_view, data->start, data->end); gtk_store = jana_gtk_event_store_new_full (store_view, jana_time_get_offset (data->start)); /* Add stores to views */ jana_gtk_event_list_add_store (JANA_GTK_EVENT_LIST (data->list_view), gtk_store); jana_gtk_day_view_add_store (JANA_GTK_DAY_VIEW (data->week_view), gtk_store); jana_gtk_month_view_add_store (JANA_GTK_MONTH_VIEW (data->month_view), gtk_store); jana_gtk_event_list_add_store (JANA_GTK_EVENT_LIST ( data->month_list_view), gtk_store); data->stores = g_list_prepend (data->stores, store); data->views = g_list_prepend (data->views, store_view); data->models = g_list_prepend (data->models, gtk_store); /* Listen to row insertion/deletion signals */ g_signal_connect (gtk_store, "row-inserted", G_CALLBACK (row_inserted_cb), data); g_signal_connect (gtk_store, "row-changed", G_CALLBACK (row_changed_cb), data); g_signal_connect (gtk_store, "row-deleted", G_CALLBACK (row_deleted_cb), data); jana_store_view_start (store_view); } static gboolean startup_cb (DatesData *data) { JanaStore *store; store = jana_ecal_store_new (JANA_COMPONENT_EVENT); g_signal_connect (G_OBJECT (store), "opened", G_CALLBACK (opened_cb), data); jana_store_open (store); return FALSE; } static void switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, DatesData *data) { data->last_page = gtk_notebook_get_current_page (notebook); } static gboolean time_update_idle (gpointer user_data) { DatesData *data = (DatesData *)user_data; JanaTime *now = jana_ecal_utils_time_now (data->location); jana_gtk_day_view_set_highlighted_time ( JANA_GTK_DAY_VIEW (data->week_view), now); jana_gtk_month_view_set_highlighted_time ( JANA_GTK_MONTH_VIEW (data->month_view), now); g_object_unref (now); return TRUE; } int main (int argc, char **argv) { DatesData data; GtkWidget *child; gtk_init (&argc, &argv); data.editing = FALSE; data.models = NULL; data.views = NULL; data.stores = NULL; data.selected_store = NULL; data.selected_event = NULL; data.search = NULL; data.category = NULL; data.category_list = NULL; data.category_idle = 0; data.category_color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)gdk_color_free); data.list_time = NULL; data.week_time = NULL; data.title_idle = 0; /* TODO: Get local time-zone */ data.location = jana_ecal_utils_guess_location (); data.start = jana_ecal_utils_time_today (data.location); data.end = jana_time_duplicate (data.start); /* Create main notebook */ data.window = gtk_window_new (GTK_WINDOW_TOPLEVEL); data.notebook = gtk_notebook_new (); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (data.notebook), GTK_POS_BOTTOM); /* Create child pages */ /* Event list page */ child = dates_create_list_page (&data); dates_notebook_add_page_with_icon (data.notebook, child, "stock_calendar-view-list", 6); gtk_widget_show (child); /* Week view page */ child = dates_create_week_page (&data); dates_notebook_add_page_with_icon (data.notebook, child, "stock_calendar-view-work-week", 6); gtk_widget_show (child); /* Month view page */ child = dates_create_month_page (&data); dates_notebook_add_page_with_icon (data.notebook, child, "stock_calendar-view-month", 6); gtk_widget_show (child); /* View/edit page */ child = dates_create_view_page (&data); dates_notebook_add_page_with_icon (data.notebook, child, GTK_STOCK_EDIT, 6); gtk_widget_show (child); dates_utils_update_category_bars (&data); #if GLIB_CHECK_VERSION(2,14,0) data.time_idle = g_timeout_add_seconds (60, time_update_idle, &data); #else data.time_idle = g_timeout_add (60000, time_update_idle, &data); #endif time_update_idle (&data); /* Add notebook to window */ gtk_container_add (GTK_CONTAINER (data.window), data.notebook); gtk_widget_show (data.notebook); g_signal_connect (data.notebook, "switch-page", G_CALLBACK (switch_page_cb), &data); g_signal_connect (data.window, "delete-event", G_CALLBACK (delete_event_cb), &data); #if 0 /* Force theme settings */ g_object_set (gtk_settings_get_default (), "gtk-theme-name", "openmoko-standard-2", /* Moko */ "gtk-icon-theme-name", "openmoko-standard", "gtk-xft-dpi", 285 * 1024, "gtk-font-name", "Sans 6", NULL); gtk_window_set_default_size (GTK_WINDOW (data.window), 480, 600); #endif dates_utils_title_idle_cb (&data); gtk_widget_show (data.window); g_idle_add ((GSourceFunc)startup_cb, &data); gtk_main (); return 0; }