1 /*
2 * Copyright (C) 2005 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20 #define LOCAL_DEBUG
21 #include "../configure.h"
22
23 #include "../libAfterStep/asapp.h"
24 #include "../libAfterStep/screen.h"
25 #include "../libAfterImage/afterimage.h"
26
27 #include <unistd.h>
28
29 #include "asgtk.h"
30 #include "asgtkai.h"
31 #include "asgtkdirtree.h"
32
33 #define TREE_NAME 0
34 #define TREE_FULLPATH 1
35 #define TREE_SCANNED 2
36 #define TREE_COLUMNS 3
37
38
39 /* local function prototypes */
40 static void asgtk_dir_tree_class_init (ASGtkDirTreeClass * klass);
41 static void asgtk_dir_tree_init (ASGtkDirTree * iv);
42 static void asgtk_dir_tree_dispose (GObject * object);
43 static void asgtk_dir_tree_finalize (GObject * object);
44 static void asgtk_dir_tree_style_set (GtkWidget * widget,
45 GtkStyle * prev_style);
46 static void asgtk_dir_tree_refresh_child (GtkTreeStore * dir_store,
47 GtkTreeIter * parent,
48 char *fullchildname, int level);
49
50
51 /* private variables */
52 static GtkScrolledWindowClass *parent_class = NULL;
53
asgtk_dir_tree_get_type(void)54 GType asgtk_dir_tree_get_type (void)
55 {
56 static GType id_type = 0;
57
58 if (!id_type) {
59 static const GTypeInfo id_info = {
60 sizeof (ASGtkDirTreeClass),
61 (GBaseInitFunc) NULL,
62 (GBaseFinalizeFunc) NULL,
63 (GClassInitFunc) asgtk_dir_tree_class_init,
64 NULL, /* class_finalize */
65 NULL, /* class_data */
66 sizeof (ASGtkDirTree),
67 0, /* n_preallocs */
68 (GInstanceInitFunc) asgtk_dir_tree_init,
69 };
70
71 id_type =
72 g_type_register_static (GTK_TYPE_SCROLLED_WINDOW, "ASGtkDirTree",
73 &id_info, 0);
74 }
75
76 return id_type;
77 }
78
asgtk_dir_tree_class_init(ASGtkDirTreeClass * klass)79 static void asgtk_dir_tree_class_init (ASGtkDirTreeClass * klass)
80 {
81 GObjectClass *object_class = G_OBJECT_CLASS (klass);
82 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
83
84 parent_class = g_type_class_peek_parent (klass);
85
86 object_class->dispose = asgtk_dir_tree_dispose;
87 object_class->finalize = asgtk_dir_tree_finalize;
88
89 widget_class->style_set = asgtk_dir_tree_style_set;
90
91 }
92
asgtk_dir_tree_init(ASGtkDirTree * id)93 static void asgtk_dir_tree_init (ASGtkDirTree * id)
94 {
95 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (id),
96 GTK_POLICY_AUTOMATIC,
97 GTK_POLICY_AUTOMATIC);
98 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (id),
99 GTK_SHADOW_IN);
100 id->root = NULL;
101 }
102
asgtk_dir_tree_dispose(GObject * object)103 static void asgtk_dir_tree_dispose (GObject * object)
104 {
105 ASGtkDirTree *dt = ASGTK_DIR_TREE (object);
106
107 destroy_string (&(dt->root));
108
109 G_OBJECT_CLASS (parent_class)->dispose (object);
110 }
111
asgtk_dir_tree_finalize(GObject * object)112 static void asgtk_dir_tree_finalize (GObject * object)
113 {
114 G_OBJECT_CLASS (parent_class)->finalize (object);
115 }
116
117 static void
asgtk_dir_tree_style_set(GtkWidget * widget,GtkStyle * prev_style)118 asgtk_dir_tree_style_set (GtkWidget * widget, GtkStyle * prev_style)
119 {
120 /* ASGtkDirTree *id = ASGTK_DIR_TREE (widget); */
121
122 GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
123 }
124
125 static void
asgtk_dir_tree_sel_handler(GtkTreeSelection * selection,gpointer user_data)126 asgtk_dir_tree_sel_handler (GtkTreeSelection * selection,
127 gpointer user_data)
128 {
129 ASGtkDirTree *dt = ASGTK_DIR_TREE (user_data);
130 GtkTreeIter iter;
131 GtkTreeModel *model;
132
133 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
134 gtk_tree_model_get (model, &iter, TREE_FULLPATH, &(dt->curr_selection),
135 -1);
136 } else {
137 dt->curr_selection = NULL;
138 }
139
140 if (dt->sel_change_handler)
141 dt->sel_change_handler (dt, dt->sel_change_user_data);
142 }
143
144 static void
asgtk_dir_tree_expand_handler(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)145 asgtk_dir_tree_expand_handler (GtkTreeView * treeview, GtkTreeIter * iter,
146 GtkTreePath * path, gpointer user_data)
147 {
148 ASGtkDirTree *dt = ASGTK_DIR_TREE (user_data);
149 GtkTreeModel *model = dt->tree_model;
150 GtkTreeIter child_iter;
151
152 gtk_tree_path_down (path);
153 gtk_tree_model_get_iter (model, &child_iter, path);
154
155 do {
156 char *fullpath;
157 int scanned = 0;
158
159 gtk_tree_model_get (model, &child_iter, TREE_FULLPATH, &fullpath,
160 TREE_SCANNED, &scanned, -1);
161 if (scanned == 1)
162 break;
163
164 asgtk_dir_tree_refresh_child (GTK_TREE_STORE (model), &child_iter,
165 fullpath, 1);
166 gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter, TREE_SCANNED,
167 1, -1);
168 }
169 while (gtk_tree_model_iter_next (model, &child_iter));
170 }
171
172 /* public functions */
asgtk_dir_tree_new()173 GtkWidget *asgtk_dir_tree_new ()
174 {
175 ASGtkDirTree *dt;
176 GtkTreeSelection *selection;
177
178 dt = g_object_new (ASGTK_TYPE_DIR_TREE, NULL);
179
180 dt->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
181 dt->tree_model =
182 GTK_TREE_MODEL (gtk_tree_store_new
183 (TREE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
184 G_TYPE_UINT));
185
186 gtk_container_add (GTK_CONTAINER (dt), GTK_WIDGET (dt->tree_view));
187 gtk_tree_view_set_model (dt->tree_view, dt->tree_model);
188 gtk_widget_show (GTK_WIDGET (dt->tree_view));
189 dt->cell = gtk_cell_renderer_text_new ();
190
191 dt->column =
192 gtk_tree_view_column_new_with_attributes ("", dt->cell, "text", 0,
193 NULL);
194 gtk_tree_view_append_column (dt->tree_view,
195 GTK_TREE_VIEW_COLUMN (dt->column));
196
197 selection = gtk_tree_view_get_selection (dt->tree_view);
198 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
199 g_signal_connect (selection, "changed",
200 G_CALLBACK (asgtk_dir_tree_sel_handler), dt);
201 g_signal_connect (dt->tree_view, "row-expanded",
202 G_CALLBACK (asgtk_dir_tree_expand_handler), dt);
203
204 colorize_gtk_tree_view_window (GTK_WIDGET (dt));
205 LOCAL_DEBUG_OUT ("created image ASGtkDirTree object %p", dt);
206 return GTK_WIDGET (dt);
207 }
208
209 void
asgtk_dir_tree_set_root(ASGtkDirTree * dt,char * root,GtkTreeModel * saved_model)210 asgtk_dir_tree_set_root (ASGtkDirTree * dt, char *root,
211 GtkTreeModel * saved_model)
212 {
213 GtkTreeModel *old_model;
214
215 g_return_if_fail (ASGTK_IS_DIR_TREE (dt));
216
217 if (dt->root == NULL && root == NULL)
218 return;
219 if (dt->root && root && strcmp (dt->root, root) == 0)
220 return;
221 destroy_string (&(dt->root));
222
223 if (root)
224 dt->root = mystrdup (root);
225
226 dt->curr_selection = NULL;
227 old_model = GTK_TREE_MODEL (dt->tree_model);
228
229 if (saved_model != NULL)
230 dt->tree_model = g_object_ref (saved_model);
231 else
232 dt->tree_model =
233 GTK_TREE_MODEL (gtk_tree_store_new
234 (TREE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
235 G_TYPE_UINT));
236 gtk_tree_view_set_model (dt->tree_view, dt->tree_model);
237
238 asgtk_dir_tree_refresh (dt);
239 g_object_unref (old_model);
240
241 }
242
asgtk_dir_tree_get_model(ASGtkDirTree * dt)243 GtkTreeModel *asgtk_dir_tree_get_model (ASGtkDirTree * dt)
244 {
245 return g_object_ref (dt->tree_model);
246 }
247
asgtk_dir_tree_set_title(ASGtkDirTree * dt,const gchar * title)248 void asgtk_dir_tree_set_title (ASGtkDirTree * dt, const gchar * title)
249 {
250 g_return_if_fail (ASGTK_IS_DIR_TREE (dt));
251 gtk_tree_view_column_set_title (dt->column, title);
252 }
253
254 void
asgtk_dir_tree_set_sel_handler(ASGtkDirTree * dt,_ASGtkDirTree_sel_handler sel_change_handler,gpointer user_data)255 asgtk_dir_tree_set_sel_handler (ASGtkDirTree * dt,
256 _ASGtkDirTree_sel_handler
257 sel_change_handler, gpointer user_data)
258 {
259 g_return_if_fail (ASGTK_IS_DIR_TREE (dt));
260
261 dt->sel_change_handler = sel_change_handler;
262 dt->sel_change_user_data = user_data;
263
264 }
265
asgtk_dir_tree_get_selection(ASGtkDirTree * dt)266 char *asgtk_dir_tree_get_selection (ASGtkDirTree * dt)
267 {
268 char *result = NULL;
269
270 if (ASGTK_IS_DIR_TREE (dt))
271 result = mystrdup (dt->curr_selection);
272
273 return result;
274 }
275
276 static void
asgtk_dir_tree_refresh_child(GtkTreeStore * dir_store,GtkTreeIter * parent,char * fullchildname,int level)277 asgtk_dir_tree_refresh_child (GtkTreeStore * dir_store,
278 GtkTreeIter * parent, char *fullchildname,
279 int level)
280 {
281 if (--level >= 0) {
282 GtkTreeIter iter;
283 struct direntry **list = NULL;
284 int n = my_scandir (fullchildname, &list, NULL, NULL);
285
286 if (n > 0) {
287 int i;
288
289 for (i = 0; i < n; i++) {
290 if (S_ISDIR (list[i]->d_mode)) {
291 Bool skip = False;
292
293 if (list[i]->d_name[0] == '.') {
294 skip = (list[i]->d_name[1] == '\0' ||
295 (list[i]->d_name[1] == '.'
296 && list[i]->d_name[2] == '\0'));
297 }
298 if (!skip) {
299 char *fulldirname =
300 make_file_name (fullchildname, list[i]->d_name);
301
302 gtk_tree_store_append (dir_store, &iter, parent);
303 gtk_tree_store_set (dir_store, &iter, TREE_NAME,
304 list[i]->d_name, TREE_FULLPATH,
305 fulldirname, TREE_SCANNED, 0, -1);
306 if (level > 0)
307 asgtk_dir_tree_refresh_child (dir_store, &iter, fulldirname,
308 level - 1);
309 free (fulldirname);
310 }
311 }
312 free (list[i]);
313 }
314 free (list);
315 }
316 }
317 }
318
319
asgtk_dir_tree_refresh(ASGtkDirTree * dt)320 void asgtk_dir_tree_refresh (ASGtkDirTree * dt)
321 {
322 GtkTreeStore *dir_store;
323 GtkTreeIter iter;
324
325 g_return_if_fail (ASGTK_IS_DIR_TREE (dt));
326
327 dir_store = GTK_TREE_STORE (dt->tree_model);
328
329 gtk_tree_store_clear (dir_store);
330
331 if (dt->root != NULL) {
332 gtk_tree_store_append (dir_store, &iter, NULL);
333 gtk_tree_store_set (dir_store, &iter, TREE_NAME, dt->root,
334 TREE_FULLPATH, dt->root, TREE_SCANNED, 1, -1);
335 asgtk_dir_tree_refresh_child (dir_store, &iter, dt->root, 2);
336 }
337 #if 0
338 curr_sel = mystrdup (dt->curr_selection ? dt->curr_selection->name : "");
339
340 gtk_list_store_clear (GTK_LIST_STORE (dt->tree_model));
341 destroy_asimage_list (&(dt->entries));
342 dt->curr_selection = NULL;
343 if (dt->fulldirname) {
344 int count;
345 GtkTreeIter iter;
346 ASImageListEntry *curr;
347 int mini_ext_len =
348 dt->mini_extension ? strlen (dt->mini_extension) : 0;
349
350 dt->entries =
351 get_asimage_list (get_screen_visual (NULL), dt->fulldirname, 0,
352 get_screen_image_manager (NULL)->gamma, 0, 0, 0,
353 &count, NULL);
354
355 curr = dt->entries;
356 while (curr) {
357 Bool mini = False;
358
359 LOCAL_DEBUG_OUT ("adding item \"%s\"", curr->name);
360 if (mini_ext_len > 1) {
361 if (dt->mini_extension[mini_ext_len - 1] == '.')
362 mini =
363 (strncmp (curr->name, dt->mini_extension, mini_ext_len) ==
364 0);
365 else {
366 int name_len = strlen (curr->name);
367
368 if (name_len > mini_ext_len)
369 mini =
370 (strncmp
371 (&(curr->name[name_len - mini_ext_len]),
372 dt->mini_extension, mini_ext_len) == 0);
373 }
374 }
375 if (!mini && curr->type <= ASIT_Supported) {
376 gtk_list_store_append (GTK_LIST_STORE (dt->tree_model), &iter);
377 gtk_list_store_set (GTK_LIST_STORE (dt->tree_model), &iter, 0,
378 curr->name, 1, curr, -1);
379 if (++items == 1)
380 gtk_tree_selection_select_iter (gtk_tree_view_get_selection
381 (dt->tree_view), &iter);
382 else if (strcmp (curr->name, curr_sel) == 0)
383 gtk_tree_selection_select_iter (gtk_tree_view_get_selection
384 (dt->tree_view), &iter);
385 }
386 curr = curr->next;
387 }
388 /*
389 This section doesnt seem to be needed here... ?
390 :sG:
391 The following 3 lines make the file lists sorted by
392 the File Name, Ascending.
393
394 For general file listing (not dirs)
395 GtkTreeSortable *sortable;
396 sortable = GTK_TREE_SORTABLE(dt->tree_model);
397 gtk_tree_sortable_set_sort_column_id(sortable,1,GTK_SORT_ASCENDING);
398 */
399
400 }
401 if (curr_sel)
402 free (curr_sel);
403 if (items == 0) {
404 asgtk_dir_tree_sel_handler (gtk_tree_view_get_selection
405 (dt->tree_view), dt);
406 }
407 #endif
408 }
409
asgtk_dir_tree_get_curr_path(ASGtkDirTree * dt)410 GtkTreePath *asgtk_dir_tree_get_curr_path (ASGtkDirTree * dt)
411 {
412 GtkTreePath *path = NULL;
413 GtkTreeViewColumn *focus_column = NULL;
414
415 gtk_tree_view_get_cursor (dt->tree_view, &path, &focus_column);
416 return path;
417 }
418
419 void
asgtk_dir_tree_restore_curr_path(ASGtkDirTree * dt,GtkTreePath * path)420 asgtk_dir_tree_restore_curr_path (ASGtkDirTree * dt, GtkTreePath * path)
421 {
422 if (path) {
423 gtk_tree_view_expand_to_path (dt->tree_view, path);
424 gtk_tree_view_set_cursor (dt->tree_view, path, dt->column, FALSE);
425 }
426 }
427