06d435e0b4b26fd13d2216f8b86607402f2b5340
[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 #include "milk-auth.h"
29 #include "milk-task.h"
30 #include "milk-task-model.h"
31
32 G_DEFINE_TYPE (MilkMainWindow, milk_main_window, HILDON_TYPE_WINDOW)
33
34 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
35 #define MILK_MAIN_WINDOW_PRIVATE(o) ((MILK_MAIN_WINDOW ((o)))->priv)
36
37 static GtkWidget *default_window = NULL;
38
39 struct _MilkMainWindowPrivate
40 {
41         MilkAuth *auth;
42
43         GtkWidget *app_menu;
44
45         GtkWidget *main_vbox;
46
47         GtkWidget *new_task_entry;
48         GtkWidget *task_view;
49         GtkWidget *task_selector;
50 };
51
52 enum {
53         TASK_VIEW_COLUMN_TITLE,
54         N_VIEW_COLUMNS
55 };
56
57 typedef struct {
58         const char *display_name;
59         const char *id;
60         gpointer    callback;
61 } MenuItem;
62
63 static void
64 milk_main_window_get_property (GObject    *object,
65                                guint       property_id,
66                                GValue     *value,
67                                GParamSpec *pspec)
68 {
69         switch (property_id)
70         {
71                 default:
72                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
73                                         pspec);
74         }
75 }
76
77 static void
78 milk_main_window_set_property (GObject      *object,
79                                guint         property_id,
80                                const GValue *value,
81                                GParamSpec   *pspec)
82 {
83         switch (property_id)
84         {
85                 default:
86                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
87                                         pspec);
88         }
89 }
90
91 static void
92 milk_main_window_dispose (GObject *object)
93 {
94         G_OBJECT_CLASS (milk_main_window_parent_class)->dispose (object);
95 }
96
97 static void
98 new_task_clicked_cb (GtkButton      *button,
99                      MilkMainWindow *window)
100 {
101         g_debug ("FIXME: implement 'new task' action");
102 }
103
104 static void
105 complete_clicked_cb (GtkButton      *button,
106                      MilkMainWindow *window)
107 {
108         g_debug ("FIXME: implement 'complete' action");
109 }
110
111 static void
112 delete_clicked_cb (GtkButton      *button,
113                    MilkMainWindow *window)
114 {
115         g_debug ("FIXME: implement 'delete' action");
116 }
117
118 static void
119 priority_plus_clicked_cb (GtkButton      *button,
120                           MilkMainWindow *window)
121 {
122         g_debug ("FIXME: implement 'priority plus' action");
123 }
124
125 static void
126 priority_minus_clicked_cb (GtkButton      *button,
127                            MilkMainWindow *window)
128 {
129         g_debug ("FIXME: implement 'priority minus' action");
130 }
131
132 static void
133 edit_clicked_cb (GtkButton      *button,
134                  MilkMainWindow *window)
135 {
136         g_debug ("FIXME: implement 'edit' action");
137 }
138
139 static MenuItem menu_items_always_shown[] = {
140         {"New Task",   "menu-item-new-task",       new_task_clicked_cb},
141 };
142
143 static MenuItem menu_items_selection_required[] = {
144         {"Edit",       "menu-item-edit",           edit_clicked_cb},
145         {"Priority +", "menu-item-priority_plus",  priority_plus_clicked_cb},
146         {"Priority -", "menu-item-priority_minus", priority_minus_clicked_cb},
147         {"Complete",   "menu-item-complete",       complete_clicked_cb},
148         {"Delete",     "menu-item-delete",         delete_clicked_cb},
149 };
150
151 static void
152 task_view_selection_changed_cb (HildonTouchSelector *view,
153                                 gint                 column,
154                                 MilkMainWindow      *window)
155 {
156         MilkMainWindowPrivate *priv;
157         GList *rows;
158         gboolean show = FALSE;
159         gint i;
160
161         priv = MILK_MAIN_WINDOW_PRIVATE (window);
162
163         rows = hildon_touch_selector_get_selected_rows (view, column);
164         show = (g_list_length (rows) > 0);
165
166         for (i = 0; i < G_N_ELEMENTS (menu_items_selection_required); i++) {
167                 GtkWidget *w;
168
169                 w = g_object_get_data (
170                                 G_OBJECT (priv->app_menu),
171                                 menu_items_selection_required[i].id);
172
173                 if (show)
174                         gtk_widget_show (w);
175                 else
176                         gtk_widget_hide (w);
177         }
178 }
179
180 static GtkWidget*
181 create_menu (gpointer user_data)
182 {
183         HildonAppMenu *menu;
184         MenuItem *menu_array;
185         gint i, length;
186         GtkWidget *w;
187
188         menu = HILDON_APP_MENU (hildon_app_menu_new ());
189
190         menu_array = menu_items_always_shown;
191         length = G_N_ELEMENTS (menu_items_always_shown);
192         for (i = 0; i < length; i++) {
193                 w = hildon_button_new_with_text (
194                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
195                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
196                                 _(menu_array[i].display_name), "");
197                 g_signal_connect (w, "clicked",
198                                 G_CALLBACK (menu_array[i].callback), user_data);
199                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
200                 hildon_app_menu_append (menu, GTK_BUTTON (w));
201                 gtk_widget_show (w);
202         }
203
204         menu_array = menu_items_selection_required;
205         length = G_N_ELEMENTS (menu_items_selection_required);
206         for (i = 0; i < length; i++) {
207                 w = hildon_button_new_with_text (
208                                 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
209                                 HILDON_BUTTON_ARRANGEMENT_VERTICAL,
210                                 menu_array[i].display_name, "");
211                 g_signal_connect (w, "clicked",
212                                 G_CALLBACK (menu_array[i].callback), user_data);
213                 g_object_set_data (G_OBJECT (menu), menu_array[i].id, w);
214                 hildon_app_menu_append (menu, GTK_BUTTON (w));
215                 gtk_widget_hide (w);
216         }
217
218         gtk_widget_show (GTK_WIDGET (menu));
219
220         return GTK_WIDGET (menu);
221 }
222
223 static void
224 contact_column_render_func (GtkCellLayout   *cell_layout,
225                             GtkCellRenderer *renderer,
226                             GtkTreeModel    *model,
227                             GtkTreeIter     *iter,
228                             gpointer         user_data)
229 {
230         MilkTask *task;
231         char *title;
232
233         gtk_tree_model_get (
234                         model, iter, MILK_TASK_MODEL_COLUMN_TASK, &task, -1);
235
236         g_object_get (task, "title", &title, NULL);
237         g_object_set (renderer, "text", title, NULL);
238
239         g_free (title);
240         g_object_unref (task);
241 }
242
243 static gboolean
244 begin_auth_idle (MilkMainWindow *window)
245 {
246         MilkMainWindowPrivate *priv;
247
248         priv = MILK_MAIN_WINDOW_PRIVATE (window);
249
250         /* FIXME: is there a better place for this? */
251         priv->auth = milk_auth_get_default ();
252         /* FIXME: plug this into the task model */
253
254         /* FIXME: cut this */
255         g_debug ("trying to run the milk auth demo");
256         /* FIXME: cut this */
257         milk_auth_run_demo (priv->auth);
258
259         return FALSE;
260 }
261
262 static void
263 milk_main_window_constructed (GObject* object)
264 {
265         MilkMainWindow *self = MILK_MAIN_WINDOW (object);
266         MilkMainWindowPrivate *priv = MILK_MAIN_WINDOW_PRIVATE (object);
267         GtkWidget *w;
268         GtkTreeModel *model;
269         GtkCellRenderer *renderer;
270         HildonTouchSelectorColumn *col;
271
272         w = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
273         gtk_container_add (GTK_CONTAINER (self), w);
274         priv->main_vbox = w;
275
276         /*
277          * New Task entry
278          */
279         w = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
280         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, FALSE, FALSE, 0);
281
282         /* FIXME: change this to hildon_gtk_entry_set_placeholder_text() is
283          * fixed, since this is deprecated */
284         hildon_entry_set_placeholder (HILDON_ENTRY (w),
285                         _("Enter a new task..."));
286         priv->new_task_entry = w;
287
288         /*
289          * Task List
290          */
291         model = GTK_TREE_MODEL (milk_task_model_new ());
292         w = hildon_touch_selector_new ();
293
294
295         renderer = gtk_cell_renderer_text_new ();
296         g_object_set (renderer,
297                         "ellipsize", PANGO_ELLIPSIZE_END,
298                         NULL);
299
300         col = hildon_touch_selector_append_column (
301                         HILDON_TOUCH_SELECTOR (w), model, NULL, NULL);
302         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (col), renderer, TRUE);
303         gtk_cell_layout_set_cell_data_func (
304                         GTK_CELL_LAYOUT (col), renderer,
305                         (GtkCellLayoutDataFunc) contact_column_render_func,
306                         self, NULL);
307         g_object_unref (model);
308
309         hildon_touch_selector_set_column_selection_mode (
310                         HILDON_TOUCH_SELECTOR (w),
311                         HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
312         hildon_touch_selector_set_hildon_ui_mode (
313                         HILDON_TOUCH_SELECTOR (w), HILDON_UI_MODE_EDIT);
314         hildon_touch_selector_unselect_all (
315                         HILDON_TOUCH_SELECTOR (w), TASK_VIEW_COLUMN_TITLE);
316
317         gtk_box_pack_start (GTK_BOX (priv->main_vbox), w, TRUE, TRUE, 0);
318         g_object_set (w, "can-focus", TRUE, NULL);
319         gtk_widget_grab_focus (w);
320
321         g_signal_connect (
322                         G_OBJECT (w), "changed",
323                         G_CALLBACK (task_view_selection_changed_cb), self);
324         priv->task_view = w;
325
326         priv->app_menu = create_menu (self);
327         hildon_window_set_app_menu (
328                         HILDON_WINDOW (self), HILDON_APP_MENU (priv->app_menu));
329
330         /* break a cyclical dependency by doing this after the window is
331          * constructed */
332         g_idle_add ((GSourceFunc) begin_auth_idle, self);
333 }
334
335 static void
336 milk_main_window_class_init (MilkMainWindowClass *klass)
337 {
338         GObjectClass *object_class = G_OBJECT_CLASS (klass);
339
340         g_type_class_add_private (klass, sizeof (MilkMainWindowPrivate));
341
342         object_class->get_property = milk_main_window_get_property;
343         object_class->set_property = milk_main_window_set_property;
344         object_class->constructed = milk_main_window_constructed;
345         object_class->dispose = milk_main_window_dispose;
346 }
347
348 static void
349 milk_main_window_init (MilkMainWindow *self)
350 {
351         self->priv = G_TYPE_INSTANCE_GET_PRIVATE (
352                         self, MILK_TYPE_MAIN_WINDOW, MilkMainWindowPrivate);
353 }
354
355 GtkWidget*
356 milk_main_window_get_default ()
357 {
358         if (!default_window) {
359                 default_window = g_object_new (MILK_TYPE_MAIN_WINDOW, NULL);
360         }
361
362         return default_window;
363 }