Make sure that all timeouts in HildonBanner are removed
[hildon] / examples / hildon-bread-crumb-trail-example.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2007 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
7  * Author: Xan Lopez <xan.lopez@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  */
25
26 #include                                        <sys/types.h>
27 #include                                        <sys/stat.h>
28 #include                                        <unistd.h>
29
30 #include                                        <hildon/hildon.h>
31
32 GtkWidget *treeview;
33 gchar *current_root;
34
35 enum {
36   ICON_COL,
37   STRING_COL,
38   IS_DIR_COL,
39   N_COLS
40 };
41
42 enum {
43   SORTID_DIRALPHA = 0
44 };
45
46 static void
47 populate_store (GtkListStore *store,
48                 const gchar *path)
49 {
50   GDir *dir;
51   GError *error = NULL;
52   gchar *item;
53   GtkTreeIter iter;
54   struct stat stat_info;
55   GdkPixbuf *pixbuf = NULL;
56   GtkWidget *dummy;
57
58   dir = g_dir_open (path, 0, &error);
59   if (error)
60     {
61       g_debug ("Error populating store: %s", error->message);
62       g_error_free (error);
63       return;
64     }
65
66   /* Dummy widget for gtk_widget_render_icon */
67   dummy = gtk_label_new ("");
68
69   while ((item = (gchar*)g_dir_read_name (dir)) != NULL)
70     {
71       gchar *file_path = g_strconcat (path, "/", item, NULL);
72
73       if (stat (file_path, &stat_info) == -1)
74         {
75           g_debug ("error retrieving stat info for %s", item);
76           continue;
77         }
78       g_free (file_path);
79
80       gtk_list_store_append (store, &iter);
81
82       if (S_ISDIR (stat_info.st_mode))
83         {
84           pixbuf = gtk_widget_render_icon (dummy, GTK_STOCK_DIRECTORY,
85                                            GTK_ICON_SIZE_BUTTON, NULL);
86         }
87       else
88         {
89           pixbuf = gtk_widget_render_icon (dummy, GTK_STOCK_FILE,
90                                            GTK_ICON_SIZE_BUTTON, NULL);
91         }
92
93       gtk_list_store_set (store, &iter,
94                           ICON_COL, pixbuf,
95                           STRING_COL, item,
96                           IS_DIR_COL, S_ISDIR (stat_info.st_mode) ? TRUE : FALSE,
97                           -1);
98       if (pixbuf)
99         g_object_unref (pixbuf);
100     }
101
102   g_dir_close (dir);
103
104   gtk_widget_destroy (dummy);
105
106   return;
107 }
108
109 static void
110 free_id (gpointer data)
111 {
112   g_debug ("Freeing ID data");
113   g_free (data);
114 }
115
116 static void
117 row_activated_cb (GtkTreeView *treeview,
118                   GtkTreePath *path,
119                   GtkTreeViewColumn *column,
120                   HildonBreadCrumbTrail *bct)
121 {
122   gchar *text = NULL, *new_root;
123   GtkTreeIter iter;
124   GtkTreeModel *model;
125   gboolean is_dir;
126
127   model = gtk_tree_view_get_model (treeview);
128   gtk_tree_model_get_iter (model, &iter, path);
129   gtk_tree_model_get (model, &iter,
130                       STRING_COL, &text,
131                       IS_DIR_COL, &is_dir,
132                       -1);
133
134   if (is_dir == FALSE) goto out;
135
136   g_debug ("Clicked treeview row%s", text);
137
138   new_root = g_strconcat (g_str_equal (current_root, "/")? "" : current_root, "/", text, NULL);
139   gtk_list_store_clear (GTK_LIST_STORE (model));
140   populate_store (GTK_LIST_STORE (model), new_root);
141
142   if (g_str_equal (current_root, "/home"))
143     {
144       GtkWidget *image;
145
146       image = gtk_image_new_from_stock (GTK_STOCK_HOME, GTK_ICON_SIZE_BUTTON);
147       hildon_bread_crumb_trail_push_icon (bct, text, image, new_root, (GDestroyNotify)free_id);
148     }
149   else
150     {
151       g_debug ("Adding %s, new root %s", text, new_root);
152       hildon_bread_crumb_trail_push_text (bct, text, new_root, (GDestroyNotify)free_id);
153     }
154   
155   if (current_root)
156     {
157       g_free (current_root);
158     }
159
160   current_root = g_strdup (new_root);
161
162  out:
163   g_free (text);
164 }
165
166 static gboolean
167 crumb_clicked_cb (HildonBreadCrumbTrail *bct, gpointer id)
168 {
169   GtkTreeModel *model;
170   gchar *text = (gchar*)id;
171
172   g_debug ("bread crumb item %s clicked", text);
173   model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
174   gtk_list_store_clear (GTK_LIST_STORE (model));
175   populate_store (GTK_LIST_STORE (model), text);
176   if (current_root)
177     g_free (current_root);
178   current_root = g_strdup (text);
179
180   return FALSE;
181 }
182
183 static void
184 clear_cb (GtkWidget *button, GtkWidget *bct)
185 {
186   hildon_bread_crumb_trail_clear (HILDON_BREAD_CRUMB_TRAIL (bct));
187 }
188
189 static gint
190 sort_iter_compare_func (GtkTreeModel *model,
191                         GtkTreeIter  *a,
192                         GtkTreeIter  *b,
193                         gpointer      userdata)
194 {
195   gint sortcol = GPOINTER_TO_INT (userdata);
196   gint ret = 0;
197
198   switch (sortcol)
199     {
200     case SORTID_DIRALPHA:
201       {
202         gboolean is_dir_a, is_dir_b;
203         gchar *string_a, *string_b;
204       
205         gtk_tree_model_get (model, a, IS_DIR_COL, &is_dir_a,
206                             STRING_COL, &string_a, -1);
207         gtk_tree_model_get (model, b, IS_DIR_COL, &is_dir_b,
208                             STRING_COL, &string_b, -1);
209
210         if (is_dir_a != is_dir_b)
211           {
212             /* One is a directory, the other isn't */
213             ret = (is_dir_a == TRUE) ? -1 : 1;
214           }
215         else
216           {
217             /* Same type, alphabetical sort */
218             ret = g_utf8_collate (string_a, string_b);
219           }
220
221         g_free (string_a);
222         g_free (string_b);
223
224         break;
225       }
226     default:
227       break;
228     }
229
230   return ret;
231 }
232
233 int main (int argc, char **argv)
234 {
235 #if 1
236   HildonProgram *program;
237 #endif
238   GtkListStore *store;
239   GtkWidget *window, *scrolled_window, *vbox, *bct, *button;
240   GtkCellRenderer *renderer;
241   GtkTreeViewColumn *column;
242
243   hildon_gtk_init (&argc, &argv);
244
245   /* Main window */
246 #if 1
247   program = hildon_program_get_instance ();
248   window = hildon_window_new ();
249   hildon_program_add_window (program, HILDON_WINDOW (window));
250 #else
251   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
252 #endif
253   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
254   gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
255   g_signal_connect (window, "delete-event", gtk_main_quit, NULL);
256
257   vbox = gtk_vbox_new (FALSE, 3);
258   gtk_container_add (GTK_CONTAINER (window), vbox);
259   gtk_widget_show (vbox);
260
261   current_root = g_strdup ("/");
262
263   bct = hildon_bread_crumb_trail_new ();
264   g_signal_connect (bct, "crumb-clicked", G_CALLBACK (crumb_clicked_cb), NULL);
265   gtk_box_pack_start (GTK_BOX (vbox), bct, FALSE, FALSE, 0);
266   gtk_widget_show (bct);
267
268   hildon_bread_crumb_trail_push_text (HILDON_BREAD_CRUMB_TRAIL (bct), "/",
269                                       g_strdup ("/"), (GDestroyNotify)free_id);
270
271   /* Treeview */
272   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
273   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
274                                   GTK_POLICY_AUTOMATIC,
275                                   GTK_POLICY_AUTOMATIC);
276   store = gtk_list_store_new (N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN);
277   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
278                                    SORTID_DIRALPHA,
279                                    sort_iter_compare_func,
280                                    GINT_TO_POINTER (SORTID_DIRALPHA),
281                                    NULL);
282   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
283                                         SORTID_DIRALPHA,
284                                         GTK_SORT_ASCENDING);
285
286   populate_store (store, "/");
287   treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
288   g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), bct);
289
290   renderer = gtk_cell_renderer_pixbuf_new ();
291   column = gtk_tree_view_column_new_with_attributes ("Icon",
292                                                      renderer,
293                                                      "pixbuf", ICON_COL,
294                                                      NULL);
295   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
296
297   renderer = gtk_cell_renderer_text_new ();
298   column = gtk_tree_view_column_new_with_attributes ("Name",
299                                                      renderer,
300                                                      "text", STRING_COL,
301                                                      NULL);
302   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
303
304   gtk_container_add (GTK_CONTAINER (scrolled_window), treeview);
305   gtk_widget_show (treeview);
306   gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
307   gtk_widget_show (scrolled_window);
308
309   button = gtk_button_new_with_label ("Clear!");
310   g_signal_connect (G_OBJECT (button), "clicked",
311                     G_CALLBACK (clear_cb), bct);
312   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
313   gtk_widget_show (button);
314
315   gtk_widget_show (window);
316
317   gtk_main ();
318
319   return 0;
320 }