create hard-coded list store for the tree model to see how it works out
[milk] / src / milk-main-window.c
1 /*
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.
6  *
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.
11  *
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
16  *
17  * Authors: Travis Reitter <treitter@gmail.com>
18  */
19
20 #include <config.h>
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gtk/gtk.h>
25 #include <hildon/hildon.h>
26
27 #include "milk-main-window.h"
28
29 G_DEFINE_TYPE (MilkMainWindow, milk_main_window, HILDON_TYPE_WINDOW)
30
31 #define MILK_MAIN_WINDOW_PRIVATE(o) \
32                 (G_TYPE_INSTANCE_GET_PRIVATE ((o), MILK_TYPE_MAIN_WINDOW, MilkMainWindowPrivate))
33
34 struct _MilkMainWindowPrivate
35 {
36         GtkWidget *main_vbox;
37
38         GtkWidget *new_task_entry;
39         GtkWidget *task_view;
40         GtkWidget *action_bar;
41 };
42
43 /* FIXME: cut this */
44 enum {
45         TASK_COLUMN_ID,
46         TASK_COLUMN_PRIORITY,
47         TASK_COLUMN_TITLE,
48         N_COLUMNS
49 };
50
51 /* FIXME: relocate this */
52 typedef struct {
53         gint id;
54         gint priority;
55         char *title;
56 } MilkTask;
57
58 /* FIXME: don't hard-code this */
59 static MilkTask tasks[] = {
60         { 0, 1, "Remember the milk"},
61         { 2, 1, "File taxes"},
62         { 6, 3, "Get a haircut"},
63         { 9, 2, "Keep it real"},
64         { 5, 3, "Invent smellovision"},
65 };
66
67 static void
68 milk_main_window_get_property (GObject    *object,
69                                guint       property_id,
70                                GValue     *value,
71                                GParamSpec *pspec)
72 {
73         switch (property_id)
74         {
75                 default:
76                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
77                                         pspec);
78         }
79 }
80
81 static void
82 milk_main_window_set_property (GObject      *object,
83                                guint         property_id,
84                                const GValue *value,
85                                GParamSpec   *pspec)
86 {
87         switch (property_id)
88         {
89                 default:
90                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
91                                         pspec);
92         }
93 }
94
95 static void
96 milk_main_window_dispose (GObject *object)
97 {
98         G_OBJECT_CLASS (milk_main_window_parent_class)->dispose (object);
99 }
100
101 static void
102 complete_clicked_cb (GtkButton      *button,
103                      MilkMainWindow *window)
104 {
105         g_debug ("FIXME: implement 'complete' action");
106 }
107
108 static void
109 delete_clicked_cb (GtkButton      *button,
110                    MilkMainWindow *window)
111 {
112         g_debug ("FIXME: implement 'delete' action");
113 }
114
115 static void
116 priority_plus_clicked_cb (GtkButton      *button,
117                           MilkMainWindow *window)
118 {
119         g_debug ("FIXME: implement 'priority plus' action");
120 }
121
122 static void
123 priority_minus_clicked_cb (GtkButton      *button,
124                            MilkMainWindow *window)
125 {
126         g_debug ("FIXME: implement 'priority minus' action");
127 }
128
129 static void
130 edit_clicked_cb (GtkButton      *button,
131                  MilkMainWindow *window)
132 {
133         g_debug ("FIXME: implement 'edit' action");
134 }
135
136 static MenuItem menu_items_always_shown[] = {
137         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
138 };
139
140 static MenuItem menu_items_selection_required[] = {
141         {"Edit",       "menu-item-edit",           edit_clicked_cb},
142         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
143         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
144         {"Complete",   "menu-item-complete",       complete_clicked_cb},
145         {"Delete",     "menu-item-delete",         delete_clicked_cb},
146 };
147
148 static void
149 task_view_selection_changed_cb (HildonTouchSelector *view,
150                                 gint                 column,
151                                 MilkMainWindow      *window)
152 {
153         MilkMainWindowPrivate *priv;
154         GList *rows;
155         gboolean show = FALSE;
156         gint i;
157
158         priv = MILK_MAIN_WINDOW_PRIVATE (window);
159
160         rows = hildon_touch_selector_get_selected_rows (view, column);
161         show = (g_list_length (rows) > 0);
162
163         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
164                 GtkWidget *w;
165
166                 w = g_object_get_data (
167                                 G_OBJECT (priv->app_menu),
168                                 menu_items_selection_required[i].id);
169
170                 if (show)
171                         gtk_widget_show (w);
172                 else
173                         gtk_widget_hide (w);
174         }
175 }
176
177 static GtkWidget*
178 create_menu (gpointer user_data)
179 {
180         HildonAppMenu *menu;
181         MenuItem *menu_array;
182         gint i, length;
183         GtkWidget *w;
184
185         menu = HILDON_APP_MENU (hildon_app_menu_new ());
186
187         menu_array = menu_items_always_shown;
188         length = G_N_ELEMENTS (menu_items_always_shown);
189         for (i = 0; i < length; i++) {
190                 w = hildon_button_new_with_text (
191                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
192                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
193                                 _(menu_array[i].display_name), "");
194                 g_signal_connect (w, "clicked",
195                                 G_CALLBACK (menu_array[i].callback), user_data);
196                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
197                 hildon_app_menu_append (menu, GTK_BUTTON (w));
198                 gtk_widget_show (w);
199         }
200
201         menu_array = menu_items_selection_required;
202         length = G_N_ELEMENTS (menu_items_selection_required);
203         for (i = 0; i < length; i++) {
204                 w = hildon_button_new_with_text (
205                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
206                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
207                                 menu_array[i].display_name, "");
208                 g_signal_connect (w, "clicked",
209                                 G_CALLBACK (menu_array[i].callback), user_data);
210                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
211                 hildon_app_menu_append (menu, GTK_BUTTON (w));
212                 gtk_widget_hide (w);
213         }
214
215         gtk_widget_show (GTK_WIDGET (menu));
216
217         return GTK_WIDGET (menu);
218 }
219
220 static MenuItem menu_items_always_shown[] = {
221         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
222 };
223
224 static MenuItem menu_items_selection_required[] = {
225         {"Edit",       "menu-item-edit",           edit_clicked_cb},
226         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
227         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
228         {"Complete",   "menu-item-complete",       complete_clicked_cb},
229         {"Delete",     "menu-item-delete",         delete_clicked_cb},
230 };
231
232 static void
233 task_view_selection_changed_cb (HildonTouchSelector *view,
234                                 gint                 column,
235                                 MilkMainWindow      *window)
236 {
237         MilkMainWindowPrivate *priv;
238         GList *rows;
239         gboolean show = FALSE;
240         gint i;
241
242         priv = MILK_MAIN_WINDOW_PRIVATE (window);
243
244         rows = hildon_touch_selector_get_selected_rows (view, column);
245         show = (g_list_length (rows) > 0);
246
247         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
248                 GtkWidget *w;
249
250                 w = g_object_get_data (
251                                 G_OBJECT (priv->app_menu),
252                                 menu_items_selection_required[i].id);
253
254                 if (show)
255                         gtk_widget_show (w);
256                 else
257                         gtk_widget_hide (w);
258         }
259 }
260
261 static GtkWidget*
262 create_menu (gpointer user_data)
263 {
264         HildonAppMenu *menu;
265         MenuItem *menu_array;
266         gint i, length;
267         GtkWidget *w;
268
269         menu = HILDON_APP_MENU (hildon_app_menu_new ());
270
271         menu_array = menu_items_always_shown;
272         length = G_N_ELEMENTS (menu_items_always_shown);
273         for (i = 0; i < length; i++) {
274                 w = hildon_button_new_with_text (
275                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
276                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
277                                 _(menu_array[i].display_name), "");
278                 g_signal_connect (w, "clicked",
279                                 G_CALLBACK (menu_array[i].callback), user_data);
280                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
281                 hildon_app_menu_append (menu, GTK_BUTTON (w));
282                 gtk_widget_show (w);
283         }
284
285         menu_array = menu_items_selection_required;
286         length = G_N_ELEMENTS (menu_items_selection_required);
287         for (i = 0; i < length; i++) {
288                 w = hildon_button_new_with_text (
289                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
290                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
291                                 menu_array[i].display_name, "");
292                 g_signal_connect (w, "clicked",
293                                 G_CALLBACK (menu_array[i].callback), user_data);
294                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
295                 hildon_app_menu_append (menu, GTK_BUTTON (w));
296                 gtk_widget_hide (w);
297         }
298
299         gtk_widget_show (GTK_WIDGET (menu));
300
301         return GTK_WIDGET (menu);
302 }
303
304 static void
305 contact_column_render_func (GtkCellLayout   *cell_layout,
306                             GtkCellRenderer *renderer,
307                             GtkTreeModel    *model,
308                             GtkTreeIter     *iter,
309                             gpointer         user_data)
310 {
311         MilkTask *task;
312         char *title;
313
314         gtk_tree_model_get (
315                         model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
316
317         g_object_get (task, "title", &title, NULL);
318         g_object_set (renderer, "text", title, NULL);
319
320         g_free (title);
321         g_object_unref (task);
322 }
323
324 /* FIXME: set up a MilkListStore instead */
325 static GtkTreeModel*
326 create_task_model ()
327 {
328         GtkListStore *list_store;
329         GtkTreeIter iter;
330         gint i;
331
332         list_store = gtk_list_store_new (N_COLUMNS,
333                                          G_TYPE_INT,
334                                          G_TYPE_INT,
335                                          G_TYPE_STRING);
336
337         /* Populate model */
338         for (i = 0; i < G_N_ELEMENTS (tasks); i++) {
339                 gtk_list_store_append (list_store, &iter);
340                 gtk_list_store_set (list_store, &iter,
341                                     TASK_COLUMN_ID, tasks[i].id,
342                                     TASK_COLUMN_PRIORITY, tasks[i].priority,
343                                     TASK_COLUMN_TITLE, tasks[i].title,
344                                    -1);
345         }
346
347         return GTK_TREE_MODEL (list_store);
348 }
349
350 static void
351 milk_main_window_constructed (GObject* object)
352 {
353         MilkMainWindow *self = MILK_MAIN_WINDOW (object);
354         MilkMainWindowPrivate *priv = MILK_MAIN_WINDOW_PRIVATE (object);
355         GtkWidget *w;
356         GtkWidget *pannable;
357         GtkTreeModel *model;
358         GtkCellRenderer *renderer;
359         GtkTreeViewColumn *col;
360
361         w = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
362         gtk_container_add (GTK_CONTAINER (self), w);
363         priv->main_vbox = w;
364
365         /*
366          * New Task entry
367          */
368         w = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
369         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
370
371         /* FIXME: change this to hildon_gtk_entry_set_placeholder_text() is
372          * fixed, since this is deprecated */
373         hildon_entry_set_placeholder (HILDON_ENTRY (w),
374                         _("Enter a new task..."));
375         priv->new_task_entry = w;
376
377         /*
378          * Task List
379          */
380         w = hildon_pannable_area_new ();
381         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, TRUE, TRUE, 0);
382         pannable = w;
383
384         /* FIXME: attach the model (create a new MilkTaskModel class that syncs
385          * with the cached tasks) */
386         model = create_task_model ();
387         w = gtk_tree_view_new_with_model (model);
388
389         renderer = gtk_cell_renderer_text_new ();
390         col = gtk_tree_view_column_new_with_attributes ("Priority", renderer,
391                         "text", TASK_COLUMN_PRIORITY, NULL);
392         gtk_tree_view_append_column (GTK_TREE_VIEW (w), col);
393         renderer = gtk_cell_renderer_text_new ();
394         col = gtk_tree_view_column_new_with_attributes ("Title", renderer,
395                         "text", TASK_COLUMN_TITLE, NULL);
396         gtk_tree_view_append_column (GTK_TREE_VIEW (w), col);
397         g_object_unref (model);
398
399         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (pannable),
400                         w);
401         gtk_widget_grab_focus (w);
402         priv->task_view = w;
403
404         /*
405          * Action Bar
406          */
407         w = gtk_hbox_new (TRUE, HILDON_MARGIN_DEFAULT);
408         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
409         priv->action_bar = w;
410
411         /* FIXME: these are probably better off being icons, for width reasons
412          */
413         w = hildon_button_new_with_text (
414                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
415                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
416                         _("Complete"), "");
417         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
418         g_signal_connect (w, "clicked", G_CALLBACK (complete_clicked_cb), self);
419
420         w = hildon_button_new_with_text (
421                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
422                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
423                         _("Delete"), "");
424         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
425         g_signal_connect (w, "clicked", G_CALLBACK (delete_clicked_cb), self);
426
427         w = hildon_button_new_with_text (
428                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
429                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
430                         _("Priority +"), "");
431         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
432         g_signal_connect (w, "clicked", G_CALLBACK (priority_plus_clicked_cb),
433                         self);
434
435         w = hildon_button_new_with_text (
436                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
437                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
438                         _("Priority -"), "");
439         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
440         g_signal_connect (w, "clicked", G_CALLBACK (priority_minus_clicked_cb),
441                         self);
442
443         w = hildon_button_new_with_text (
444                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
445                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
446                         _("Edit"), "");
447         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
448         g_signal_connect (w, "clicked", G_CALLBACK (edit_clicked_cb),
449                         self);
450
451         w = hildon_button_new_with_text (
452                         HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
453                         HILDON_BUTTON_ARRANGEMENT_VERTICAL,
454                         _("Edit Tags"), "");
455         gtk_container_add (GTK_CONTAINER (priv->action_bar), w);
456         g_signal_connect (w, "clicked", G_CALLBACK (edit_tags_clicked_cb),
457                         self);
458 }
459
460 static void
461 milk_main_window_class_init (MilkMainWindowClass *klass)
462 {
463         GObjectClass *object_class = G_OBJECT_CLASS (klass);
464
465         g_type_class_add_private (klass, sizeof (MilkMainWindowPrivate));
466
467         object_class->get_property = milk_main_window_get_property;
468         object_class->set_property = milk_main_window_set_property;
469         object_class->constructed = milk_main_window_constructed;
470         object_class->dispose = milk_main_window_dispose;
471 }
472
473 static void
474 milk_main_window_init (MilkMainWindow *self)
475 {
476         self->priv = MILK_MAIN_WINDOW_PRIVATE (self);
477 }
478
479 GtkWidget*
480 milk_main_window_new ()
481 {
482         return g_object_new (MILK_TYPE_MAIN_WINDOW,
483                              NULL);
484 }