Mercurial > geeqie.yaz
comparison src/ui_pathsel.c @ 9:d907d608745f
Sync to GQview 1.5.9 release.
########
DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS!
This CVS is never up to date with current development and is provided
solely for reference purposes, please use the latest official release
package when making any changes or translation updates.
########
author | gqview |
---|---|
date | Sat, 26 Feb 2005 00:13:35 +0000 |
parents | |
children | 606fcf461a68 |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
1 /* | |
2 * (SLIK) SimpLIstic sKin functions | |
3 * (C) 2004 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 #ifdef HAVE_CONFIG_H | |
13 # include "config.h" | |
14 #endif | |
15 #include "intl.h" | |
16 | |
17 #include <stdio.h> | |
18 #include <stdlib.h> | |
19 #include <string.h> | |
20 | |
21 #include <dirent.h> | |
22 #include <fcntl.h> | |
23 #include <unistd.h> | |
24 #include <sys/types.h> | |
25 #include <sys/stat.h> | |
26 | |
27 #include <gtk/gtk.h> | |
28 | |
29 #include <gdk/gdkkeysyms.h> /* for key values */ | |
30 | |
31 #include "ui_pathsel.h" | |
32 | |
33 #include "ui_bookmark.h" | |
34 #include "ui_fileops.h" | |
35 #include "ui_menu.h" | |
36 #include "ui_misc.h" | |
37 #include "ui_utildlg.h" | |
38 #include "ui_tabcomp.h" | |
39 #include "ui_tree_edit.h" | |
40 | |
41 | |
42 #define DEST_WIDTH 250 | |
43 #define DEST_HEIGHT 210 | |
44 | |
45 #define RENAME_PRESS_DELAY 333 /* 1/3 second, to allow double clicks */ | |
46 | |
47 #define PATH_SEL_USE_HEADINGS FALSE | |
48 | |
49 enum { | |
50 FILTER_COLUMN_NAME = 0, | |
51 FILTER_COLUMN_FILTER | |
52 }; | |
53 | |
54 typedef struct _Dest_Data Dest_Data; | |
55 struct _Dest_Data | |
56 { | |
57 GtkWidget *d_view; | |
58 GtkWidget *f_view; | |
59 GtkWidget *entry; | |
60 gchar *filter; | |
61 gchar *path; | |
62 | |
63 GList *filter_list; | |
64 GList *filter_text_list; | |
65 GtkWidget *filter_combo; | |
66 | |
67 gint show_hidden; | |
68 GtkWidget *hidden_button; | |
69 | |
70 GtkWidget *bookmark_list; | |
71 | |
72 GtkTreePath *right_click_path; | |
73 | |
74 void (*select_func)(const gchar *path, gpointer data); | |
75 gpointer select_data; | |
76 | |
77 GenericDialog *gd; /* any open confirm dialogs ? */ | |
78 }; | |
79 | |
80 typedef struct _DestDel_Data DestDel_Data; | |
81 struct _DestDel_Data | |
82 { | |
83 Dest_Data *dd; | |
84 gchar *path; | |
85 }; | |
86 | |
87 | |
88 static void dest_view_delete_dlg_cancel(GenericDialog *gd, gpointer data); | |
89 | |
90 | |
91 /* | |
92 *----------------------------------------------------------------------------- | |
93 * (private) | |
94 *----------------------------------------------------------------------------- | |
95 */ | |
96 | |
97 static void dest_free_data(GtkWidget *widget, gpointer data) | |
98 { | |
99 Dest_Data *dd = data; | |
100 | |
101 if (dd->gd) | |
102 { | |
103 GenericDialog *gd = dd->gd; | |
104 dest_view_delete_dlg_cancel(dd->gd, dd->gd->data); | |
105 generic_dialog_close(gd); | |
106 } | |
107 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); | |
108 | |
109 g_free(dd->filter); | |
110 g_free(dd->path); | |
111 g_free(dd); | |
112 } | |
113 | |
114 static gint dest_check_filter(const gchar *filter, const gchar *file) | |
115 { | |
116 const gchar *f_ptr = filter; | |
117 const gchar *strt_ptr; | |
118 gint i; | |
119 gint l; | |
120 | |
121 l = strlen(file); | |
122 | |
123 if (filter[0] == '*') return TRUE; | |
124 while (f_ptr < filter + strlen(filter)) | |
125 { | |
126 strt_ptr = f_ptr; | |
127 i=0; | |
128 while (*f_ptr != ';' && *f_ptr != '\0') | |
129 { | |
130 f_ptr++; | |
131 i++; | |
132 } | |
133 if (*f_ptr != '\0' && f_ptr[1] == ' ') f_ptr++; /* skip space immediately after separator */ | |
134 f_ptr++; | |
135 if (l >= i && strncasecmp(file + l - i, strt_ptr, i) == 0) return TRUE; | |
136 } | |
137 return FALSE; | |
138 } | |
139 | |
140 #ifndef CASE_SORT | |
141 #define CASE_SORT strcmp | |
142 #endif | |
143 | |
144 static gint dest_sort_cb(void *a, void *b) | |
145 { | |
146 return CASE_SORT((gchar *)a, (gchar *)b); | |
147 } | |
148 | |
149 static gint is_hidden(const gchar *name) | |
150 { | |
151 if (name[0] != '.') return FALSE; | |
152 if (name[1] == '\0') return FALSE; | |
153 if (name[1] == '.' && name[2] == '\0') return FALSE; | |
154 return TRUE; | |
155 } | |
156 | |
157 static void dest_populate(Dest_Data *dd, const gchar *path) | |
158 { | |
159 DIR *dp; | |
160 struct dirent *dir; | |
161 struct stat ent_sbuf; | |
162 GList *path_list = NULL; | |
163 GList *file_list = NULL; | |
164 GList *list; | |
165 GtkListStore *store; | |
166 gchar *pathl; | |
167 | |
168 if(!path) return; | |
169 | |
170 pathl = path_from_utf8(path); | |
171 dp = opendir(pathl); | |
172 if (!dp) | |
173 { | |
174 /* dir not found */ | |
175 g_free(pathl); | |
176 return; | |
177 } | |
178 while ((dir = readdir(dp)) != NULL) | |
179 { | |
180 /* skips removed files */ | |
181 if (dir->d_ino > 0 && (dd->show_hidden || !is_hidden(dir->d_name)) ) | |
182 { | |
183 gchar *name = dir->d_name; | |
184 gchar *filepath = g_strconcat(pathl, "/", name, NULL); | |
185 if (stat(filepath, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) | |
186 { | |
187 path_list = g_list_prepend(path_list, path_to_utf8(name)); | |
188 } | |
189 else if (dd->f_view) | |
190 { | |
191 if (!dd->filter || (dd->filter && dest_check_filter(dd->filter, name))) | |
192 file_list = g_list_prepend(file_list, path_to_utf8(name)); | |
193 } | |
194 g_free(filepath); | |
195 } | |
196 } | |
197 closedir(dp); | |
198 g_free(pathl); | |
199 | |
200 path_list = g_list_sort(path_list, (GCompareFunc) dest_sort_cb); | |
201 file_list = g_list_sort(file_list, (GCompareFunc) dest_sort_cb); | |
202 | |
203 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->d_view))); | |
204 gtk_list_store_clear(store); | |
205 | |
206 list = path_list; | |
207 while (list) | |
208 { | |
209 GtkTreeIter iter; | |
210 gchar *filepath; | |
211 | |
212 if (strcmp(list->data, ".") == 0) | |
213 { | |
214 filepath = g_strdup(path); | |
215 } | |
216 else if (strcmp(list->data, "..") == 0) | |
217 { | |
218 gchar *p; | |
219 filepath = g_strdup(path); | |
220 p = (gchar *)filename_from_path(filepath); | |
221 if (p - 1 != filepath) p--; | |
222 p[0] = '\0'; | |
223 } | |
224 else | |
225 { | |
226 filepath = concat_dir_and_file(path, list->data); | |
227 } | |
228 | |
229 gtk_list_store_append(store, &iter); | |
230 gtk_list_store_set(store, &iter, 0, list->data, 1, filepath, -1); | |
231 | |
232 g_free(filepath); | |
233 list = list->next; | |
234 } | |
235 | |
236 path_list_free(path_list); | |
237 | |
238 | |
239 if (dd->f_view) | |
240 { | |
241 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->f_view))); | |
242 gtk_list_store_clear(store); | |
243 | |
244 list = file_list; | |
245 while (list) | |
246 { | |
247 GtkTreeIter iter; | |
248 gchar *filepath; | |
249 const gchar *name = list->data; | |
250 | |
251 filepath = concat_dir_and_file(path, name); | |
252 | |
253 gtk_list_store_append(store, &iter); | |
254 gtk_list_store_set(store, &iter, 0, name, 1, filepath, -1); | |
255 | |
256 g_free(filepath); | |
257 list = list->next; | |
258 } | |
259 | |
260 path_list_free(file_list); | |
261 } | |
262 | |
263 g_free(dd->path); | |
264 dd->path = g_strdup(path); | |
265 } | |
266 | |
267 static void dest_change_dir(Dest_Data *dd, const gchar *path, gint retain_name) | |
268 { | |
269 gchar *old_name = NULL; | |
270 gint s = 0; | |
271 | |
272 if (retain_name) | |
273 { | |
274 const gchar *buf = gtk_entry_get_text(GTK_ENTRY(dd->entry)); | |
275 if (!isdir(buf)) | |
276 { | |
277 if (path && strcmp(path, "/") == 0) | |
278 { | |
279 old_name = g_strdup(filename_from_path(buf)); | |
280 } | |
281 else | |
282 { | |
283 old_name = g_strconcat("/", filename_from_path(buf), NULL); | |
284 s = 1; | |
285 } | |
286 } | |
287 } | |
288 | |
289 gtk_entry_set_text(GTK_ENTRY(dd->entry), path); | |
290 | |
291 dest_populate(dd, path); | |
292 | |
293 /* remember filename */ | |
294 if (old_name) | |
295 { | |
296 gint pos = -1; | |
297 gtk_editable_insert_text(GTK_EDITABLE(dd->entry), old_name, -1, &pos); | |
298 gtk_editable_select_region(GTK_EDITABLE(dd->entry), strlen(path) + s, strlen(path) + strlen(old_name)); | |
299 g_free(old_name); | |
300 } | |
301 } | |
302 | |
303 /* | |
304 *----------------------------------------------------------------------------- | |
305 * drag and drop | |
306 *----------------------------------------------------------------------------- | |
307 */ | |
308 | |
309 enum { | |
310 TARGET_URI_LIST, | |
311 TARGET_TEXT_PLAIN | |
312 }; | |
313 | |
314 static GtkTargetEntry dest_drag_types[] = { | |
315 { "text/uri-list", 0, TARGET_URI_LIST }, | |
316 { "text/plain", 0, TARGET_TEXT_PLAIN } | |
317 }; | |
318 #define dest_drag_types_n 2 | |
319 | |
320 | |
321 static void dest_dnd_set_data(GtkWidget *view, | |
322 GdkDragContext *context, GtkSelectionData *selection_data, | |
323 guint info, guint time, gpointer data) | |
324 { | |
325 gchar *path = NULL; | |
326 gchar *uri_text = NULL; | |
327 GList *list = NULL; | |
328 gint length = 0; | |
329 GtkTreeModel *model; | |
330 GtkTreeSelection *selection; | |
331 GtkTreeIter iter; | |
332 | |
333 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); | |
334 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; | |
335 | |
336 gtk_tree_model_get(model, &iter, 1, &path, -1); | |
337 if (!path) return; | |
338 | |
339 list = g_list_append(list, path); | |
340 | |
341 switch (info) | |
342 { | |
343 case TARGET_URI_LIST: | |
344 uri_text = uri_text_from_list(list, &length, FALSE); | |
345 break; | |
346 case TARGET_TEXT_PLAIN: | |
347 uri_text = uri_text_from_list(list, &length, TRUE); | |
348 break; | |
349 } | |
350 | |
351 path_list_free(list); | |
352 | |
353 if (!uri_text) return; | |
354 | |
355 gtk_selection_data_set(selection_data, selection_data->target, | |
356 8, uri_text, length); | |
357 g_free(uri_text); | |
358 } | |
359 | |
360 static void dest_dnd_init(Dest_Data *dd) | |
361 { | |
362 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->d_view), GDK_BUTTON1_MASK, | |
363 dest_drag_types, dest_drag_types_n, | |
364 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); | |
365 g_signal_connect(G_OBJECT(dd->d_view), "drag_data_get", | |
366 G_CALLBACK(dest_dnd_set_data), dd); | |
367 | |
368 if (dd->f_view) | |
369 { | |
370 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->f_view), GDK_BUTTON1_MASK, | |
371 dest_drag_types, dest_drag_types_n, | |
372 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); | |
373 g_signal_connect(G_OBJECT(dd->f_view), "drag_data_get", | |
374 G_CALLBACK(dest_dnd_set_data), dd); | |
375 } | |
376 } | |
377 | |
378 | |
379 /* | |
380 *----------------------------------------------------------------------------- | |
381 * destination widget file management utils | |
382 *----------------------------------------------------------------------------- | |
383 */ | |
384 | |
385 static void dest_view_store_selection(Dest_Data *dd, GtkTreeView *view) | |
386 { | |
387 GtkTreeModel *model; | |
388 GtkTreeSelection *selection; | |
389 GtkTreeIter iter; | |
390 | |
391 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); | |
392 dd->right_click_path = NULL; | |
393 | |
394 selection = gtk_tree_view_get_selection(view); | |
395 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) | |
396 { | |
397 return; | |
398 } | |
399 | |
400 dd->right_click_path = gtk_tree_model_get_path(model, &iter); | |
401 } | |
402 | |
403 static gint dest_view_rename_cb(TreeEditData *ted, const gchar *old, const gchar *new, gpointer data) | |
404 { | |
405 Dest_Data *dd = data; | |
406 GtkTreeModel *model; | |
407 GtkTreeIter iter; | |
408 gchar *buf; | |
409 gchar *old_path; | |
410 gchar *new_path; | |
411 | |
412 model = gtk_tree_view_get_model(GTK_TREE_VIEW(ted->tree)); | |
413 gtk_tree_model_get_iter(model, &iter, dd->right_click_path); | |
414 | |
415 gtk_tree_model_get(model, &iter, 1, &old_path, -1); | |
416 if (!old_path) return FALSE; | |
417 | |
418 buf = remove_level_from_path(old_path); | |
419 new_path = concat_dir_and_file(buf, new); | |
420 g_free(buf); | |
421 | |
422 if (isname(new_path)) | |
423 { | |
424 buf = g_strdup_printf(_("A file with name %s already exists."), new); | |
425 warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_INFO, dd->entry); | |
426 g_free(buf); | |
427 } | |
428 else if (!rename_file(old_path, new_path)) | |
429 { | |
430 buf = g_strdup_printf(_("Failed to rename %s to %s."), old, new); | |
431 warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_ERROR, dd->entry); | |
432 g_free(buf); | |
433 } | |
434 else | |
435 { | |
436 const gchar *text; | |
437 | |
438 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, new, 1, new_path, -1); | |
439 | |
440 text = gtk_entry_get_text(GTK_ENTRY(dd->entry)); | |
441 if (text && old_path && strcmp(text, old_path) == 0) | |
442 { | |
443 gtk_entry_set_text(GTK_ENTRY(dd->entry), new_path); | |
444 } | |
445 } | |
446 | |
447 g_free(old_path); | |
448 g_free(new_path); | |
449 | |
450 return TRUE; | |
451 } | |
452 | |
453 static void dest_view_rename(Dest_Data *dd, GtkTreeView *view) | |
454 { | |
455 GtkTreeModel *model; | |
456 GtkTreeIter iter; | |
457 gchar *text; | |
458 | |
459 if (!dd->right_click_path) return; | |
460 | |
461 model = gtk_tree_view_get_model(view); | |
462 gtk_tree_model_get_iter(model, &iter, dd->right_click_path); | |
463 gtk_tree_model_get(model, &iter, 0, &text, -1); | |
464 | |
465 tree_edit_by_path(view, dd->right_click_path, 0, text, | |
466 dest_view_rename_cb, dd); | |
467 | |
468 g_free(text); | |
469 } | |
470 | |
471 static void dest_view_delete_dlg_cancel(GenericDialog *gd, gpointer data) | |
472 { | |
473 DestDel_Data *dl = data; | |
474 | |
475 dl->dd->gd = NULL; | |
476 g_free(dl->path); | |
477 g_free(dl); | |
478 } | |
479 | |
480 static void dest_view_delete_dlg_ok_cb(GenericDialog *gd, gpointer data) | |
481 { | |
482 DestDel_Data *dl = data; | |
483 | |
484 if (!unlink_file(dl->path)) | |
485 { | |
486 gchar *text = g_strdup_printf(_("Unable to delete file:\n%s"), dl->path); | |
487 warning_dialog(_("File deletion failed"), text, GTK_STOCK_DIALOG_WARNING, dl->dd->entry); | |
488 g_free(text); | |
489 } | |
490 else if (dl->dd->path) | |
491 { | |
492 /* refresh list */ | |
493 gchar *path = g_strdup(dl->dd->path); | |
494 dest_populate(dl->dd, path); | |
495 g_free(path); | |
496 } | |
497 | |
498 dest_view_delete_dlg_cancel(gd, data); | |
499 } | |
500 | |
501 static void dest_view_delete(Dest_Data *dd, GtkTreeView *view) | |
502 { | |
503 gchar *path; | |
504 gchar *text; | |
505 DestDel_Data *dl; | |
506 GtkTreeModel *model; | |
507 GtkTreeIter iter; | |
508 | |
509 if (view != GTK_TREE_VIEW(dd->f_view)) return; | |
510 if (!dd->right_click_path) return; | |
511 | |
512 model = gtk_tree_view_get_model(view); | |
513 gtk_tree_model_get_iter(model, &iter, dd->right_click_path); | |
514 gtk_tree_model_get(model, &iter, 1, &path, -1); | |
515 | |
516 if (!path) return; | |
517 | |
518 dl = g_new(DestDel_Data, 1); | |
519 dl->dd = dd; | |
520 dl->path = path; | |
521 | |
522 if (dd->gd) | |
523 { | |
524 GenericDialog *gd = dd->gd; | |
525 dest_view_delete_dlg_cancel(dd->gd, dd->gd->data); | |
526 generic_dialog_close(gd); | |
527 } | |
528 | |
529 dd->gd = generic_dialog_new(_("Delete file"), PACKAGE, "dlg_confirm", | |
530 dd->entry, TRUE, | |
531 dest_view_delete_dlg_cancel, dl); | |
532 | |
533 generic_dialog_add_button(dd->gd, GTK_STOCK_DELETE, NULL, dest_view_delete_dlg_ok_cb, TRUE); | |
534 | |
535 text = g_strdup_printf(_("About to delete the file:\n %s"), path); | |
536 generic_dialog_add_message(dd->gd, GTK_STOCK_DIALOG_QUESTION, | |
537 _("Delete file"), text); | |
538 g_free(text); | |
539 | |
540 gtk_widget_show(dd->gd->dialog); | |
541 } | |
542 | |
543 static void dest_view_bookmark(Dest_Data *dd, GtkTreeView *view) | |
544 { | |
545 GtkTreeModel *model; | |
546 GtkTreeIter iter; | |
547 gchar *path; | |
548 | |
549 if (!dd->right_click_path) return; | |
550 | |
551 model = gtk_tree_view_get_model(view); | |
552 gtk_tree_model_get_iter(model, &iter, dd->right_click_path); | |
553 gtk_tree_model_get(model, &iter, 1, &path, -1); | |
554 | |
555 bookmark_list_add(dd->bookmark_list, filename_from_path(path), path); | |
556 g_free(path); | |
557 } | |
558 | |
559 static void dest_popup_dir_rename_cb(GtkWidget *widget, gpointer data) | |
560 { | |
561 Dest_Data *dd = data; | |
562 dest_view_rename(dd, GTK_TREE_VIEW(dd->d_view)); | |
563 } | |
564 | |
565 static void dest_popup_dir_bookmark_cb(GtkWidget *widget, gpointer data) | |
566 { | |
567 Dest_Data *dd = data; | |
568 dest_view_bookmark(dd, GTK_TREE_VIEW(dd->d_view)); | |
569 } | |
570 | |
571 static void dest_popup_file_rename_cb(GtkWidget *widget, gpointer data) | |
572 { | |
573 Dest_Data *dd = data; | |
574 dest_view_rename(dd, GTK_TREE_VIEW(dd->f_view)); | |
575 } | |
576 | |
577 static void dest_popup_file_delete_cb(GtkWidget *widget, gpointer data) | |
578 { | |
579 Dest_Data *dd = data; | |
580 dest_view_delete(dd, GTK_TREE_VIEW(dd->f_view)); | |
581 } | |
582 | |
583 static void dest_popup_file_bookmark_cb(GtkWidget *widget, gpointer data) | |
584 { | |
585 Dest_Data *dd = data; | |
586 dest_view_bookmark(dd, GTK_TREE_VIEW(dd->f_view)); | |
587 } | |
588 | |
589 static void dest_popup_position_cb(GtkMenu *menu, gint *x, gint *y, | |
590 gboolean *push_in, gpointer data) | |
591 { | |
592 Dest_Data *dd = data; | |
593 GtkTreeView *view; | |
594 gint cw, ch; | |
595 | |
596 view = g_object_get_data(G_OBJECT(menu), "active_view"); | |
597 | |
598 tree_view_get_cell_clamped(view, dd->right_click_path, 0, TRUE, x, y, &cw, &ch); | |
599 *y += ch; | |
600 popup_menu_position_clamp(menu, x, y, 0); | |
601 } | |
602 | |
603 static gint dest_popup_menu(Dest_Data *dd, GtkTreeView *view, | |
604 gint button, guint32 time, gint local) | |
605 { | |
606 GtkWidget *menu; | |
607 | |
608 if (!dd->right_click_path) return FALSE; | |
609 | |
610 if (view == GTK_TREE_VIEW(dd->d_view)) | |
611 { | |
612 GtkTreeModel *model; | |
613 GtkTreeIter iter; | |
614 gchar *text; | |
615 gint normal_dir; | |
616 | |
617 model = gtk_tree_view_get_model(view); | |
618 gtk_tree_model_get_iter(model, &iter, dd->right_click_path); | |
619 gtk_tree_model_get(model, &iter, 0, &text, -1); | |
620 | |
621 if (!text) return FALSE; | |
622 | |
623 normal_dir = (strcmp(text, ".") == 0 || strcmp(text, "..") == 0); | |
624 | |
625 menu = popup_menu_short_lived(); | |
626 menu_item_add_sensitive(menu, _("_Rename"), !normal_dir, | |
627 G_CALLBACK(dest_popup_dir_rename_cb), dd); | |
628 menu_item_add_stock(menu, _("Add _Bookmark"), GTK_STOCK_JUMP_TO, | |
629 G_CALLBACK(dest_popup_dir_bookmark_cb), dd); | |
630 } | |
631 else | |
632 { | |
633 menu = popup_menu_short_lived(); | |
634 menu_item_add(menu, _("_Rename"), | |
635 G_CALLBACK(dest_popup_file_rename_cb), dd); | |
636 menu_item_add_stock(menu, _("_Delete"), GTK_STOCK_DELETE, | |
637 G_CALLBACK(dest_popup_file_delete_cb), dd); | |
638 menu_item_add_stock(menu, _("Add _Bookmark"), GTK_STOCK_JUMP_TO, | |
639 G_CALLBACK(dest_popup_file_bookmark_cb), dd); | |
640 } | |
641 | |
642 if (local) | |
643 { | |
644 g_object_set_data(G_OBJECT(menu), "active_view", view); | |
645 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, | |
646 dest_popup_position_cb, dd, button, time); | |
647 } | |
648 else | |
649 { | |
650 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, time); | |
651 } | |
652 | |
653 return TRUE; | |
654 } | |
655 | |
656 static gint dest_press_cb(GtkWidget *view, GdkEventButton *event, gpointer data) | |
657 { | |
658 Dest_Data *dd = data; | |
659 GtkTreePath *tpath; | |
660 GtkTreeViewColumn *column; | |
661 gint cell_x, cell_y; | |
662 GtkTreeModel *model; | |
663 GtkTreeIter iter; | |
664 GtkTreeSelection *selection; | |
665 | |
666 if (event->button != 3 || | |
667 !gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), event->x, event->y, | |
668 &tpath, &column, &cell_x, &cell_y)) | |
669 { | |
670 return FALSE; | |
671 } | |
672 | |
673 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); | |
674 gtk_tree_model_get_iter(model, &iter, tpath); | |
675 | |
676 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); | |
677 gtk_tree_selection_select_iter(selection, &iter); | |
678 | |
679 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); | |
680 dd->right_click_path = tpath; | |
681 | |
682 return dest_popup_menu(dd, GTK_TREE_VIEW(view), 0, event->time, FALSE); | |
683 } | |
684 | |
685 static gboolean dest_keypress_cb(GtkWidget *view, GdkEventKey *event, gpointer data) | |
686 { | |
687 Dest_Data *dd = data; | |
688 | |
689 switch (event->keyval) | |
690 { | |
691 case GDK_F10: | |
692 if (!(event->state & GDK_CONTROL_MASK)) return FALSE; | |
693 case GDK_Menu: | |
694 dest_view_store_selection(dd, GTK_TREE_VIEW(view)); | |
695 dest_popup_menu(dd, GTK_TREE_VIEW(view), 0, event->time, TRUE); | |
696 return TRUE; | |
697 break; | |
698 case 'R': case 'r': | |
699 if (event->state & GDK_CONTROL_MASK) | |
700 { | |
701 dest_view_store_selection(dd, GTK_TREE_VIEW(view)); | |
702 dest_view_rename(dd, GTK_TREE_VIEW(view)); | |
703 return TRUE; | |
704 } | |
705 break; | |
706 case GDK_Delete: | |
707 dest_view_store_selection(dd, GTK_TREE_VIEW(view)); | |
708 dest_view_delete(dd, GTK_TREE_VIEW(view)); | |
709 return TRUE; | |
710 break; | |
711 case 'B' : case 'b': | |
712 if (event->state & GDK_CONTROL_MASK) | |
713 { | |
714 dest_view_store_selection(dd, GTK_TREE_VIEW(view)); | |
715 dest_view_bookmark(dd, GTK_TREE_VIEW(view)); | |
716 return TRUE; | |
717 } | |
718 break; | |
719 } | |
720 | |
721 return FALSE; | |
722 } | |
723 | |
724 static void dest_new_dir_cb(GtkWidget *widget, gpointer data) | |
725 { | |
726 Dest_Data *dd = data; | |
727 gchar *path; | |
728 gchar *buf; | |
729 const gchar *tmp; | |
730 gint from_text = FALSE; | |
731 | |
732 tmp = gtk_entry_get_text(GTK_ENTRY(dd->entry)); | |
733 if (!isname(tmp)) | |
734 { | |
735 path = g_strdup(tmp); | |
736 from_text = TRUE; | |
737 } | |
738 else | |
739 { | |
740 buf = concat_dir_and_file(dd->path, _("New folder")); | |
741 path = unique_filename(buf, NULL, " ", FALSE); | |
742 g_free(buf); | |
743 } | |
744 | |
745 if (!mkdir_utf8(path, 0755)) | |
746 { | |
747 /* failed */ | |
748 gchar *text; | |
749 | |
750 text = g_strdup_printf(_("Unable to create folder:\n%s"), filename_from_path(path)); | |
751 warning_dialog(_("Error creating folder"), text, GTK_STOCK_DIALOG_ERROR, dd->entry); | |
752 g_free(text); | |
753 } | |
754 else | |
755 { | |
756 GtkTreeIter iter; | |
757 GtkListStore *store; | |
758 const gchar *text; | |
759 | |
760 if (from_text) gtk_entry_set_text(GTK_ENTRY(dd->entry), dd->path); | |
761 | |
762 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->d_view))); | |
763 | |
764 text = filename_from_path(path); | |
765 | |
766 gtk_list_store_append(store, &iter); | |
767 gtk_list_store_set(store, &iter, 0, text, 1, path, -1); | |
768 | |
769 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); | |
770 dd->right_click_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); | |
771 | |
772 tree_edit_by_path(GTK_TREE_VIEW(dd->d_view), dd->right_click_path, 0, text, | |
773 dest_view_rename_cb, dd); | |
774 } | |
775 | |
776 g_free(path); | |
777 } | |
778 | |
779 /* | |
780 *----------------------------------------------------------------------------- | |
781 * destination widget file selection, traversal, view options | |
782 *----------------------------------------------------------------------------- | |
783 */ | |
784 | |
785 static void dest_select_cb(GtkTreeSelection *selection, gpointer data) | |
786 { | |
787 Dest_Data *dd = data; | |
788 GtkTreeView *view; | |
789 GtkTreeModel *store; | |
790 GtkTreeIter iter; | |
791 gchar *path; | |
792 | |
793 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return; | |
794 | |
795 view = gtk_tree_selection_get_tree_view(selection); | |
796 store = gtk_tree_view_get_model(view); | |
797 gtk_tree_model_get(store, &iter, 1, &path, -1); | |
798 | |
799 if (view == GTK_TREE_VIEW(dd->d_view)) | |
800 { | |
801 dest_change_dir(dd, path, (dd->f_view != NULL)); | |
802 } | |
803 else | |
804 { | |
805 gtk_entry_set_text(GTK_ENTRY(dd->entry), path); | |
806 } | |
807 | |
808 g_free(path); | |
809 } | |
810 | |
811 static void dest_activate_cb(GtkWidget *view, GtkTreePath *tpath, GtkTreeViewColumn *column, gpointer data) | |
812 { | |
813 Dest_Data *dd = data; | |
814 GtkTreeModel *store; | |
815 GtkTreeIter iter; | |
816 gchar *path; | |
817 | |
818 store = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); | |
819 gtk_tree_model_get_iter(store, &iter, tpath); | |
820 gtk_tree_model_get(store, &iter, 1, &path, -1); | |
821 | |
822 if (view == dd->d_view) | |
823 { | |
824 dest_change_dir(dd, path, (dd->f_view != NULL)); | |
825 } | |
826 else | |
827 { | |
828 if (dd->select_func) | |
829 { | |
830 dd->select_func(path, dd->select_data); | |
831 } | |
832 } | |
833 | |
834 g_free(path); | |
835 } | |
836 | |
837 static void dest_home_cb(GtkWidget *widget, gpointer data) | |
838 { | |
839 Dest_Data *dd = data; | |
840 | |
841 dest_change_dir(dd, homedir(), (dd->f_view != NULL)); | |
842 } | |
843 | |
844 static void dest_show_hidden_cb(GtkWidget *widget, gpointer data) | |
845 { | |
846 Dest_Data *dd = data; | |
847 gchar *buf; | |
848 | |
849 dd->show_hidden = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dd->hidden_button)); | |
850 | |
851 buf = g_strdup(dd->path); | |
852 dest_populate(dd, buf); | |
853 g_free(buf); | |
854 } | |
855 | |
856 static void dest_entry_changed_cb(GtkEditable *editable, gpointer data) | |
857 { | |
858 Dest_Data *dd = data; | |
859 const gchar *path; | |
860 gchar *buf; | |
861 | |
862 path = gtk_entry_get_text(GTK_ENTRY(dd->entry)); | |
863 if (strcmp(path, dd->path) == 0) return; | |
864 | |
865 buf = remove_level_from_path(path); | |
866 | |
867 if (buf && strcmp(buf, dd->path) != 0) | |
868 { | |
869 gchar *tmp = remove_trailing_slash(path); | |
870 if (isdir(tmp)) | |
871 { | |
872 dest_populate(dd, tmp); | |
873 } | |
874 else if (isdir(buf)) | |
875 { | |
876 dest_populate(dd, buf); | |
877 } | |
878 g_free(tmp); | |
879 } | |
880 g_free(buf); | |
881 } | |
882 | |
883 static void dest_filter_list_sync(Dest_Data *dd) | |
884 { | |
885 GtkWidget *entry; | |
886 GtkListStore *store; | |
887 gchar *old_text; | |
888 GList *fwork; | |
889 GList *twork; | |
890 | |
891 if (!dd->filter_list || !dd->filter_combo) return; | |
892 | |
893 entry = GTK_BIN(dd->filter_combo)->child; | |
894 old_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); | |
895 | |
896 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(dd->filter_combo))); | |
897 gtk_list_store_clear(store); | |
898 | |
899 fwork = dd->filter_list; | |
900 twork = dd->filter_text_list; | |
901 while (fwork && twork) | |
902 { | |
903 GtkTreeIter iter; | |
904 gchar *name; | |
905 gchar *filter; | |
906 | |
907 name = twork->data; | |
908 filter = fwork->data; | |
909 | |
910 gtk_list_store_append(store, &iter); | |
911 gtk_list_store_set(store, &iter, FILTER_COLUMN_NAME, name, | |
912 FILTER_COLUMN_FILTER, filter, -1); | |
913 | |
914 if (strcmp(old_text, filter) == 0) | |
915 { | |
916 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dd->filter_combo), &iter); | |
917 } | |
918 | |
919 fwork = fwork->next; | |
920 twork = twork->next; | |
921 } | |
922 | |
923 g_free(old_text); | |
924 } | |
925 | |
926 static void dest_filter_add(Dest_Data *dd, const gchar *filter, const gchar *description, gint set) | |
927 { | |
928 GList *work; | |
929 gchar *buf; | |
930 gint c = 0; | |
931 | |
932 if (!filter) return; | |
933 | |
934 work = dd->filter_list; | |
935 while (work) | |
936 { | |
937 gchar *f = work->data; | |
938 | |
939 if (strcmp(f, filter) == 0) | |
940 { | |
941 if (set) gtk_combo_box_set_active(GTK_COMBO_BOX(dd->filter_combo), c); | |
942 return; | |
943 } | |
944 work = work->next; | |
945 c++; | |
946 } | |
947 | |
948 dd->filter_list = uig_list_insert_link(dd->filter_list, g_list_last(dd->filter_list), g_strdup(filter)); | |
949 | |
950 if (description) | |
951 { | |
952 buf = g_strdup_printf("%s ( %s )", description, filter); | |
953 } | |
954 else | |
955 { | |
956 buf = g_strdup_printf("( %s )", filter); | |
957 } | |
958 dd->filter_text_list = uig_list_insert_link(dd->filter_text_list, g_list_last(dd->filter_text_list), buf); | |
959 | |
960 if (set) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(dd->filter_combo)->child), filter); | |
961 dest_filter_list_sync(dd); | |
962 } | |
963 | |
964 static void dest_filter_clear(Dest_Data *dd) | |
965 { | |
966 path_list_free(dd->filter_list); | |
967 dd->filter_list = NULL; | |
968 | |
969 path_list_free(dd->filter_text_list); | |
970 dd->filter_text_list = NULL; | |
971 | |
972 dest_filter_add(dd, "*", _("All Files"), TRUE); | |
973 } | |
974 | |
975 static void dest_filter_changed_cb(GtkEditable *editable, gpointer data) | |
976 { | |
977 Dest_Data *dd = data; | |
978 GtkWidget *entry; | |
979 const gchar *buf; | |
980 gchar *path; | |
981 | |
982 entry = GTK_BIN(dd->filter_combo)->child; | |
983 buf = gtk_entry_get_text(GTK_ENTRY(entry)); | |
984 | |
985 g_free(dd->filter); | |
986 dd->filter = NULL; | |
987 if (strlen(buf) > 0) dd->filter = g_strdup(buf); | |
988 | |
989 path = g_strdup(dd->path); | |
990 dest_populate(dd, path); | |
991 g_free(path); | |
992 } | |
993 | |
994 static void dest_bookmark_select_cb(const gchar *path, gpointer data) | |
995 { | |
996 Dest_Data *dd = data; | |
997 | |
998 if (isdir(path)) | |
999 { | |
1000 dest_change_dir(dd, path, (dd->f_view != NULL)); | |
1001 } | |
1002 else if (isfile(path) && dd->f_view) | |
1003 { | |
1004 gtk_entry_set_text(GTK_ENTRY(dd->entry), path); | |
1005 } | |
1006 } | |
1007 | |
1008 /* | |
1009 *----------------------------------------------------------------------------- | |
1010 * destination widget setup routines (public) | |
1011 *----------------------------------------------------------------------------- | |
1012 */ | |
1013 | |
1014 GtkWidget *path_selection_new_with_files(GtkWidget *entry, const gchar *path, | |
1015 const gchar *filter, const gchar *filter_desc) | |
1016 { | |
1017 GtkWidget *hbox2; | |
1018 Dest_Data *dd; | |
1019 GtkWidget *scrolled; | |
1020 GtkWidget *table; | |
1021 GtkWidget *paned; | |
1022 GtkListStore *store; | |
1023 GtkTreeSelection *selection; | |
1024 GtkTreeViewColumn *column; | |
1025 GtkCellRenderer *renderer; | |
1026 | |
1027 dd = g_new0(Dest_Data, 1); | |
1028 dd->show_hidden = FALSE; | |
1029 dd->select_func = NULL; | |
1030 dd->select_data = NULL; | |
1031 dd->gd = NULL; | |
1032 | |
1033 table = gtk_table_new(4, (filter != NULL) ? 3 : 1, FALSE); | |
1034 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP); | |
1035 gtk_table_set_row_spacing(GTK_TABLE(table), 0, PREF_PAD_GAP); | |
1036 gtk_widget_show(table); | |
1037 | |
1038 dd->entry = entry; | |
1039 g_object_set_data(G_OBJECT(dd->entry), "destination_data", dd); | |
1040 | |
1041 hbox2 = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL); | |
1042 gtk_box_set_spacing(GTK_BOX(hbox2), PREF_PAD_BUTTON_GAP); | |
1043 pref_button_new(hbox2, NULL, _("Home"), FALSE, | |
1044 G_CALLBACK(dest_home_cb), dd); | |
1045 pref_button_new(hbox2, NULL, _("New folder"), FALSE, | |
1046 G_CALLBACK(dest_new_dir_cb), dd); | |
1047 | |
1048 dd->hidden_button = gtk_check_button_new_with_label(_("Show hidden")); | |
1049 g_signal_connect(G_OBJECT(dd->hidden_button), "clicked", | |
1050 G_CALLBACK(dest_show_hidden_cb), dd); | |
1051 gtk_box_pack_end(GTK_BOX(hbox2), dd->hidden_button, FALSE, FALSE, 0); | |
1052 gtk_widget_show(dd->hidden_button); | |
1053 | |
1054 hbox2 = gtk_hbox_new(FALSE, PREF_PAD_GAP); | |
1055 if (filter) | |
1056 { | |
1057 paned = gtk_hpaned_new(); | |
1058 gtk_table_attach(GTK_TABLE(table), paned, 0, 3, 1, 2, | |
1059 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); | |
1060 gtk_widget_show(paned); | |
1061 gtk_paned_add1(GTK_PANED(paned), hbox2); | |
1062 } | |
1063 else | |
1064 { | |
1065 paned = NULL; | |
1066 gtk_table_attach(GTK_TABLE(table), hbox2, 0, 1, 1, 2, | |
1067 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); | |
1068 } | |
1069 gtk_widget_show(hbox2); | |
1070 | |
1071 /* bookmarks */ | |
1072 scrolled = bookmark_list_new(NULL, dest_bookmark_select_cb, dd); | |
1073 gtk_box_pack_start(GTK_BOX(hbox2), scrolled, FALSE, FALSE, 0); | |
1074 gtk_widget_show(scrolled); | |
1075 | |
1076 dd->bookmark_list = scrolled; | |
1077 | |
1078 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
1079 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
1080 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), | |
1081 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
1082 gtk_box_pack_start(GTK_BOX(hbox2), scrolled, TRUE, TRUE, 0); | |
1083 gtk_widget_show(scrolled); | |
1084 | |
1085 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); | |
1086 dd->d_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
1087 g_object_unref(store); | |
1088 | |
1089 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dd->d_view), PATH_SEL_USE_HEADINGS); | |
1090 | |
1091 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dd->d_view)); | |
1092 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE); | |
1093 | |
1094 column = gtk_tree_view_column_new(); | |
1095 gtk_tree_view_column_set_title(column, _("Folders")); | |
1096 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); | |
1097 | |
1098 renderer = gtk_cell_renderer_text_new(); | |
1099 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1100 gtk_tree_view_column_add_attribute(column, renderer, "text", 0); | |
1101 | |
1102 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->d_view), column); | |
1103 | |
1104 #if 0 | |
1105 /* only for debugging */ | |
1106 column = gtk_tree_view_column_new(); | |
1107 gtk_tree_view_column_set_title(column, _("Path")); | |
1108 renderer = gtk_cell_renderer_text_new(); | |
1109 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1110 gtk_tree_view_column_add_attribute(column, renderer, "text", 1); | |
1111 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->d_view), column); | |
1112 #endif | |
1113 | |
1114 gtk_widget_set_size_request(dd->d_view, DEST_WIDTH, DEST_HEIGHT); | |
1115 gtk_container_add(GTK_CONTAINER(scrolled), dd->d_view); | |
1116 gtk_widget_show(dd->d_view); | |
1117 | |
1118 g_signal_connect(G_OBJECT(dd->d_view), "button_press_event", | |
1119 G_CALLBACK(dest_press_cb), dd); | |
1120 g_signal_connect(G_OBJECT(dd->d_view), "key_press_event", | |
1121 G_CALLBACK(dest_keypress_cb), dd); | |
1122 g_signal_connect(G_OBJECT(dd->d_view), "row_activated", | |
1123 G_CALLBACK(dest_activate_cb), dd); | |
1124 g_signal_connect(G_OBJECT(dd->d_view), "destroy", | |
1125 G_CALLBACK(dest_free_data), dd); | |
1126 | |
1127 if (filter) | |
1128 { | |
1129 GtkListStore *store; | |
1130 | |
1131 hbox2 = pref_table_box(table, 2, 0, GTK_ORIENTATION_HORIZONTAL, NULL); | |
1132 pref_label_new(hbox2, _("Filter:")); | |
1133 | |
1134 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); | |
1135 | |
1136 dd->filter_combo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(store), | |
1137 FILTER_COLUMN_FILTER); | |
1138 g_object_unref(store); | |
1139 gtk_cell_layout_clear(GTK_CELL_LAYOUT(dd->filter_combo)); | |
1140 renderer = gtk_cell_renderer_text_new(); | |
1141 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dd->filter_combo), renderer, TRUE); | |
1142 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dd->filter_combo), renderer, | |
1143 "text", FILTER_COLUMN_NAME, NULL); | |
1144 #if 0 | |
1145 gtk_combo_set_case_sensitive(GTK_COMBO(dd->filter_combo), TRUE); | |
1146 #endif | |
1147 gtk_box_pack_start(GTK_BOX(hbox2), dd->filter_combo, TRUE, TRUE, 0); | |
1148 gtk_widget_show(dd->filter_combo); | |
1149 | |
1150 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
1151 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
1152 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), | |
1153 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
1154 if (paned) | |
1155 { | |
1156 gtk_paned_add2(GTK_PANED(paned), scrolled); | |
1157 } | |
1158 else | |
1159 { | |
1160 gtk_table_attach(GTK_TABLE(table), scrolled, 2, 3, 1, 2, | |
1161 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); | |
1162 } | |
1163 gtk_widget_show(scrolled); | |
1164 | |
1165 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); | |
1166 dd->f_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
1167 g_object_unref(store); | |
1168 | |
1169 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dd->f_view), PATH_SEL_USE_HEADINGS); | |
1170 | |
1171 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dd->f_view)); | |
1172 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE); | |
1173 | |
1174 column = gtk_tree_view_column_new(); | |
1175 gtk_tree_view_column_set_title(column, _("Files")); | |
1176 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); | |
1177 | |
1178 renderer = gtk_cell_renderer_text_new(); | |
1179 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1180 gtk_tree_view_column_add_attribute(column, renderer, "text", 0); | |
1181 | |
1182 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->f_view), column); | |
1183 | |
1184 gtk_widget_set_size_request(dd->f_view, DEST_WIDTH, DEST_HEIGHT); | |
1185 gtk_container_add(GTK_CONTAINER(scrolled), dd->f_view); | |
1186 gtk_widget_show(dd->f_view); | |
1187 | |
1188 g_signal_connect(G_OBJECT(dd->f_view), "button_press_event", | |
1189 G_CALLBACK(dest_press_cb), dd); | |
1190 g_signal_connect(G_OBJECT(dd->f_view), "key_press_event", | |
1191 G_CALLBACK(dest_keypress_cb), dd); | |
1192 g_signal_connect(G_OBJECT(dd->f_view), "row_activated", | |
1193 G_CALLBACK(dest_activate_cb), dd); | |
1194 g_signal_connect(selection, "changed", | |
1195 G_CALLBACK(dest_select_cb), dd); | |
1196 | |
1197 dest_filter_clear(dd); | |
1198 dest_filter_add(dd, filter, filter_desc, TRUE); | |
1199 | |
1200 dd->filter = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(dd->filter_combo)->child))); | |
1201 } | |
1202 | |
1203 if (path && path[0] == '/' && isdir(path)) | |
1204 { | |
1205 dest_populate(dd, path); | |
1206 } | |
1207 else | |
1208 { | |
1209 gchar *buf = remove_level_from_path(path); | |
1210 if (buf && buf[0] == '/' && isdir(buf)) | |
1211 { | |
1212 dest_populate(dd, buf); | |
1213 } | |
1214 else | |
1215 { | |
1216 gint pos = -1; | |
1217 | |
1218 dest_populate(dd, (gchar *)homedir()); | |
1219 if (path) gtk_editable_insert_text(GTK_EDITABLE(dd->entry), "/", -1, &pos); | |
1220 if (path) gtk_editable_insert_text(GTK_EDITABLE(dd->entry), path, -1, &pos); | |
1221 } | |
1222 g_free(buf); | |
1223 } | |
1224 | |
1225 if (dd->filter_combo) | |
1226 { | |
1227 g_signal_connect(G_OBJECT(GTK_BIN(dd->filter_combo)->child), "changed", | |
1228 G_CALLBACK(dest_filter_changed_cb), dd); | |
1229 } | |
1230 g_signal_connect(G_OBJECT(dd->entry), "changed", | |
1231 G_CALLBACK(dest_entry_changed_cb), dd); | |
1232 | |
1233 dest_dnd_init(dd); | |
1234 | |
1235 return table; | |
1236 } | |
1237 | |
1238 GtkWidget *path_selection_new(const gchar *path, GtkWidget *entry) | |
1239 { | |
1240 return path_selection_new_with_files(entry, path, NULL, NULL); | |
1241 } | |
1242 | |
1243 void path_selection_sync_to_entry(GtkWidget *entry) | |
1244 { | |
1245 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data"); | |
1246 const gchar *path; | |
1247 | |
1248 if (!dd) return; | |
1249 | |
1250 path = gtk_entry_get_text(GTK_ENTRY(entry)); | |
1251 | |
1252 if (isdir(path) && strcmp(path, dd->path) != 0) | |
1253 { | |
1254 dest_populate(dd, path); | |
1255 } | |
1256 else | |
1257 { | |
1258 gchar *buf = remove_level_from_path(path); | |
1259 if (isdir(buf) && strcmp(buf, dd->path) != 0) | |
1260 { | |
1261 dest_populate(dd, buf); | |
1262 } | |
1263 g_free(buf); | |
1264 } | |
1265 } | |
1266 | |
1267 void path_selection_add_select_func(GtkWidget *entry, | |
1268 void (*func)(const gchar *, gpointer), gpointer data) | |
1269 { | |
1270 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data"); | |
1271 | |
1272 if (!dd) return; | |
1273 | |
1274 dd->select_func = func; | |
1275 dd->select_data = data; | |
1276 } | |
1277 | |
1278 void path_selection_add_filter(GtkWidget *entry, const gchar *filter, const gchar *description, gint set) | |
1279 { | |
1280 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data"); | |
1281 | |
1282 if (!dd) return; | |
1283 if (!filter) return; | |
1284 | |
1285 dest_filter_add(dd, filter, description, set); | |
1286 } | |
1287 | |
1288 void path_selection_clear_filter(GtkWidget *entry) | |
1289 { | |
1290 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data"); | |
1291 | |
1292 if (!dd) return; | |
1293 | |
1294 dest_filter_clear(dd); | |
1295 } | |
1296 |