Logo Search packages:      
Sourcecode: dates version File versions


/* -*- mode:C; c-file-style:"linux"; tab-width:8; -*- */
 *  Dates - An electronic calendar optimised for embedded devices.
 *  Principal author    : Chris Lord <chris@o-hand.com>
 *  Maemo port          : Tomas Frydrych <tf@o-hand.com>
 *  Copyright (c) 2005 - 2006 OpenedHand Ltd - http://o-hand.com
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  GNU General Public License for more details.

#include <string.h>
#include <math.h>
#include <libecal/e-cal-time-util.h>
#include <libical/icaltime.h>
#include <gconf/gconf-client.h>

#include "dates_types.h"
#include "dates_platform.h"
#include "dates_callbacks.h"

#include "gconf-bridge.h"

static GtkWidget *
create_dates_view ()
      GtkWidget *widget;
      widget = dates_view_new ();
      /* TODO: This is temporary until the widget sizes itself properly */
      gtk_widget_set_size_request (widget, 240, 240);
      gtk_widget_show (widget);
      return widget;

static void
dates_autoselect_calendars (DatesData *d, ESourceList * cal_list)
      GSList *selected_list;

      if (!cal_list)
      selected_list = gconf_client_get_list (gconf_client_get_default (),
                                     GCONF_VALUE_STRING, NULL);

      if (!selected_list) {
            /* select all available calendars */
            GSList *list = NULL, *groups, *g;
            groups = e_source_list_peek_groups (cal_list);
            for (g = groups; g; g = g->next) {
                  GSList *sources, *s;
                  sources =
                        e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
                  for (s = sources; s; s = s->next) {
                        ESource *source = E_SOURCE (s->data);
                        ECal *ecal;
                        gchar * uid;
                        ecal = dates_load_esource (source,
                                             NULL, d);
                        if (!ecal)

                        uid = (gchar *)e_source_peek_uid (e_cal_get_source (ecal));
                        list = g_slist_prepend (list, uid);

            if (list)
                  gconf_client_set_list (gconf_client_get_default (),
                                     list, NULL);

static gboolean
dates_load_calendars (DatesData *d)
      ESourceList *cal_list;
      /* Load calendars */
      cal_list = e_source_list_new_for_gconf_default (CALENDAR_GCONF_SOURCES);

      if (!cal_list) {
            g_error ("Error loading ESource list");
            return FALSE;

      dates_autoselect_calendars (d, cal_list);
      if (!e_source_list_peek_groups (cal_list)) {
            g_warning ("No groups found");
            g_object_unref (cal_list);
            return FALSE;

      g_signal_connect (G_OBJECT (cal_list), "changed",
            G_CALLBACK (dates_sources_changed_cb), d);
      dates_update_calendars (cal_list, d);
      return TRUE;

/* Thanks to GnuCash to find out how to do this */
static void
dates_autoconnect (const gchar *handler_name, GObject *object,
                  const gchar *signal_name, const gchar *signal_data,
                  GObject *connect_object, gboolean after,
                  gpointer user_data)
      static GModule *symbols = NULL;
      GCallback func;
      GCallback *pfunc = &func;
      if (!symbols) {
            symbols = g_module_open(NULL, 0);
      if (!g_module_symbol (symbols, handler_name, (gpointer *)pfunc)) {
            g_warning ("Handler '%s' not found.", handler_name);

      if (connect_object) {
            if (after)
                  g_signal_connect_object (object, signal_name,
                        func, connect_object, G_CONNECT_AFTER);
                  g_signal_connect_object (object, signal_name,
                        func, connect_object, 0);
      } else {
            if (after)
                  g_signal_connect_after(object, signal_name,
                        func, user_data);
                  g_signal_connect(object, signal_name, func, user_data);

static gboolean
dates_selected_calendars_filter_func (GtkTreeModel *model,
                              GtkTreePath *path,
                              GtkTreeIter *iter,
                              gpointer data)
      GSList **list;
      gboolean selected;
      ECal *ecal;
      gchar *uid;

      gtk_tree_model_get (model, iter,
                  COL_SELECTED, &selected,
                  COL_CALPTR, &ecal, -1);
      uid = (gchar *)e_source_peek_uid (e_cal_get_source (ecal));
      list = (GSList **)data;
      if (selected) *list = g_slist_prepend (*list, uid);

      return FALSE; /* foreach goes on */

static gboolean
dates_sel_or_read_only_filter_func (GtkTreeModel *model,
                            GtkTreeIter *iter,
                            gpointer user_data)
      gboolean not_read_only, selected;

      gtk_tree_model_get (model, iter,
                  COL_SELECTED, &selected,
                  COL_NOTREADONLY, &not_read_only, -1);
      if ((!not_read_only) || (!selected))
            return FALSE;
            return TRUE;

static void
dates_toggle_renderer_toggled_cb (GtkCellRendererToggle *renderer,
                          gchar *path_str,
                          gpointer userdata)
      GtkTreeModel *model;
      GtkTreeIter iter;
      gboolean toggle;
      GSList *selected;

      model = GTK_TREE_MODEL (userdata);
      gtk_tree_model_get_iter_from_string (model, &iter, path_str);
      gtk_tree_model_get (model, &iter,
                      COL_SELECTED, &toggle, -1);
      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
                      COL_SELECTED, !toggle, -1);

      selected = NULL;
      gtk_tree_model_foreach (model, dates_selected_calendars_filter_func,

      /* Changing the GConf selected calendars string will cause the
       * calendars to be updated (we're listening to this GConf value).
      gconf_client_set_list (gconf_client_get_default (),
            selected, NULL);

static void
connect_callbacks_view (DatesData * d)
      g_signal_connect (G_OBJECT (d->view), "date_changed",
                    G_CALLBACK (dates_date_changed_cb), d);
      g_signal_connect (G_OBJECT (d->view), "event_selected",
                    G_CALLBACK (dates_event_selected_cb), d);
      g_signal_connect (G_OBJECT (d->view), "event_moved",
                    G_CALLBACK (dates_event_moved_cb), d);
      g_signal_connect (G_OBJECT (d->view), "event_sized",
                    G_CALLBACK (dates_event_sized_cb), d);
      g_signal_connect (G_OBJECT (d->view), "event_activated",
                    G_CALLBACK (dates_open_cb), d);
      g_signal_connect (G_OBJECT (d->view), "button_press_event",
                    G_CALLBACK (dates_button_press_cb), d);
      g_signal_connect (G_OBJECT (d->view), "key_press_event",
                    G_CALLBACK (dates_cal_key_press_cb), d);
      g_signal_connect (G_OBJECT (d->view), "ical_drop",
                    G_CALLBACK (dates_ical_drop_cb), d);

main (int argc, char **argv)
      GtkWidget *widget;
      DatesData data;
      GtkTreeModel *filter;
      GConfClient *client;
      GConfBridge *bridge;
      GOptionContext *context;
      static gint plug = 0;
#ifdef DEBUG
      const gchar *debug;
      static GOptionEntry entries[] = {
            { "plug", 'p', 0, G_OPTION_ARG_INT, &plug,
                  "Socket ID of an XEmbed socket to plug into", NULL },
            { NULL }

      memset (&data, 0, sizeof (DatesData));
      /* Initialise the i18n support code */
      bindtextdomain (GETTEXT_PACKAGE, DATES_LOCALE_DIR);;
      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
      textdomain (GETTEXT_PACKAGE);

      context = g_option_context_new (" - A light-weight, zooming calendar");
      g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
      g_option_context_add_group (context, gtk_get_option_group (TRUE));
      g_option_context_parse (context, &argc, &argv, NULL);

      /* NOTE: No need to call gtk_init after the g_option_context_parse */
      /* gtk_init (&argc, &argv); */

#ifdef DEBUG
      debug = g_getenv ("DATES_DEBUG");
      if (debug)
            data.debug = g_parse_debug_string (debug,
                  dates_debug_keys, G_N_ELEMENTS (dates_debug_keys));

      /* Set critical errors to close application */
      /*g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);*/

      data.view = DATES_VIEW (create_dates_view ());

      connect_callbacks_view (&data);

      dates_platform_init (&data);
      dates_platform_create_ui (&data);
      client = gconf_client_get_default ();
      if (!client)
            g_error ("Failed to retrieve default gconf client");
      data.zoom    = gconf_client_get_int (client, DATES_GCONF_ZOOM, NULL);
      data.comp    = NULL;
      data.widgets = NULL;
      data.waiting = NONE;

      if (data.zoom == 0) {
            data.zoom = 3;
            gtk_widget_set_sensitive (data.TBZoomIn, FALSE);
      } else if (data.zoom == 3) {
            gtk_widget_set_sensitive (data.TBZoomIn, FALSE);
      } else if (data.zoom == 16) {
            gtk_widget_set_sensitive (data.TBZoomOut, FALSE);

      gtk_widget_set_sensitive (data.TBDelete, FALSE);
        /* Perhaps in a future version? */
        /* dates_view_set_use_list (data.view, TRUE);*/

      dates_zoom_change (data.zoom, data.view);

      /* Load calendars */
      data.cal_list_store = gtk_list_store_new (COL_LAST, G_TYPE_STRING,

      /* TODO: UI for multiple calendars */
            GtkTreeView *treeview;
            GtkCellRenderer *toggle_renderer, *label_renderer;
            GtkTreeViewColumn *toggle_column, *label_column;

            treeview = GTK_TREE_VIEW (data.cal_tree_view);
            gtk_tree_view_set_model (treeview,
                  GTK_TREE_MODEL (data.cal_list_store));

            toggle_renderer = gtk_cell_renderer_toggle_new ();
            g_signal_connect (G_OBJECT (toggle_renderer), "toggled",
                  G_CALLBACK (dates_toggle_renderer_toggled_cb),
            toggle_column = gtk_tree_view_column_new_with_attributes (
                  _("Selected"), toggle_renderer,
                  "active", COL_SELECTED, NULL);
            gtk_tree_view_append_column (treeview, toggle_column);

            label_renderer = gtk_cell_renderer_text_new ();
            label_column = gtk_tree_view_column_new_with_attributes (
                  _("Calendar"), label_renderer,
                  "text", COL_CALNAME, NULL);
            gtk_tree_view_append_column (treeview, label_column);

      data.first_load = FALSE;
      if (!dates_load_calendars (&data)) {
            /* Ensure system calendar exists */
            ECal *ecal = e_cal_new_system_calendar ();
            data.first_load = TRUE;

#ifdef DEBUG
            if (data.debug & DATES_DEBUG_CALENDAR)
                  g_debug ("Trying to create/open system calendar...");
            g_assert (ecal);

            g_signal_connect (G_OBJECT (ecal), "cal_opened",
                          G_CALLBACK (dates_cal_open_cb), &data);

            e_cal_open_async (ecal, FALSE);
      /* Set transient parent for dialogs */
      if (GTK_IS_WINDOW (data.calendars_dialog))
            gtk_window_set_transient_for (
                  GTK_WINDOW (data.calendars_dialog),
                  GTK_WINDOW (data.main_window));
      if (GTK_IS_WINDOW (data.details_dialog))
            gtk_window_set_transient_for (
                  GTK_WINDOW (data.details_dialog),
                  GTK_WINDOW (data.main_window));
      if (GTK_IS_WINDOW (data.time_dialog) &&
          GTK_IS_WINDOW (data.details_dialog))
            gtk_window_set_transient_for (
                  GTK_WINDOW (data.time_dialog),
                  GTK_WINDOW (data.details_dialog));
      if (GTK_IS_WINDOW (data.exceptions_dialog) &&
          GTK_IS_WINDOW (data.details_dialog))
            gtk_window_set_transient_for (
                  GTK_WINDOW (data.exceptions_dialog),
                  GTK_WINDOW (data.details_dialog));

      /* Create tree model filter to filter out read-only calendars */
      filter = gtk_tree_model_filter_new (
            GTK_TREE_MODEL (data.cal_list_store), NULL);
      gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
            dates_sel_or_read_only_filter_func, NULL, NULL);
      /* Set tree model for details dialog calendar selector */
      widget = data.details_calendar_combobox;
      gtk_combo_box_set_model (GTK_COMBO_BOX (widget), filter);
      dates_date_changed_cb (data.view, &data);

      /* Bind widgets to gconf properties */
      bridge = gconf_bridge_get ();
      gconf_bridge_bind_window (bridge, DATES_GCONF_WINDOW, GTK_WINDOW (
            data.main_window), TRUE, TRUE);
/*    gconf_bridge_bind_property (bridge, DATES_GCONF_PREFIX,
            G_OBJECT (data.view), "week_start");
      gconf_bridge_bind_property (bridge, DATES_GCONF_PREFIX,
            G_OBJECT (data.view), "use_24h");*/

      /* Calendar selection signals */
      gconf_client_add_dir (client, CALENDAR_GCONF_PREFIX,
      gconf_client_notify_add (client, CALENDAR_GCONF_SELECTED,
            dates_gconf_selected_cb, &data, NULL, NULL);
      widget = data.main_window;

      dates_platform_pre_show (&data);
      if (plug > 0) {
            GtkWidget *plug_widget;
            GtkWidget *contents;
#ifdef DEBUG
            if (data.debug & DATES_DEBUG_XEMBED)
                  g_debug ("Plugging into socket %d", plug);
            plug_widget = gtk_plug_new (plug);
            contents = g_object_ref (gtk_bin_get_child (GTK_BIN (widget)));
            gtk_container_remove (GTK_CONTAINER (widget), contents);
            gtk_container_add (GTK_CONTAINER (plug_widget), contents);
            g_object_unref (contents);
            g_signal_connect (G_OBJECT (plug_widget), "destroy",
                          G_CALLBACK (gtk_main_quit), NULL);
            gtk_widget_hide (data.main_menu);
            gtk_widget_show (data.header_eventbox);
            gtk_widget_show (plug_widget);
      } else {
            gtk_widget_show (data.main_window);

      gtk_main ();

      /* clean up */
      g_option_context_free (context);
      return 0;

Generated by  Doxygen 1.6.0   Back to index