2.5 filebrowser
[blender-staging.git] / source / blender / editors / space_file / fsmenu.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <math.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_linklist.h"
39 #include "BLI_dynstr.h"
40
41 #ifdef WIN32
42 #include <windows.h> /* need to include windows.h so _WIN32_IE is defined  */
43 #ifndef _WIN32_IE
44 #define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
45 #endif
46 #include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */
47 #include "BLI_winstuff.h"
48 #endif
49
50 #include "fsmenu.h"  /* include ourselves */
51
52
53 /* FSMENU HANDLING */
54
55         /* FSMenuEntry's without paths indicate seperators */
56 typedef struct _FSMenuEntry FSMenuEntry;
57 struct _FSMenuEntry {
58         FSMenuEntry *next;
59
60         char *path;
61         short save;
62         short xs, ys;
63 };
64
65 static FSMenuEntry *fsmenu_system= 0;
66 static FSMenuEntry *fsmenu_bookmarks= 0;
67 static FSMenuEntry *fsmenu_recent= 0;
68
69 static FSMenuCategory selected_category= FS_CATEGORY_SYSTEM;
70 static int selected_entry= 0;
71
72 void fsmenu_select_entry(FSMenuCategory category, int index)
73 {
74         selected_category = category;
75         selected_entry = index;
76 }
77
78 int     fsmenu_is_selected(FSMenuCategory category, int index)
79 {
80         return (category==selected_category) && (index==selected_entry);
81 }
82
83 static FSMenuEntry *fsmenu_get(FSMenuCategory category)
84 {
85         FSMenuEntry *fsmenu = NULL;
86
87         switch(category) {
88                 case FS_CATEGORY_SYSTEM:
89                         fsmenu = fsmenu_system;
90                         break;
91                 case FS_CATEGORY_BOOKMARKS:
92                         fsmenu = fsmenu_bookmarks;
93                         break;
94                 case FS_CATEGORY_RECENT:
95                         fsmenu = fsmenu_recent;
96                         break;
97         }
98         return fsmenu;
99 }
100
101 static void fsmenu_set(FSMenuCategory category, FSMenuEntry *fsmenu)
102 {
103         switch(category) {
104                 case FS_CATEGORY_SYSTEM:
105                         fsmenu_system = fsmenu;
106                         break;
107                 case FS_CATEGORY_BOOKMARKS:
108                         fsmenu_bookmarks = fsmenu;
109                         break;
110                 case FS_CATEGORY_RECENT:
111                         fsmenu_recent = fsmenu;
112                         break;
113         }
114 }
115
116 int fsmenu_get_nentries(FSMenuCategory category)
117 {
118         FSMenuEntry *fsme;
119         int count= 0;
120
121         for (fsme= fsmenu_get(category); fsme; fsme= fsme->next) 
122                 count++;
123
124         return count;
125 }
126
127 char *fsmenu_get_entry(FSMenuCategory category, int idx)
128 {
129         FSMenuEntry *fsme;
130
131         for (fsme= fsmenu_get(category); fsme && idx; fsme= fsme->next)
132                 idx--;
133
134         return fsme?fsme->path:NULL;
135 }
136
137 void    fsmenu_set_pos( FSMenuCategory category, int idx, short xs, short ys)
138 {
139         FSMenuEntry *fsme;
140
141         for (fsme= fsmenu_get(category); fsme && idx; fsme= fsme->next)
142                 idx--;
143
144         if (fsme) {
145                 fsme->xs = xs;
146                 fsme->ys = ys;
147         }
148 }
149
150 int     fsmenu_get_pos (FSMenuCategory category, int idx, short* xs, short* ys)
151 {
152         FSMenuEntry *fsme;
153
154         for (fsme= fsmenu_get(category); fsme && idx; fsme= fsme->next)
155                 idx--;
156
157         if (fsme) {
158                 *xs = fsme->xs;
159                 *ys = fsme->ys;
160                 return 1;
161         }
162
163         return 0;
164 }
165
166
167 void fsmenu_insert_entry(FSMenuCategory category, char *path, int sorted, short save)
168 {
169         FSMenuEntry *prev;
170         FSMenuEntry *fsme;
171         FSMenuEntry *fsmenu;
172
173         fsmenu = fsmenu_get(category);
174         prev= fsme= fsmenu;
175
176         for (; fsme; prev= fsme, fsme= fsme->next) {
177                 if (fsme->path) {
178                         if (BLI_streq(path, fsme->path)) {
179                                 return;
180                         } else if (sorted && strcmp(path, fsme->path)<0) {
181                                 break;
182                         }
183                 } else {
184                         // if we're bookmarking this, file should come 
185                         // before the last separator, only automatically added
186                         // current dir go after the last sep.
187                         if (save) {
188                                 break;
189                         }
190                 }
191         }
192         
193         fsme= MEM_mallocN(sizeof(*fsme), "fsme");
194         fsme->path= BLI_strdup(path);
195         fsme->save = save;
196
197         if (prev) {
198                 fsme->next= prev->next;
199                 prev->next= fsme;
200         } else {
201                 fsme->next= fsmenu;
202                 fsmenu_set(category, fsme);
203         }
204 }
205
206 void fsmenu_remove_entry(FSMenuCategory category, int idx)
207 {
208         FSMenuEntry *prev= NULL, *fsme= NULL;
209         FSMenuEntry *fsmenu = fsmenu_get(category);
210
211         for (fsme= fsmenu; fsme && idx; prev= fsme, fsme= fsme->next)           
212                 idx--;
213
214         if (fsme) {
215                 /* you should only be able to remove entries that were 
216                    not added by default, like windows drives.
217                    also separators (where path == NULL) shouldn't be removed */
218                 if (fsme->save && fsme->path) {
219
220                         /* remove fsme from list */
221                         if (prev) {
222                                 prev->next= fsme->next;
223                         } else {
224                                 fsmenu= fsme->next;
225                                 fsmenu_set(category, fsmenu);
226                         }
227                         /* free entry */
228                         MEM_freeN(fsme->path);
229                         MEM_freeN(fsme);
230                 }
231         }
232 }
233
234 void fsmenu_write_file(const char *filename)
235 {
236         FSMenuEntry *fsme= NULL;
237
238         FILE *fp = fopen(filename, "w");
239         if (!fp) return;
240
241         for (fsme= fsmenu_get(FS_CATEGORY_BOOKMARKS); fsme; fsme= fsme->next) {
242                 if (fsme->path && fsme->save) {
243                         fprintf(fp, "%s\n", fsme->path);
244                 }
245         }
246         fclose(fp);
247 }
248
249 void fsmenu_read_file(const char *filename)
250 {
251         char line[256];
252         FILE *fp;
253
254         #ifdef WIN32
255         /* Add the drive names to the listing */
256         {
257                 __int64 tmp;
258                 char folder[256];
259                 char tmps[4];
260                 int i;
261                         
262                 tmp= GetLogicalDrives();
263                 
264                 for (i=2; i < 26; i++) {
265                         if ((tmp>>i) & 1) {
266                                 tmps[0]='a'+i;
267                                 tmps[1]=':';
268                                 tmps[2]='\\';
269                                 tmps[3]=0;
270                                 
271                                 fsmenu_insert_entry(FS_CATEGORY_SYSTEM, tmps, 1, 0);
272                         }
273                 }
274
275                 /* Adding Desktop and My Documents */
276                 SHGetSpecialFolderPath(0, folder, CSIDL_PERSONAL, 0);
277                 fsmenu_insert_entry(FS_CATEGORY_BOOKMARKS, folder, 1, 0);
278                 SHGetSpecialFolderPath(0, folder, CSIDL_DESKTOPDIRECTORY, 0);
279                 fsmenu_insert_entry(FS_CATEGORY_BOOKMARKS, folder, 1, 0);
280         }
281 #endif
282
283         fp = fopen(filename, "r");
284         if (!fp) return;
285
286         while ( fgets ( line, 256, fp ) != NULL ) /* read a line */
287         {
288                 int len = strlen(line);
289                 if (len>0) {
290                         if (line[len-1] == '\n') {
291                                 line[len-1] = '\0';
292                         }
293                         fsmenu_insert_entry(FS_CATEGORY_BOOKMARKS, line, 0, 1);
294                 }
295         }
296         fclose(fp);
297 }
298
299 static void fsmenu_free_category(FSMenuCategory category)
300 {
301         FSMenuEntry *fsme= fsmenu_get(category);
302
303         while (fsme) {
304                 FSMenuEntry *n= fsme->next;
305
306                 if (fsme->path) MEM_freeN(fsme->path);
307                 MEM_freeN(fsme);
308
309                 fsme= n;
310         }
311 }
312
313 void fsmenu_free(void)
314 {
315         fsmenu_free_category(FS_CATEGORY_SYSTEM);
316         fsmenu_free_category(FS_CATEGORY_BOOKMARKS);
317         fsmenu_free_category(FS_CATEGORY_RECENT);
318 }
319