* Added a new call modest_window_mgr_get_current_top that returns the topmost window
[modest] / src / hildon2 / modest-hildon2-window.c
1 /* Copyright (c) 2008, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <hildon/hildon-banner.h>
31 #include <modest-platform.h>
32 #include <hildon/hildon-program.h>
33 #include <modest-maemo-utils.h>
34 #include <modest-defs.h>
35 #include <modest-ui-dimming-rules.h>
36 #include <modest-ui-dimming-manager.h>
37 #include <modest-window-priv.h>
38 #include <modest-hildon2-window.h>
39 #include <modest-ui-actions.h>
40 #include <hildon/hildon-edit-toolbar.h>
41
42 typedef struct _EditModeRegister {
43         gchar *description;
44         gchar *button_label;
45         GtkWidget *tree_view;
46         GtkSelectionMode mode;
47         ModestHildon2EditModeCallback action;
48 } EditModeRegister;
49
50 /* 'private'/'protected' functions */
51 static void modest_hildon2_window_class_init  (gpointer klass, gpointer class_data);
52 static void modest_hildon2_window_instance_init (GTypeInstance *instance, gpointer g_class);
53 static void modest_hildon2_window_finalize    (GObject *obj);
54
55 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
56 static void setup_menu (ModestHildon2Window *self);
57
58 static void modest_hildon2_window_show_toolbar (ModestWindow *self,
59                                                  gboolean show_toolbar);
60 static gboolean modest_hildon2_window_toggle_menu (HildonWindow *window,
61                                                     guint button,
62                                                     guint32 time);
63 static void modest_hildon2_window_pack_toolbar_not_implemented (ModestHildon2Window *self,
64                                                                 GtkPackType pack_type,
65                                                                 GtkWidget *toolbar);
66 static EditModeRegister *edit_mode_register_new (const gchar *description,
67                                                  const gchar *button_label,
68                                                  GtkTreeView *tree_view,
69                                                  GtkSelectionMode mode,
70                                                  ModestHildon2EditModeCallback action);
71 static void edit_mode_register_destroy (gpointer data);
72 static void edit_toolbar_button_clicked (HildonEditToolbar *toolbar,
73                                          ModestHildon2Window *self);
74 static void edit_toolbar_arrow_clicked (HildonEditToolbar *toolbar,
75                                         ModestHildon2Window *self);
76
77 typedef struct _ModestHildon2WindowPrivate ModestHildon2WindowPrivate;
78 struct _ModestHildon2WindowPrivate {
79
80         GtkWidget *app_menu;
81         ModestDimmingRulesGroup *app_menu_dimming_group;
82
83         /* Edit mode support */
84         gboolean edit_mode;
85         gint edit_command;
86         GtkWidget *edit_toolbar;
87         GtkWidget *current_edit_tree_view;
88         GHashTable *edit_mode_registry;
89 };
90 #define MODEST_HILDON2_WINDOW_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE((o), \
91                                                                             MODEST_TYPE_HILDON2_WINDOW, \
92                                                                             ModestHildon2WindowPrivate))
93
94 /* globals */
95 static GtkWindowClass *parent_class = NULL;
96
97 /************************************************************************/
98
99 GType
100 modest_hildon2_window_get_type (void)
101 {
102         static GType my_type = 0;
103         if (!my_type) {
104                 static const GTypeInfo my_info = {
105                         sizeof(ModestHildon2WindowClass),
106                         NULL,           /* base init */
107                         NULL,           /* base finalize */
108                         (GClassInitFunc) modest_hildon2_window_class_init,
109                         NULL,           /* class finalize */
110                         NULL,           /* class data */
111                         sizeof(ModestHildon2Window),
112                         1,              /* n_preallocs */
113                         (GInstanceInitFunc) modest_hildon2_window_instance_init,
114                         NULL
115                 };
116                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
117                                                   "ModestHildon2Window",
118                                                   &my_info, 0);
119         }
120         return my_type;
121 }
122
123 static void
124 modest_hildon2_window_class_init (gpointer klass, gpointer class_data)
125 {
126         GObjectClass *gobject_class;
127         gobject_class = (GObjectClass*) klass;
128         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
129         HildonWindowClass *hildon_window_class = (HildonWindowClass *) klass;
130         ModestHildon2WindowClass *modest_hildon2_window_class = (ModestHildon2WindowClass *) klass;
131
132         parent_class            = g_type_class_peek_parent (klass);
133         gobject_class->finalize = modest_hildon2_window_finalize;
134
135         g_type_class_add_private (gobject_class, sizeof(ModestHildon2WindowPrivate));
136         
137         hildon_window_class->toggle_menu = modest_hildon2_window_toggle_menu;
138
139         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
140         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
141         modest_window_class->show_toolbar_func = modest_hildon2_window_show_toolbar;
142
143         modest_hildon2_window_class->pack_toolbar_func = modest_hildon2_window_pack_toolbar_not_implemented;
144 }
145
146 static void
147 modest_hildon2_window_finalize (GObject *obj)
148 {
149         ModestHildon2WindowPrivate *priv;
150
151         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE(obj);
152
153         g_object_unref (priv->app_menu_dimming_group);
154         priv->app_menu_dimming_group = NULL;
155
156         g_hash_table_destroy (priv->edit_mode_registry);
157         priv->edit_mode_registry = NULL;
158
159         G_OBJECT_CLASS(parent_class)->finalize (obj);
160 }
161
162 static void
163 modest_hildon2_window_instance_init (GTypeInstance *instance, gpointer g_class)
164 {
165         ModestHildon2Window *self = NULL;       
166         ModestWindowPrivate *parent_priv = NULL;
167         ModestHildon2WindowPrivate *priv = NULL;
168
169         self = (ModestHildon2Window *) instance;
170         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
171         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
172
173         priv->edit_mode = FALSE;
174         priv->edit_toolbar = NULL;
175         priv->current_edit_tree_view = NULL;
176         priv->edit_command = -1;
177         priv->edit_mode_registry = g_hash_table_new_full (g_direct_hash, g_direct_equal,
178                                                           NULL, edit_mode_register_destroy);
179
180         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
181         priv->app_menu_dimming_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
182
183         setup_menu (self);
184
185         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, 
186                                                       priv->app_menu_dimming_group);
187
188         /* Dont't restore settings here, 
189          * because it requires a gtk_widget_show(), 
190          * and we don't want to do that until later,
191          * so that the UI is not visible for non-menu D-Bus activation.
192          */
193 }
194
195 static gboolean
196 on_zoom_minus_plus_not_implemented (ModestWindow *window)
197 {
198         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW (window), FALSE);
199
200         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
201         return FALSE;
202
203 }
204
205 static void 
206 modest_hildon2_window_pack_toolbar_not_implemented (ModestHildon2Window *self,
207                                                     GtkPackType pack_type,
208                                                     GtkWidget *toolbar)
209 {
210         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
211
212         g_warning ("%s not implemented", __FUNCTION__);
213 }
214
215 void
216 modest_hildon2_window_pack_toolbar (ModestHildon2Window *self,
217                                     GtkPackType pack_type,
218                                     GtkWidget *toolbar)
219 {
220         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
221
222         MODEST_HILDON2_WINDOW_GET_CLASS (self)->pack_toolbar_func (self, pack_type, toolbar);
223 }
224
225 void 
226 modest_hildon2_window_add_button_to_menu (ModestHildon2Window *self,
227                                           GtkButton *button,
228                                           ModestDimmingCallback dimming_callback)
229 {
230         ModestHildon2WindowPrivate *priv;
231
232         g_return_if_fail (MODEST_IS_HILDON2_WINDOW(self));
233         g_return_if_fail (GTK_IS_BUTTON (button));
234         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
235
236         if (dimming_callback)
237                 modest_dimming_rules_group_add_widget_rule (priv->app_menu_dimming_group,
238                                                             GTK_WIDGET (button),
239                                                             (GCallback) dimming_callback,
240                                                             MODEST_WINDOW (self));
241         hildon_app_menu_append (HILDON_APP_MENU (priv->app_menu), GTK_BUTTON (button));
242 }
243
244 void 
245 modest_hildon2_window_add_to_menu (ModestHildon2Window *self,
246                                    gchar *label,
247                                    ModestHildon2AppMenuCallback callback,
248                                    ModestDimmingCallback dimming_callback)
249 {
250         ModestHildon2WindowPrivate *priv = NULL;
251         GtkWidget *button;
252
253         g_return_if_fail (MODEST_IS_HILDON2_WINDOW(self));
254         g_return_if_fail (label && label[0] != '\0');
255         g_return_if_fail (callback != NULL);
256
257         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
258
259         button = gtk_button_new_with_label (label);
260         g_signal_connect_after (G_OBJECT (button), "clicked",
261                                 G_CALLBACK (callback), (gpointer) self);
262
263         modest_hildon2_window_add_button_to_menu (self, GTK_BUTTON (button), dimming_callback);
264 }
265
266 static void setup_menu (ModestHildon2Window *self)
267 {
268         ModestHildon2WindowPrivate *priv = NULL;
269
270         g_return_if_fail (MODEST_IS_HILDON2_WINDOW(self));
271
272         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
273
274         priv->app_menu = hildon_app_menu_new ();
275
276         /* we expect that the app menu is filled in children using the expected 
277          * add_to_menu methods */
278
279         hildon_stackable_window_set_main_menu (HILDON_STACKABLE_WINDOW (self), 
280                                                HILDON_APP_MENU (priv->app_menu));
281 }
282
283 static gboolean 
284 modest_hildon2_window_toggle_menu (HildonWindow *window,
285                                     guint button,
286                                     guint32 time)
287 {
288         ModestHildon2WindowPrivate *priv = NULL;
289
290         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (window);
291
292         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
293
294         gtk_widget_queue_resize (priv->app_menu);
295
296         return HILDON_WINDOW_CLASS (parent_class)->toggle_menu (window, button, time);
297 }
298
299 static void
300 modest_hildon2_window_show_toolbar (ModestWindow *self,
301                                     gboolean show_toolbar)
302 {
303         /* Empty implementation: Hildon 2.2 implementation
304          * doesn't switch toolbar visibility */
305 }
306
307 void 
308 modest_hildon2_window_register_edit_mode (ModestHildon2Window *self,
309                                           gint edit_mode_id,
310                                           const gchar *description,
311                                           const gchar *button_label,
312                                           GtkTreeView *tree_view,
313                                           GtkSelectionMode mode,
314                                           ModestHildon2EditModeCallback action)
315 {
316         ModestHildon2WindowPrivate *priv = NULL;
317         EditModeRegister *reg;
318
319         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
320         g_return_if_fail (edit_mode_id >= 0);
321         g_return_if_fail (description);
322         g_return_if_fail (button_label);
323         g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
324
325         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
326
327         reg = (EditModeRegister *) g_hash_table_lookup (priv->edit_mode_registry, GINT_TO_POINTER (edit_mode_id));
328         g_return_if_fail (reg == NULL);
329
330         reg = edit_mode_register_new (description, button_label, tree_view, mode, action);
331         g_hash_table_insert (priv->edit_mode_registry, GINT_TO_POINTER (edit_mode_id), (gpointer) reg);
332 }
333
334 void
335 modest_hildon2_window_set_edit_mode (ModestHildon2Window *self,
336                                      gint edit_mode_id)
337 {
338         ModestHildon2WindowPrivate *priv = NULL;
339         EditModeRegister *reg;
340         GtkTreeSelection *selection;
341
342         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
343         g_return_if_fail (edit_mode_id >= 0);
344
345         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
346         reg = (EditModeRegister *) g_hash_table_lookup (priv->edit_mode_registry, GINT_TO_POINTER (edit_mode_id));
347         g_return_if_fail (reg != NULL);
348
349         if (priv->edit_mode) {
350                 modest_hildon2_window_unset_edit_mode (self);
351         }
352
353         priv->edit_mode = TRUE;
354         priv->edit_command = edit_mode_id;
355
356         priv->current_edit_tree_view = reg->tree_view;
357         g_object_set (G_OBJECT (priv->current_edit_tree_view),
358                       "hildon-ui-mode", HILDON_UI_MODE_EDIT,
359                       NULL);
360
361         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->current_edit_tree_view));
362         gtk_tree_selection_set_mode (selection, reg->mode);
363         gtk_tree_selection_unselect_all (selection);
364
365         priv->edit_toolbar = hildon_edit_toolbar_new ();
366         hildon_edit_toolbar_set_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
367                                        reg->description);
368         hildon_edit_toolbar_set_button_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
369                                               reg->button_label);
370         modest_hildon2_window_pack_toolbar (self, GTK_PACK_START,
371                                             priv->edit_toolbar);
372
373         g_signal_connect (G_OBJECT (priv->edit_toolbar), "button-clicked",
374                           G_CALLBACK (edit_toolbar_button_clicked), (gpointer) self);
375         g_signal_connect (G_OBJECT (priv->edit_toolbar), "arrow-clicked",
376                           G_CALLBACK (edit_toolbar_arrow_clicked), (gpointer) self);
377
378         gtk_widget_show (priv->edit_toolbar);
379         gtk_widget_queue_resize (priv->current_edit_tree_view);
380         gtk_window_fullscreen (GTK_WINDOW (self));
381
382 }
383
384 void 
385 modest_hildon2_window_unset_edit_mode (ModestHildon2Window *self)
386 {
387         ModestHildon2WindowPrivate *priv = NULL;
388
389         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
390         priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
391
392         if (priv->edit_toolbar) {
393                 gtk_widget_destroy (priv->edit_toolbar);
394                 priv->edit_toolbar = NULL;
395         }
396
397         if (priv->edit_mode) {
398                 priv->edit_mode = FALSE;
399                 priv->edit_command = -1;
400                 if (priv->current_edit_tree_view) {
401                         g_object_set (G_OBJECT (priv->current_edit_tree_view), 
402                                       "hildon-ui-mode", HILDON_UI_MODE_NORMAL, 
403                                       NULL);
404                         gtk_widget_queue_resize (priv->current_edit_tree_view);
405                         priv->current_edit_tree_view = NULL;
406                 }
407                 gtk_window_unfullscreen (GTK_WINDOW (self));
408         }
409 }
410
411 static EditModeRegister *
412 edit_mode_register_new (const gchar *description,
413                         const gchar *button_label,
414                         GtkTreeView *tree_view,
415                         GtkSelectionMode mode,
416                         ModestHildon2EditModeCallback action)
417 {
418         EditModeRegister *reg;
419
420         reg = g_slice_new (EditModeRegister);
421
422         reg->description = g_strdup (description);
423         reg->button_label = g_strdup (button_label);
424         reg->tree_view = g_object_ref (tree_view);
425         reg->mode = mode;
426         reg->action = action;
427
428         return reg;
429 }
430
431 static void 
432 edit_mode_register_destroy (gpointer data)
433 {
434         EditModeRegister *reg = (EditModeRegister *) data;
435
436         g_free (reg->description);
437         g_free (reg->button_label);
438         g_object_unref (reg->tree_view);
439
440         g_slice_free (EditModeRegister, reg);
441 }
442
443 static void
444 edit_toolbar_button_clicked (HildonEditToolbar *toolbar,
445                              ModestHildon2Window *self)
446 {
447         ModestHildon2WindowPrivate *priv = MODEST_HILDON2_WINDOW_GET_PRIVATE (self);
448         EditModeRegister *reg;
449
450         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
451         
452         reg = (EditModeRegister *) g_hash_table_lookup (priv->edit_mode_registry, 
453                                                         GINT_TO_POINTER (priv->edit_command));
454         if (reg == NULL)
455                 modest_hildon2_window_unset_edit_mode (self);
456
457         if ((reg->action == NULL) || reg->action (self))
458                 modest_hildon2_window_unset_edit_mode (self);
459
460 }
461
462 static void
463 edit_toolbar_arrow_clicked (HildonEditToolbar *toolbar,
464                             ModestHildon2Window *self)
465 {
466         g_return_if_fail (MODEST_IS_HILDON2_WINDOW (self));
467         
468         modest_hildon2_window_unset_edit_mode (self);
469 }
470