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-auth.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");
106 /* XXX: The latency between clicking "complete" and actually removing the task
107 * from the view after polling the server is very long, so there's an obvious
108 * lag -- it will be completely transparent (and look very fast) as soon as
109 * we've got a cache in place */
111 complete_clicked_cb (GtkButton *button,
112 MilkMainWindow *window)
114 MilkMainWindowPrivate *priv;
118 GError *error = NULL;
120 priv = MILK_MAIN_WINDOW_PRIVATE (window);
122 rows = hildon_touch_selector_get_selected_rows (
123 HILDON_TOUCH_SELECTOR (priv->task_view),
124 TASK_VIEW_COLUMN_TITLE);
125 model = hildon_touch_selector_get_model (
126 HILDON_TOUCH_SELECTOR (priv->task_view),
127 TASK_VIEW_COLUMN_TITLE);
129 timeline = milk_auth_timeline_create (priv->auth, &error);
132 g_warning (G_STRLOC ": failed to create a timeline: %s",
134 g_clear_error (&error);
140 gtk_tree_model_get_iter (model, &iter, rows->data);
141 gtk_tree_model_get (model, &iter,
142 MILK_TASK_MODEL_COLUMN_TASK, &task,
145 milk_auth_task_complete (priv->auth, timeline, task,
148 g_warning (G_STRLOC ": failed to complete task "
150 rtm_task_get_id (task),
152 g_clear_error (&error);
155 rows = g_list_delete_link (rows, rows);
160 /* XXX: high latency until we have a cache; see the note for
161 * complete_clicked_cb() */
163 delete_clicked_cb (GtkButton *button,
164 MilkMainWindow *window)
166 MilkMainWindowPrivate *priv;
170 GError *error = NULL;
172 priv = MILK_MAIN_WINDOW_PRIVATE (window);
174 rows = hildon_touch_selector_get_selected_rows (
175 HILDON_TOUCH_SELECTOR (priv->task_view),
176 TASK_VIEW_COLUMN_TITLE);
177 model = hildon_touch_selector_get_model (
178 HILDON_TOUCH_SELECTOR (priv->task_view),
179 TASK_VIEW_COLUMN_TITLE);
181 timeline = milk_auth_timeline_create (priv->auth, &error);
184 g_warning (G_STRLOC ": failed to create a timeline: %s",
186 g_clear_error (&error);
192 gtk_tree_model_get_iter (model, &iter, rows->data);
193 gtk_tree_model_get (model, &iter,
194 MILK_TASK_MODEL_COLUMN_TASK, &task,
197 milk_auth_task_delete (priv->auth, timeline, task,
200 g_warning (G_STRLOC ": failed to delete task "
202 rtm_task_get_id (task),
204 g_clear_error (&error);
207 rows = g_list_delete_link (rows, rows);
213 priority_plus_clicked_cb (GtkButton *button,
214 MilkMainWindow *window)
216 g_debug ("FIXME: implement 'priority plus' action");
220 priority_minus_clicked_cb (GtkButton *button,
221 MilkMainWindow *window)
223 g_debug ("FIXME: implement 'priority minus' action");
227 edit_clicked_cb (GtkButton *button,
228 MilkMainWindow *window)
230 g_debug ("FIXME: implement 'edit' action");
233 static MenuItem menu_items_always_shown[] = {
234 {"New Task", "menu-item-new-task", new_task_clicked_cb},
237 static MenuItem menu_items_selection_required[] = {
238 {"Edit", "menu-item-edit", edit_clicked_cb},
239 {"Priority +", "menu-item-priority_plus", priority_plus_clicked_cb},
240 {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
241 {"Complete", "menu-item-complete", complete_clicked_cb},
242 {"Delete", "menu-item-delete", delete_clicked_cb},
246 new_task_entry_activated_cb (GtkEntry *entry,
247 MilkMainWindow *window)
249 MilkMainWindowPrivate *priv;
252 priv = MILK_MAIN_WINDOW_PRIVATE (window);
254 name = g_strdup (gtk_entry_get_text (entry));
256 /* Strip the contents of leading and trailing whitespace, and add as a
257 * new task if the result is non-empty */
258 if (g_strcmp0 (g_strstrip (name), "")) {
260 GError *error = NULL;
262 timeline = milk_auth_timeline_create (priv->auth, &error);
265 g_warning (G_STRLOC ": failed to create a timeline: %s",
267 g_clear_error (&error);
271 task = milk_auth_task_add (priv->auth, timeline, name,
274 /* empty out the entry and show its placeholder
276 gtk_entry_set_text (entry, "");
277 gtk_widget_grab_focus (priv->task_view);
279 g_warning (G_STRLOC ": failed to add task: %s",
281 g_clear_error (&error);
290 new_task_entry_key_press_event_cb (GtkEntry *entry,
292 MilkMainWindow *window)
294 MilkMainWindowPrivate *priv;
296 priv = MILK_MAIN_WINDOW_PRIVATE (window);
298 if (!event || event->type != GDK_KEY_PRESS) {
302 switch (event->keyval) {
305 new_task_entry_activated_cb (entry, window);
313 task_view_selection_changed_cb (HildonTouchSelector *view,
315 MilkMainWindow *window)
317 MilkMainWindowPrivate *priv;
319 gboolean show = FALSE;
322 priv = MILK_MAIN_WINDOW_PRIVATE (window);
324 rows = hildon_touch_selector_get_selected_rows (view, column);
325 show = (g_list_length (rows) > 0);
327 for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
330 w = g_object_get_data (
331 G_OBJECT (priv->app_menu),
332 menu_items_selection_required[i].id);
344 create_menu (gpointer user_data)
347 MenuItem *menu_array;
351 menu = HILDON_APP_MENU (hildon_app_menu_new ());
353 menu_array = menu_items_always_shown;
354 length = G_N_ELEMENTS (menu_items_always_shown);
355 for (i = 0; i < length; i++) {
356 w = hildon_button_new_with_text (
357 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
358 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
359 _(menu_array[i].display_name), "");
360 g_signal_connect (w, "clicked",
361 G_CALLBACK (menu_array[i].callback), user_data);
362 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
363 hildon_app_menu_append (menu, GTK_BUTTON (w));
367 menu_array = menu_items_selection_required;
368 length = G_N_ELEMENTS (menu_items_selection_required);
369 for (i = 0; i < length; i++) {
370 w = hildon_button_new_with_text (
371 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
372 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
373 menu_array[i].display_name, "");
374 g_signal_connect (w, "clicked",
375 G_CALLBACK (menu_array[i].callback), user_data);
376 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
377 hildon_app_menu_append (menu, GTK_BUTTON (w));
381 gtk_widget_show (GTK_WIDGET (menu));
383 return GTK_WIDGET (menu);
387 contact_column_render_func (GtkCellLayout *cell_layout,
388 GtkCellRenderer *renderer,
396 model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
397 g_object_set (renderer, "text", rtm_task_get_name (task), NULL);
399 g_object_unref (task);
403 begin_auth_idle (MilkMainWindow *window)
405 MilkMainWindowPrivate *priv;
407 priv = MILK_MAIN_WINDOW_PRIVATE (window);
409 milk_auth_log_in (priv->auth);
415 milk_main_window_constructed (GObject* object)
417 MilkMainWindow *self = MILK_MAIN_WINDOW (object);
418 MilkMainWindowPrivate *priv = MILK_MAIN_WINDOW_PRIVATE (object);
421 GtkCellRenderer *renderer;
422 HildonTouchSelectorColumn *col;
424 w = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
425 gtk_container_add (GTK_CONTAINER (self), w);
431 w = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
432 gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
434 /* FIXME: change this to hildon_gtk_entry_set_placeholder_text() is
435 * fixed, since this is deprecated */
436 hildon_entry_set_placeholder (HILDON_ENTRY (w),
437 _(NEW_TASK_PLACEHOLDER_TEXT));
438 priv->new_task_entry = w;
439 g_signal_connect (G_OBJECT (w), "activate",
440 G_CALLBACK (new_task_entry_activated_cb), self);
441 g_signal_connect (G_OBJECT (w), "key-press-event",
442 G_CALLBACK (new_task_entry_key_press_event_cb), self);
447 priv->auth = milk_auth_get_default ();
448 model = GTK_TREE_MODEL (milk_task_model_new (priv->auth));
449 w = hildon_touch_selector_new ();
452 renderer = gtk_cell_renderer_text_new ();
453 g_object_set (renderer,
454 "ellipsize", PANGO_ELLIPSIZE_END,
457 col = hildon_touch_selector_append_column (
458 HILDON_TOUCH_SELECTOR (w), model, NULL, NULL);
459 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (col), renderer, TRUE);
460 gtk_cell_layout_set_cell_data_func (
461 GTK_CELL_LAYOUT (col), renderer,
462 (GtkCellLayoutDataFunc) contact_column_render_func,
464 g_object_unref (model);
466 hildon_touch_selector_set_column_selection_mode (
467 HILDON_TOUCH_SELECTOR (w),
468 HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
469 hildon_touch_selector_set_hildon_ui_mode (
470 HILDON_TOUCH_SELECTOR (w), HILDON_UI_MODE_EDIT);
471 hildon_touch_selector_unselect_all (
472 HILDON_TOUCH_SELECTOR (w), TASK_VIEW_COLUMN_TITLE);
474 gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, TRUE, TRUE, 0);
475 g_object_set (w, "can-focus", TRUE, NULL);
476 gtk_widget_grab_focus (w);
479 G_OBJECT (w), "changed",
480 G_CALLBACK (task_view_selection_changed_cb), self);
483 priv->app_menu = create_menu (self);
484 hildon_window_set_app_menu (
485 HILDON_WINDOW (self), HILDON_APP_MENU (priv->app_menu));
487 /* break a cyclical dependency by doing this after the window is
489 g_idle_add ((GSourceFunc) begin_auth_idle, self);
493 milk_main_window_class_init (MilkMainWindowClass *klass)
495 GObjectClass *object_class = G_OBJECT_CLASS (klass);
497 g_type_class_add_private (klass, sizeof (MilkMainWindowPrivate));
499 object_class->get_property = milk_main_window_get_property;
500 object_class->set_property = milk_main_window_set_property;
501 object_class->constructed = milk_main_window_constructed;
502 object_class->dispose = milk_main_window_dispose;
506 milk_main_window_init (MilkMainWindow *self)
508 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (
509 self, MILK_TYPE_MAIN_WINDOW, MilkMainWindowPrivate);
513 milk_main_window_get_default ()
515 if (!default_window) {
516 default_window = g_object_new (MILK_TYPE_MAIN_WINDOW, NULL);
519 return default_window;