2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
12 * You should have received a copy of the GNU General Public
13 * License along with this program; if not, write to the
14 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
15 * Boston, MA 02110-1301 USA
17 * Authors: Travis Reitter <treitter@gmail.com>
23 #include <glib/gi18n.h>
25 #include <hildon/hildon.h>
26 #include <rtm-glib/rtm-glib.h>
28 #include "milk-main-window.h"
29 #include "milk-cache.h"
30 #include "milk-task-model.h"
32 G_DEFINE_TYPE (MilkMainWindow, milk_main_window, HILDON_TYPE_WINDOW)
34 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
35 #define MILK_MAIN_WINDOW_PRIVATE(o) ((MILK_MAIN_WINDOW ((o)))->priv)
37 #define NEW_TASK_PLACEHOLDER_TEXT "Enter a new task..."
39 static GtkWidget *default_window = NULL;
41 struct _MilkMainWindowPrivate
49 GtkWidget *new_task_entry;
51 GtkWidget *task_selector;
55 TASK_VIEW_COLUMN_TITLE,
60 const char *display_name;
66 milk_main_window_get_property (GObject *object,
74 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
80 milk_main_window_set_property (GObject *object,
88 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
94 milk_main_window_dispose (GObject *object)
96 G_OBJECT_CLASS (milk_main_window_parent_class)->dispose (object);
100 new_task_clicked_cb (GtkButton *button,
101 MilkMainWindow *window)
103 g_debug ("FIXME: implement 'new task' action");
107 get_selected_tasks (MilkMainWindow *window)
109 MilkMainWindowPrivate *priv;
114 priv = MILK_MAIN_WINDOW_PRIVATE (window);
116 rows = hildon_touch_selector_get_selected_rows (
117 HILDON_TOUCH_SELECTOR (priv->task_view),
118 TASK_VIEW_COLUMN_TITLE);
119 model = hildon_touch_selector_get_model (
120 HILDON_TOUCH_SELECTOR (priv->task_view),
121 TASK_VIEW_COLUMN_TITLE);
127 gtk_tree_model_get_iter (model, &iter, rows->data);
128 gtk_tree_model_get (model, &iter,
129 MILK_TASK_MODEL_COLUMN_TASK, &task,
132 tasks = g_list_prepend (tasks, task);
133 rows = g_list_delete_link (rows, rows);
140 complete_clicked_cb (GtkButton *button,
141 MilkMainWindow *window)
143 MilkMainWindowPrivate *priv;
146 GError *error = NULL;
148 priv = MILK_MAIN_WINDOW_PRIVATE (window);
150 tasks = get_selected_tasks (window);
151 timeline = milk_cache_timeline_create (priv->cache, &error);
154 g_warning (G_STRLOC ": failed to create a timeline: %s",
156 g_clear_error (&error);
159 milk_cache_task_complete (priv->cache, timeline,
160 tasks->data, &error);
161 tasks = g_list_delete_link (tasks, tasks);
167 delete_clicked_cb (GtkButton *button,
168 MilkMainWindow *window)
170 MilkMainWindowPrivate *priv;
173 GError *error = NULL;
175 priv = MILK_MAIN_WINDOW_PRIVATE (window);
177 tasks = get_selected_tasks (window);
178 timeline = milk_cache_timeline_create (priv->cache, &error);
181 g_warning (G_STRLOC ": failed to create a timeline: %s",
183 g_clear_error (&error);
186 milk_cache_task_delete (priv->cache, timeline,
187 tasks->data, &error);
188 tasks = g_list_delete_link (tasks, tasks);
194 priority_plus_clicked_cb (GtkButton *button,
195 MilkMainWindow *window)
197 g_debug ("FIXME: implement 'priority plus' action");
201 priority_minus_clicked_cb (GtkButton *button,
202 MilkMainWindow *window)
204 g_debug ("FIXME: implement 'priority minus' action");
208 edit_clicked_cb (GtkButton *button,
209 MilkMainWindow *window)
211 g_debug ("FIXME: implement 'edit' action");
214 static MenuItem menu_items_always_shown[] = {
215 {"New Task", "menu-item-new-task", new_task_clicked_cb},
218 static MenuItem menu_items_selection_required[] = {
219 {"Edit", "menu-item-edit", edit_clicked_cb},
220 {"Priority +", "menu-item-priority_plus", priority_plus_clicked_cb},
221 {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
222 {"Complete", "menu-item-complete", complete_clicked_cb},
223 {"Delete", "menu-item-delete", delete_clicked_cb},
227 new_task_entry_activated_cb (GtkEntry *entry,
228 MilkMainWindow *window)
230 MilkMainWindowPrivate *priv;
233 priv = MILK_MAIN_WINDOW_PRIVATE (window);
235 name = g_strdup (gtk_entry_get_text (entry));
237 /* Strip the contents of leading and trailing whitespace, and add as a
238 * new task if the result is non-empty */
239 if (g_strcmp0 (g_strstrip (name), "")) {
241 GError *error = NULL;
243 timeline = milk_cache_timeline_create (priv->cache, &error);
246 g_warning (G_STRLOC ": failed to create a timeline: %s",
248 g_clear_error (&error);
252 task = milk_cache_task_add (priv->cache, timeline, name,
255 /* empty out the entry and show its placeholder
257 gtk_entry_set_text (entry, "");
258 gtk_widget_grab_focus (priv->task_view);
260 /* FIXME: we should probably scroll to this new
261 * task in the model view, if it's not currently
262 * visible (and highlight only it in any case */
264 g_warning (G_STRLOC ": failed to add task: %s",
266 g_clear_error (&error);
275 new_task_entry_key_press_event_cb (GtkEntry *entry,
277 MilkMainWindow *window)
279 MilkMainWindowPrivate *priv;
281 priv = MILK_MAIN_WINDOW_PRIVATE (window);
283 if (!event || event->type != GDK_KEY_PRESS) {
287 switch (event->keyval) {
290 new_task_entry_activated_cb (entry, window);
298 task_view_selection_changed_cb (HildonTouchSelector *view,
300 MilkMainWindow *window)
302 MilkMainWindowPrivate *priv;
304 gboolean show = FALSE;
307 priv = MILK_MAIN_WINDOW_PRIVATE (window);
309 rows = hildon_touch_selector_get_selected_rows (view, column);
310 show = (g_list_length (rows) > 0);
312 for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
315 w = g_object_get_data (
316 G_OBJECT (priv->app_menu),
317 menu_items_selection_required[i].id);
329 create_menu (gpointer user_data)
332 MenuItem *menu_array;
336 menu = HILDON_APP_MENU (hildon_app_menu_new ());
338 menu_array = menu_items_always_shown;
339 length = G_N_ELEMENTS (menu_items_always_shown);
340 for (i = 0; i < length; i++) {
341 w = hildon_button_new_with_text (
342 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
343 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
344 _(menu_array[i].display_name), "");
345 g_signal_connect (w, "clicked",
346 G_CALLBACK (menu_array[i].callback), user_data);
347 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
348 hildon_app_menu_append (menu, GTK_BUTTON (w));
352 menu_array = menu_items_selection_required;
353 length = G_N_ELEMENTS (menu_items_selection_required);
354 for (i = 0; i < length; i++) {
355 w = hildon_button_new_with_text (
356 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
357 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
358 menu_array[i].display_name, "");
359 g_signal_connect (w, "clicked",
360 G_CALLBACK (menu_array[i].callback), user_data);
361 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
362 hildon_app_menu_append (menu, GTK_BUTTON (w));
366 gtk_widget_show (GTK_WIDGET (menu));
368 return GTK_WIDGET (menu);
372 priority_column_render_func (GtkCellLayout *cell_layout,
373 GtkCellRenderer *renderer,
379 const char *priority;
381 gboolean color_set = TRUE;
384 model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
386 priority = rtm_task_get_priority (task);
389 } else if (!g_strcmp0 (priority, "1")) {
390 gdk_color_parse ("#ea5200", &color);
391 } else if (!g_strcmp0 (priority, "2")) {
392 gdk_color_parse ("#0060bf", &color);
393 } else if (!g_strcmp0 (priority, "3")) {
394 gdk_color_parse ("#359aff", &color);
399 g_object_set (renderer,
400 "cell-background-gdk", color_set ? &color : NULL,
401 "cell-background-set", color_set,
404 g_object_unref (task);
408 name_column_render_func (GtkCellLayout *cell_layout,
409 GtkCellRenderer *renderer,
417 model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
418 g_object_set (renderer, "text", rtm_task_get_name (task), NULL);
420 g_object_unref (task);
424 begin_cache_idle (MilkMainWindow *window)
426 MilkMainWindowPrivate *priv;
428 priv = MILK_MAIN_WINDOW_PRIVATE (window);
430 milk_cache_authenticate (priv->cache);
436 milk_main_window_constructed (GObject* object)
438 MilkMainWindow *self = MILK_MAIN_WINDOW (object);
439 MilkMainWindowPrivate *priv = MILK_MAIN_WINDOW_PRIVATE (object);
442 GtkCellRenderer *renderer;
443 HildonTouchSelectorColumn *col;
445 w = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
446 gtk_container_add (GTK_CONTAINER (self), w);
452 w = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
453 gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
455 /* FIXME: change this to hildon_gtk_entry_set_placeholder_text() is
456 * fixed, since this is deprecated */
457 hildon_entry_set_placeholder (HILDON_ENTRY (w),
458 _(NEW_TASK_PLACEHOLDER_TEXT));
459 priv->new_task_entry = w;
460 g_signal_connect (G_OBJECT (w), "activate",
461 G_CALLBACK (new_task_entry_activated_cb), self);
462 g_signal_connect (G_OBJECT (w), "key-press-event",
463 G_CALLBACK (new_task_entry_key_press_event_cb), self);
468 model = GTK_TREE_MODEL (milk_task_model_new ());
469 w = hildon_touch_selector_new ();
471 col = hildon_touch_selector_append_column (
472 HILDON_TOUCH_SELECTOR (w), model, NULL, NULL);
474 renderer = gtk_cell_renderer_text_new ();
475 g_object_set (renderer,
476 "width", HILDON_ICON_PIXEL_SIZE_XSMALL,
479 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (col), renderer, FALSE);
480 gtk_cell_layout_set_cell_data_func (
481 GTK_CELL_LAYOUT (col), renderer,
482 (GtkCellLayoutDataFunc) priority_column_render_func,
485 renderer = gtk_cell_renderer_text_new ();
486 g_object_set (renderer,
487 "ellipsize", PANGO_ELLIPSIZE_END,
488 "alignment", PANGO_ALIGN_LEFT,
489 "xpad", HILDON_MARGIN_DEFAULT,
491 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (col), renderer, TRUE);
492 gtk_cell_layout_set_cell_data_func (
493 GTK_CELL_LAYOUT (col), renderer,
494 (GtkCellLayoutDataFunc) name_column_render_func,
497 g_object_unref (model);
499 hildon_touch_selector_set_column_selection_mode (
500 HILDON_TOUCH_SELECTOR (w),
501 HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
502 hildon_touch_selector_set_hildon_ui_mode (
503 HILDON_TOUCH_SELECTOR (w), HILDON_UI_MODE_EDIT);
504 hildon_touch_selector_unselect_all (
505 HILDON_TOUCH_SELECTOR (w), TASK_VIEW_COLUMN_TITLE);
507 gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, TRUE, TRUE, 0);
508 g_object_set (w, "can-focus", TRUE, NULL);
509 gtk_widget_grab_focus (w);
512 G_OBJECT (w), "changed",
513 G_CALLBACK (task_view_selection_changed_cb), self);
516 priv->app_menu = create_menu (self);
517 hildon_window_set_app_menu (
518 HILDON_WINDOW (self), HILDON_APP_MENU (priv->app_menu));
520 /* set up the cache */
521 priv->cache = milk_cache_get_default ();
523 /* break a cyclical dependency by doing this after the window is
525 g_idle_add ((GSourceFunc) begin_cache_idle, self);
529 milk_main_window_class_init (MilkMainWindowClass *klass)
531 GObjectClass *object_class = G_OBJECT_CLASS (klass);
533 g_type_class_add_private (klass, sizeof (MilkMainWindowPrivate));
535 object_class->get_property = milk_main_window_get_property;
536 object_class->set_property = milk_main_window_set_property;
537 object_class->constructed = milk_main_window_constructed;
538 object_class->dispose = milk_main_window_dispose;
542 milk_main_window_init (MilkMainWindow *self)
544 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (
545 self, MILK_TYPE_MAIN_WINDOW, MilkMainWindowPrivate);
549 milk_main_window_get_default ()
551 if (!default_window) {
552 default_window = g_object_new (MILK_TYPE_MAIN_WINDOW, NULL);
555 return default_window;