/* * Copyright (C) 2007 OpenedHand Ltd * Authored by: Rob Bradford * * 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 of the License, 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 MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _TasksApp { GtkWidget *search_entry; GtkWidget *filter_combo; GtkTreeModel *task_store, *group_filter, *group_filter_store, *group_store; GtkWidget *treeview; GtkWidget *notebook; GtkWidget *delete_button; GtkWidget *main_window; GtkWidget *edit_page; GtkTreeSelection *selection; GtkWidget *editor; ECal *cal; } TasksApp; enum { PAGE_MAIN = 0, PAGE_EDIT }; void koto_platform_open_url (const gchar *url) { } static void tv_selection_changed (GtkTreeSelection *selection, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; GtkTreeModel *model; GtkTreeIter iter; KotoTask *task = NULL; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, COLUMN_TASK, &task, -1); if (app->editor) { g_object_set (app->editor, "task", task, NULL); gtk_widget_show (app->editor); } gtk_widget_set_sensitive (app->delete_button, TRUE); gtk_widget_show (app->edit_page); } else { gtk_widget_set_sensitive (app->delete_button, FALSE); gtk_widget_hide (app->edit_page); } } static void notebook_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, guint page_no, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; KotoTask *task = NULL; GError *error = NULL; if (app->editor && koto_task_editor_is_dirty (KOTO_TASK_EDITOR (app->editor))) { g_object_get (app->editor, "task", &task, NULL); if (task && !e_cal_modify_object (app->cal, task->comp, CALOBJ_MOD_THIS, &error)) { g_warning ("Cannot modify object: %s", error->message); g_clear_error (&error); } } } static gboolean ensure_first_selected_cb (gpointer userdata) { TasksApp *app = (TasksApp *)userdata; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; if (!gtk_tree_selection_get_selected (app->selection, &model, &iter)) { gtk_tree_model_get_iter_first (model, &iter); path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_set_cursor (GTK_TREE_VIEW (app->treeview), path, NULL, FALSE); gtk_tree_path_free (path); } return FALSE; } static void row_inserted_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; /* try to ensure that something is always selected */ if (!gtk_tree_selection_get_selected (app->selection, NULL, NULL)) { g_idle_add (ensure_first_selected_cb, app); } } static void row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; GtkTreeIter iter; if (gtk_tree_path_prev (path)) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (app->treeview), path, NULL, FALSE); } else { if (gtk_tree_model_get_iter (model, &iter, path)) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (app->treeview), path, NULL, FALSE); } else { gtk_widget_hide (app->editor); } } } static void new_clicked_cb (GtkToolButton *button, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; icalcomponent *comp; gchar *uid = NULL; GError *error = NULL; KotoTask *task; comp = icalcomponent_new (ICAL_VTODO_COMPONENT); icalcomponent_add_property (comp, icalproperty_new_class (ICAL_CLASS_PUBLIC)); icalcomponent_add_property (comp, icalproperty_new_summary (_("New task"))); if (!e_cal_create_object (app->cal, comp, &uid, &error)) { g_warning (G_STRLOC ": cannot create task: %s", error->message); g_clear_error (&error); return; } task = koto_task_new (comp); g_object_set (app->editor, "task", task, NULL); gtk_widget_show (app->editor); gtk_notebook_set_current_page (GTK_NOTEBOOK (app->notebook), PAGE_EDIT); } static void delete_clicked_cb (GtkToolButton *button, gpointer userdata) { TasksApp *app = (TasksApp *)userdata; KotoTask *task; GError *error = NULL; GtkWidget *dialog; task = koto_task_view_get_selected_task (KOTO_TASK_VIEW (app->treeview)); if (task) { dialog = gtk_message_dialog_new (GTK_WINDOW (app->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Are you sure you want to delete \"%s\"?"), icalcomponent_get_summary (task->comp)); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { if (!e_cal_remove_object (app->cal, icalcomponent_get_uid (task->comp), &error)) { g_warning ("Cannot remove object: %s", error->message); g_clear_error (&error); } } gtk_widget_destroy (dialog); koto_task_unref (task); } } int main (int argc, char **argv) { GtkWidget *box, *toolbar, *details, *w; GtkToolItem *toolitem; TasksApp *app; ECalView *cal_view; GError *error = NULL; GtkWidget *alignment; gtk_init (&argc, &argv); app = g_new0 (TasksApp, 1); /* Get the data stores */ app->cal = e_cal_new_system_tasks (); if (!app->cal) g_error ("Cannot get system tasks"); if (!e_cal_open (app->cal, FALSE, &error)) g_error("Cannot open calendar: %s", error->message); if (!e_cal_get_query (app->cal, "#t", &cal_view, &error)) g_error("Cannot get calendar view: %s", error->message); /* TODO: nasty, should pass cal to the stores or add e_cal_view_get_cal() */ g_object_set_data_full (G_OBJECT (cal_view), "koto-ecal", g_object_ref (app->cal), g_object_unref); /* Create the data stores */ app->task_store = koto_task_store_new (cal_view); app->group_filter_store = koto_group_store_new (cal_view); koto_group_store_add_group (KOTO_GROUP_STORE (app->group_filter_store), koto_all_group_new ()); koto_group_store_add_group (KOTO_GROUP_STORE (app->group_filter_store), koto_meta_group_new (KOTO_META_GROUP_SEPERATOR, -99)); app->group_store = koto_group_store_new (cal_view); koto_group_store_add_group (KOTO_GROUP_STORE (app->group_store), koto_meta_group_new (KOTO_META_GROUP_SEPERATOR, 99)); koto_group_store_add_group (KOTO_GROUP_STORE (app->group_store), koto_no_category_group_new ()); app->group_filter = koto_group_model_filter_new (KOTO_TASK_STORE (app->task_store)); /* tree view */ app->treeview = koto_task_view_new (KOTO_TASK_STORE (app->task_store), KOTO_GROUP_MODEL_FILTER (app->group_filter)); /* selection */ app->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (app->treeview)); g_signal_connect (app->selection, "changed", G_CALLBACK (tv_selection_changed), app); gtk_tree_selection_set_mode (app->selection, GTK_SELECTION_BROWSE); /* signals to try and ensure something useful is selected */ g_signal_connect (app->task_store, "row-inserted", G_CALLBACK (row_inserted_cb), app); g_signal_connect (app->task_store, "row-deleted", G_CALLBACK (row_deleted_cb), app); /* main window */ app->main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (app->main_window), "delete-event", (GCallback) gtk_main_quit, NULL); gtk_window_set_title (GTK_WINDOW (app->main_window), "Tasks"); /* main notebook */ app->notebook = gtk_notebook_new (); gtk_container_add (GTK_CONTAINER (app->main_window), app->notebook); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (app->notebook), GTK_POS_BOTTOM); g_signal_connect (app->notebook, "switch-page", G_CALLBACK (notebook_switch_page_cb), app); /* navigation */ box = gtk_vbox_new (FALSE, 0); gtk_notebook_append_page (GTK_NOTEBOOK (app->notebook), box, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_LARGE_TOOLBAR)); gtk_container_child_set (GTK_CONTAINER (app->notebook), box, "tab-expand", TRUE, NULL); /* toolbar */ toolbar = gtk_toolbar_new (); gtk_box_pack_start (GTK_BOX (box), toolbar, FALSE, FALSE, 0); /* new */ toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_NEW); g_signal_connect (toolitem, "clicked", G_CALLBACK (new_clicked_cb), app); gtk_tool_item_set_expand (toolitem, TRUE); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 0); /* delete */ toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE); gtk_tool_item_set_expand (toolitem, TRUE); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 1); gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE); app->delete_button = GTK_WIDGET (toolitem); g_signal_connect (toolitem, "clicked", G_CALLBACK (delete_clicked_cb), app); /* search/filter bar */ app->filter_combo = koto_group_combo_new (KOTO_GROUP_STORE (app->group_filter_store)); gtk_box_pack_start (GTK_BOX (box), app->filter_combo, FALSE, FALSE, 0); gtk_combo_box_set_active (GTK_COMBO_BOX (app->filter_combo), 0); koto_group_combo_connect_filter (KOTO_GROUP_COMBO (app->filter_combo), KOTO_GROUP_MODEL_FILTER (app->group_filter)); /* scrolled window */ w = moko_finger_scroll_new (); gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (w), app->treeview); /* details */ details = gtk_vbox_new (FALSE, 6); alignment = gtk_alignment_new (0, 0, 1, 1); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 6, 6); gtk_container_add (GTK_CONTAINER (alignment), details); app->editor = koto_task_editor_new (); koto_task_editor_add_fields (KOTO_TASK_EDITOR (app->editor), ICAL_SUMMARY_PROPERTY, ICAL_CATEGORIES_PROPERTY, ICAL_PRIORITY_PROPERTY, ICAL_DUE_PROPERTY, NULL); g_object_set (app->editor, "groups", app->group_store, NULL); gtk_box_pack_start (GTK_BOX (details), app->editor, TRUE, TRUE, 2); g_object_set (app->editor, "no-show-all", TRUE, NULL); /* show all the widgets on the edit page except the top most as this will be * shown when a task is selected */ app->edit_page = alignment; gtk_widget_set_no_show_all (app->edit_page, TRUE); gtk_widget_show_all (details); gtk_notebook_append_page (GTK_NOTEBOOK (app->notebook), alignment, gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_LARGE_TOOLBAR)); gtk_container_child_set (GTK_CONTAINER (app->notebook), alignment, "tab-expand", TRUE, NULL); e_cal_view_start (cal_view); /* let's go! */ gtk_widget_show_all (app->main_window); gtk_main (); g_free (app); return 0; }