* examples/hildon-bread-crumb-trail-example.c: * src/Makefile.am: * src/hildon-bread...
[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.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 gint
184 sort_iter_compare_func (GtkTreeModel *model,
185                         GtkTreeIter  *a,
186                         GtkTreeIter  *b,
187                         gpointer      userdata)
188 {
189   gint sortcol = GPOINTER_TO_INT (userdata);
190   gint ret = 0;
191
192   switch (sortcol)
193     {
194     case SORTID_DIRALPHA:
195       {
196         gboolean is_dir_a, is_dir_b;
197         gchar *string_a, *string_b;
198       
199         gtk_tree_model_get (model, a, IS_DIR_COL, &is_dir_a,
200                             STRING_COL, &string_a, -1);
201         gtk_tree_model_get (model, b, IS_DIR_COL, &is_dir_b,
202                             STRING_COL, &string_b, -1);
203
204         if (is_dir_a != is_dir_b)
205           {
206             /* One is a directory, the other isn't */
207             ret = (is_dir_a == TRUE) ? -1 : 1;
208           }
209         else
210           {
211             /* Same type, alphabetical sort */
212             ret = g_utf8_collate (string_a, string_b);
213             g_free (string_a);
214             g_free (string_b);
215           }
216         break;
217       }
218     default:
219       break;
220     }
221
222   return ret;
223 }
224
225 int main (int argc, char **argv)
226 {
227 #if 1
228   HildonProgram *program;
229 #endif
230   GtkListStore *store;
231   GtkWidget *window, *scrolled_window, *vbox, *bct;
232   GtkCellRenderer *renderer;
233   GtkTreeViewColumn *column;
234
235   gtk_init (&argc, &argv);
236
237   /* Main window */
238 #if 1
239   program = hildon_program_get_instance ();
240   window = hildon_window_new ();
241   hildon_program_add_window (program, HILDON_WINDOW (window));
242 #else
243   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
244 #endif
245   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
246   gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
247   g_signal_connect (window, "delete-event", gtk_main_quit, NULL);
248
249   vbox = gtk_vbox_new (FALSE, 3);
250   gtk_container_add (GTK_CONTAINER (window), vbox);
251   gtk_widget_show (vbox);
252
253   current_root = g_strdup ("/");
254
255   bct = hildon_bread_crumb_trail_new ();
256   g_signal_connect (bct, "crumb-clicked", G_CALLBACK (crumb_clicked_cb), NULL);
257   gtk_box_pack_start (GTK_BOX (vbox), bct, FALSE, FALSE, 0);
258   gtk_widget_show (bct);
259
260   hildon_bread_crumb_trail_push_text (HILDON_BREAD_CRUMB_TRAIL (bct), "/",
261                                       g_strdup ("/"), (GDestroyNotify)free_id);
262
263   /* Treeview */
264   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
265   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
266                                   GTK_POLICY_AUTOMATIC,
267                                   GTK_POLICY_AUTOMATIC);
268   store = gtk_list_store_new (N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN);
269   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
270                                    SORTID_DIRALPHA,
271                                    sort_iter_compare_func,
272                                    GINT_TO_POINTER (SORTID_DIRALPHA),
273                                    NULL);
274   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
275                                         SORTID_DIRALPHA,
276                                         GTK_SORT_ASCENDING);
277
278   populate_store (store, "/");
279   treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
280   g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), bct);
281
282   renderer = gtk_cell_renderer_pixbuf_new ();
283   column = gtk_tree_view_column_new_with_attributes ("Icon",
284                                                      renderer,
285                                                      "pixbuf", ICON_COL,
286                                                      NULL);
287   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
288
289   renderer = gtk_cell_renderer_text_new ();
290   column = gtk_tree_view_column_new_with_attributes ("Name",
291                                                      renderer,
292                                                      "text", STRING_COL,
293                                                      NULL);
294   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
295
296   gtk_container_add (GTK_CONTAINER (scrolled_window), treeview);
297   gtk_widget_show (treeview);
298   gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
299   gtk_widget_show (scrolled_window);
300
301   gtk_widget_show (window);
302
303   gtk_main ();
304
305   return 0;
306 }