914d57b9d4eba671e61569b93b2c64f93ae75283
[geeqie.git] / src / pathsel.c
1 /*
2  * GQview image viewer
3  * (C)1999 John Ellis
4  *
5  * Author: John Ellis
6  *
7  */
8
9 #include "gqview.h"
10
11 #define DEST_WIDTH 250
12 #define DEST_HEIGHT 100
13
14 typedef struct _Dest_Data Dest_Data;
15 struct _Dest_Data
16 {
17         GtkWidget *d_clist;
18         GtkWidget *f_clist;
19         GtkWidget *entry;
20         gchar *filter;
21         gchar *path;
22 };
23
24 static void dest_free_data(GtkWidget *widget, gpointer data);
25 static gint dest_check_filter(gchar *filter, gchar *file);
26 static gint dest_sort_cb(void *a, void *b);
27 static void dest_populate(Dest_Data *dd, gchar *path);
28 static void dest_select_cb(GtkWidget *clist, gint row, gint column,
29                           GdkEventButton *bevent, gpointer data);
30
31 /*
32  *-----------------------------------------------------------------------------
33  * destination widget routines (private)
34  *-----------------------------------------------------------------------------
35  */ 
36
37 static void dest_free_data(GtkWidget *widget, gpointer data)
38 {
39         Dest_Data *dd = data;
40         g_free(dd->filter);
41         g_free(dd->path);
42         g_free(dd);
43 }
44
45 static gint dest_check_filter(gchar *filter, gchar *file)
46 {
47         gchar *f_ptr = filter;
48         gchar *file_ptr;
49         gchar *strt_ptr;
50         gint i;
51
52         if (filter[0] == '*') return TRUE;
53         while (f_ptr < filter + strlen(filter))
54                 {
55                 strt_ptr = f_ptr;
56                 i=0;
57                 while (*f_ptr != ';' && *f_ptr != '\0')
58                         {
59                         f_ptr++;
60                         i++;
61                         }
62                 f_ptr++;
63                 file_ptr = file + strlen(file) - i;
64                 if (!strncasecmp(file_ptr, strt_ptr, i)) return TRUE;
65                 }
66         return FALSE;
67 }
68
69 static gint dest_sort_cb(void *a, void *b)
70 {
71         return strcmp((gchar *)a, (gchar *)b);
72 }
73
74 static void dest_populate(Dest_Data *dd, gchar *path)
75 {
76         DIR *dp;
77         struct dirent *dir;
78         struct stat ent_sbuf;
79         gchar *buf[2];
80         GList *path_list = NULL;
81         GList *file_list = NULL;
82         GList *list;
83
84         buf[1] = NULL;
85
86         if((dp = opendir(path))==NULL)
87                 {
88                 /* dir not found */
89                 return;
90                 }
91         while ((dir = readdir(dp)) != NULL)
92                 {
93                 /* skips removed files */
94                 if (dir->d_ino > 0)
95                         {
96                         gchar *name = dir->d_name;
97                         gchar *filepath = g_strconcat(path, "/", name, NULL);
98                         if (stat(filepath,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
99                                 {
100                                 path_list = g_list_prepend(path_list, g_strdup(name));
101                                 }
102                         else if (dd->f_clist)
103                                 {
104                                 if (!dd->filter || (dd->filter && dest_check_filter(dd->filter, name)))
105                                         file_list = g_list_prepend(file_list, g_strdup(name));
106                                 }
107                         g_free(filepath);
108                         }
109                 }
110         closedir(dp);
111
112         path_list = g_list_sort(path_list, (GCompareFunc) dest_sort_cb);
113         file_list = g_list_sort(file_list, (GCompareFunc) dest_sort_cb);
114
115         gtk_clist_freeze(GTK_CLIST(dd->d_clist));
116         gtk_clist_clear(GTK_CLIST(dd->d_clist));
117
118         list = path_list;
119         while (list)
120                 {
121                 gint row;
122                 gchar *filepath;
123                 if (strcmp(list->data, ".") == 0)
124                         {
125                         filepath = g_strdup(path);
126                         }
127                 else if (strcmp(list->data, "..") == 0)
128                         {
129                         gchar *p;
130                         filepath = g_strdup(path);
131                         p = filename_from_path(filepath);
132                         if (p - 1 != filepath) p--;
133                         p[0] = '\0';
134                         }
135                 else if (strcmp(path, "/") == 0)
136                         {
137                         filepath = g_strconcat("/", list->data, NULL);
138                         }
139                 else
140                         filepath = g_strconcat(path, "/", list->data, NULL);
141                 
142                 buf[0] = list->data;
143                 row = gtk_clist_append(GTK_CLIST(dd->d_clist),buf);
144                 gtk_clist_set_row_data_full(GTK_CLIST(dd->d_clist), row,
145                                             filepath, (GtkDestroyNotify) g_free);
146                 g_free(list->data);
147                 list = list->next;
148                 }
149
150         g_list_free(path_list);
151
152         gtk_clist_thaw(GTK_CLIST(dd->d_clist));
153
154         if (dd->f_clist)
155                 {
156                 gtk_clist_freeze(GTK_CLIST(dd->f_clist));
157                 gtk_clist_clear(GTK_CLIST(dd->f_clist));
158
159                 list = file_list;
160                 while (list)
161                         {
162                         gint row;
163                         gchar *filepath;
164                         filepath = g_strconcat(path, "/", list->data, NULL);
165                 
166                         buf[0] = list->data;
167                         row = gtk_clist_append(GTK_CLIST(dd->f_clist),buf);
168                         gtk_clist_set_row_data_full(GTK_CLIST(dd->f_clist), row,
169                                             filepath, (GtkDestroyNotify) g_free);
170                         g_free(list->data);
171                         list = list->next;
172                         }
173
174                 g_list_free(file_list);
175
176                 gtk_clist_thaw(GTK_CLIST(dd->f_clist));
177                 }
178
179         g_free(dd->path);
180         dd->path = g_strdup(path);
181 }
182
183 static void dest_select_cb(GtkWidget *clist, gint row, gint column,
184                           GdkEventButton *bevent, gpointer data)
185 {
186         Dest_Data *dd = data;
187         gchar *path = g_strdup(gtk_clist_get_row_data(GTK_CLIST(clist), row));
188         gtk_entry_set_text(GTK_ENTRY(dd->entry),path);
189
190         if (clist == dd->d_clist) dest_populate(dd, path);
191         g_free(path);
192 }
193
194 /*
195  *-----------------------------------------------------------------------------
196  * destination widget setup routines (public)
197  *-----------------------------------------------------------------------------
198  */ 
199
200 GtkWidget *destination_widget_new_with_files(gchar *path, gchar *filter, GtkWidget *entry)
201 {
202         GtkWidget *vbox;
203         Dest_Data *dd;
204         GtkWidget *scrolled;
205
206         dd = g_new0(Dest_Data, 1);
207
208         vbox = gtk_vbox_new(FALSE, 5);
209         gtk_widget_show(vbox);
210
211         dd->entry = entry;
212         gtk_object_set_data(GTK_OBJECT(dd->entry), "destination_data", dd);
213
214         scrolled = gtk_scrolled_window_new(NULL, NULL);
215         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
216                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
217         gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
218         gtk_widget_show(scrolled);
219
220         dd->d_clist=gtk_clist_new (1);
221         gtk_clist_set_column_auto_resize(GTK_CLIST(dd->d_clist), 0, TRUE);
222         gtk_signal_connect (GTK_OBJECT (dd->d_clist), "select_row",(GtkSignalFunc) dest_select_cb, dd);
223         gtk_signal_connect(GTK_OBJECT(dd->d_clist), "destroy", (GtkSignalFunc) dest_free_data, dd);
224         gtk_widget_set_usize(dd->d_clist, DEST_WIDTH, DEST_HEIGHT);
225         gtk_container_add (GTK_CONTAINER (scrolled), dd->d_clist);
226         gtk_widget_show (dd->d_clist);
227
228         if (filter)
229                 {
230                 scrolled = gtk_scrolled_window_new(NULL, NULL);
231                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
232                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
233                 gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
234                 gtk_widget_show(scrolled);
235
236                 dd->f_clist=gtk_clist_new (1);
237                 gtk_clist_set_column_auto_resize(GTK_CLIST(dd->f_clist), 0, TRUE);
238                 gtk_widget_set_usize(dd->f_clist, DEST_WIDTH, DEST_HEIGHT);
239                 gtk_signal_connect (GTK_OBJECT (dd->f_clist), "select_row",(GtkSignalFunc) dest_select_cb, dd);
240                 gtk_container_add (GTK_CONTAINER (scrolled), dd->f_clist);
241                 gtk_widget_show (dd->f_clist);
242
243                 dd->filter = g_strdup(filter);
244                 }
245
246         if (isdir(path))
247                 {
248                 dest_populate(dd, path);
249                 }
250         else
251                 {
252                 gchar *buf = remove_level_from_path(path);
253                 if (isdir(buf))
254                         {
255                         dest_populate(dd, buf);
256                         }
257                 else
258                         {
259                         dest_populate(dd, homedir());
260                         }
261                 g_free(buf);
262                 }
263         return vbox;
264 }
265
266 GtkWidget *destination_widget_new(gchar *path, GtkWidget *entry)
267 {
268         return destination_widget_new_with_files(path, NULL, entry);
269 }
270
271 void destination_widget_sync_to_entry(GtkWidget *entry)
272 {
273         Dest_Data *dd = gtk_object_get_data(GTK_OBJECT(entry), "destination_data");
274         gchar *path;
275
276         if (!dd) return;
277
278         path = gtk_entry_get_text(GTK_ENTRY(entry));
279         
280         if (isdir(path) && strcmp(path, dd->path) != 0)
281                 {
282                 dest_populate(dd, path);
283                 }
284         else
285                 {
286                 gchar *buf = remove_level_from_path(path);
287                 if (isdir(buf) && strcmp(buf, dd->path) != 0)
288                         {
289                         dest_populate(dd, buf);
290                         }
291                 g_free(buf);
292                 }
293 }
294