2007-09-25 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / plugins / file-manager / file-model.c
bloba62a2aced435e2a6b565920ebc34ad52eed79c20
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) Johannes Schmid 2007 <jhs@gnome.org>
5 *
6 * anjuta is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * anjuta is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with anjuta. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include "file-model.h"
26 #include <gdl/gdl-icons.h>
27 #include <glib/gi18n.h>
28 #include <string.h>
30 #include <libgnomevfs/gnome-vfs.h>
32 #define DIRECTORY_MIME_TYPE "x-directory/normal"
33 #define DIRECTORY_OPEN "x-directory/open"
34 #define ICON_SIZE 12
36 enum
38 PROP_0,
39 PROP_BASE_URI
42 typedef struct _FileModelPrivate FileModelPrivate;
44 struct _FileModelPrivate
46 gchar* base_uri;
48 GdlIcons* icons;
50 guint expand_idle_id;
53 typedef struct _FileModelIdleExpand FileModelIdleExpand;
54 struct _FileModelIdleExpand
56 FileModel* model;
57 GList* files;
58 GtkTreePath* path;
59 gchar* uri;
62 #define FILE_MODEL_GET_PRIVATE(o) \
63 (G_TYPE_INSTANCE_GET_PRIVATE((o), FILE_TYPE_MODEL, FileModelPrivate))
65 G_DEFINE_TYPE (FileModel, file_model, GTK_TYPE_TREE_STORE);
67 static void
68 file_model_cancel_expand_idle(FileModel* model)
70 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE(model);
72 if (priv->expand_idle_id)
74 GSource* source = g_main_context_find_source_by_id (g_main_context_default(),
75 priv->expand_idle_id);
76 g_source_destroy (source);
77 priv->expand_idle_id = 0;
81 static void
82 file_model_add_dummy (FileModel* model,
83 GtkTreeIter* iter)
85 FileModelPrivate* priv =
86 FILE_MODEL_GET_PRIVATE (model);
87 GtkTreeStore* store = GTK_TREE_STORE (model);
88 GtkTreeIter dummy;
90 gtk_tree_store_append (store, &dummy, iter);
91 gtk_tree_store_set (store, &dummy,
92 COLUMN_FILENAME, _("Loading..."),
93 -1);
96 static gboolean
97 file_model_expand_idle (gpointer data)
99 FileModelIdleExpand* expand = (FileModelIdleExpand*) data;
100 FileModel* model = expand->model;
101 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE (model);
102 GtkTreeStore* store = GTK_TREE_STORE (model);
103 GtkTreeIter parent;
105 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL(model), &parent, expand->path))
106 return FALSE;
107 if (expand->files)
109 GList* file = expand->files;
110 GnomeVFSFileInfo* info = (GnomeVFSFileInfo*) file->data;
111 GtkTreeIter new_iter;
112 GdkPixbuf* pixbuf;
113 gboolean directory = FALSE;
115 /* Set pointer to the next element */
116 expand->files = g_list_next (file);
118 /* Ignore hidden files */
119 if (g_str_has_prefix (info->name, "."))
121 return TRUE;
124 /* Create file entry in tree */
125 const gchar* mime_type = gnome_vfs_file_info_get_mime_type (info);
126 gchar* uri = g_build_filename (expand->uri, info->name, NULL);
128 pixbuf = gdl_icons_get_mime_icon (priv->icons, mime_type);
130 gtk_tree_store_append (store, &new_iter, &parent);
132 if (g_str_equal (mime_type, DIRECTORY_MIME_TYPE))
134 file_model_add_dummy (model, &new_iter);
135 directory = TRUE;
138 gtk_tree_store_set (store, &new_iter,
139 COLUMN_FILENAME, info->name,
140 COLUMN_URI, uri,
141 COLUMN_PIXBUF, pixbuf,
142 COLUMN_IS_DIR, directory,
143 -1);
144 g_free (uri);
145 return TRUE;
147 else
149 GtkTreeIter dummy;
150 gnome_vfs_file_info_list_free (expand->files);
151 gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &dummy, &parent);
152 gtk_tree_store_remove (store, &dummy);
154 g_free (expand->uri);
156 priv->expand_idle_id = 0;
158 return FALSE;
162 static int
163 file_model_sort (gconstpointer a, gconstpointer b)
165 GnomeVFSFileInfo* info_a = (GnomeVFSFileInfo*) a;
166 GnomeVFSFileInfo* info_b = (GnomeVFSFileInfo*) b;
167 gboolean dir_a = (info_a->type == GNOME_VFS_FILE_TYPE_DIRECTORY);
168 gboolean dir_b = (info_b->type == GNOME_VFS_FILE_TYPE_DIRECTORY);
170 if (dir_a == dir_b)
172 return strcasecmp (info_a->name, info_b->name);
174 else if (dir_a)
176 return -1;
178 else if (dir_b)
180 return 1;
182 else
183 return 0;
186 static void
187 file_model_row_expanded (GtkTreeView* tree_view, GtkTreeIter* iter,
188 GtkTreePath* path)
190 FileModel* model = FILE_MODEL(gtk_tree_view_get_model(tree_view));
191 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE (model);
192 gchar* uri;
193 GList* files = NULL;
195 gtk_tree_model_get (GTK_TREE_MODEL(model), iter, COLUMN_URI, &uri, -1);
197 if (gnome_vfs_directory_list_load (&files, uri,
198 GNOME_VFS_FILE_INFO_GET_MIME_TYPE) ==
199 GNOME_VFS_OK)
201 files = g_list_sort (files, file_model_sort);
202 FileModelIdleExpand* expand = g_new0 (FileModelIdleExpand, 1);
203 expand->files = files;
204 expand->path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
205 expand->model = model;
206 expand->uri = uri;
208 priv->expand_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
209 (GSourceFunc) file_model_expand_idle,
210 (gpointer) expand,
211 (GDestroyNotify) g_free);
213 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
214 COLUMN_PIXBUF,
215 gdl_icons_get_mime_icon (priv->icons, DIRECTORY_OPEN),
216 -1);
221 static void
222 file_model_row_collapsed (GtkTreeView* tree_view, GtkTreeIter* iter,
223 GtkTreePath* path)
225 FileModel* model = FILE_MODEL(gtk_tree_view_get_model(tree_view));
226 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE (model);
227 GtkTreeIter child;
229 while (gtk_tree_model_iter_children (GTK_TREE_MODEL(model), &child, iter))
231 gtk_tree_store_remove (GTK_TREE_STORE (model), &child);
233 file_model_add_dummy (model, iter);
234 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
235 COLUMN_PIXBUF,
236 gdl_icons_get_folder_icon (priv->icons),
237 -1);
240 static void
241 file_model_init (FileModel *object)
243 FileModel* model = FILE_MODEL(object);
244 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE (model);
246 priv->icons = gdl_icons_new(ICON_SIZE);
249 static void
250 file_model_finalize (GObject *object)
252 FileModel* model = FILE_MODEL(object);
253 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE(model);
255 g_object_unref (G_OBJECT(priv->icons));
256 G_OBJECT_CLASS (file_model_parent_class)->finalize (object);
259 static void
260 file_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
262 g_return_if_fail (FILE_IS_MODEL (object));
263 FileModel* model = FILE_MODEL(object);
264 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE(model);
266 switch (prop_id)
268 case PROP_BASE_URI:
269 g_free (priv->base_uri);
270 priv->base_uri = g_strdup (g_value_get_string (value));
271 break;
272 default:
273 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 break;
278 static void
279 file_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
281 g_return_if_fail (FILE_IS_MODEL (object));
282 FileModel* model = FILE_MODEL(object);
283 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE(model);
285 switch (prop_id)
287 case PROP_BASE_URI:
288 g_value_set_string (value, priv->base_uri);
289 break;
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 break;
296 static void
297 file_model_class_init (FileModelClass *klass)
299 GObjectClass* object_class = G_OBJECT_CLASS (klass);
300 GtkTreeStoreClass* parent_class = GTK_TREE_STORE_CLASS (klass);
302 object_class->finalize = file_model_finalize;
303 object_class->set_property = file_model_set_property;
304 object_class->get_property = file_model_get_property;
306 g_type_class_add_private (object_class, sizeof(FileModelPrivate));
308 g_object_class_install_property (object_class,
309 PROP_BASE_URI,
310 g_param_spec_string ("base_uri",
311 "Base uri",
312 "Base uri",
313 "NULL",
314 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
318 FileModel*
319 file_model_new (GtkTreeView* tree_view, const gchar* base_uri)
321 GObject* model =
322 g_object_new (FILE_TYPE_MODEL, "base_uri", base_uri, NULL);
323 GType types[N_COLUMNS] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
324 G_TYPE_BOOLEAN};
326 g_signal_connect (G_OBJECT (tree_view), "row-collapsed",
327 G_CALLBACK (file_model_row_collapsed), model);
328 g_signal_connect (G_OBJECT (tree_view), "row-expanded",
329 G_CALLBACK (file_model_row_expanded), model);
331 gtk_tree_store_set_column_types (GTK_TREE_STORE (model), N_COLUMNS,
332 types);
334 return FILE_MODEL(model);
337 void
338 file_model_refresh (FileModel* model)
340 GtkTreeStore* store = GTK_TREE_STORE (model);
341 GtkTreeIter iter;
342 FileModelPrivate* priv = FILE_MODEL_GET_PRIVATE(model);
344 gchar* path = gnome_vfs_get_local_path_from_uri (priv->base_uri);
345 gchar* basename = g_path_get_basename (path);
346 GdkPixbuf* pixbuf = gdl_icons_get_folder_icon (priv->icons);
348 file_model_cancel_expand_idle(model);
350 gtk_tree_store_clear (store);
351 gtk_tree_store_append (store, &iter, NULL);
353 gtk_tree_store_set (store, &iter,
354 COLUMN_FILENAME, basename,
355 COLUMN_URI, priv->base_uri,
356 COLUMN_PIXBUF, pixbuf,
357 COLUMN_IS_DIR, TRUE,
358 -1);
359 g_free (basename);
360 g_free (path);
362 file_model_add_dummy (model, &iter);
365 gchar*
366 file_model_get_uri (FileModel* model, GtkTreeIter* iter)
368 gchar* uri;
369 gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COLUMN_URI, &uri, -1);
371 return uri;
374 gchar*
375 file_model_get_filename (FileModel* model, GtkTreeIter* iter)
377 gchar* filename;
378 gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COLUMN_FILENAME, &filename, -1);
380 return filename;