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 };
63
64 static FSMenuEntry *fsmenu= 0;
65
66 int fsmenu_get_nentries(void)
67 {
68         FSMenuEntry *fsme;
69         int count= 0;
70
71         for (fsme= fsmenu; fsme; fsme= fsme->next) 
72                 count++;
73
74         return count;
75 }
76 int fsmenu_is_entry_a_separator(int idx)
77 {
78         FSMenuEntry *fsme;
79
80         for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
81                 idx--;
82
83         return (fsme && !fsme->path)?1:0;
84 }
85 char *fsmenu_get_entry(int idx)
86 {
87         FSMenuEntry *fsme;
88
89         for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
90                 idx--;
91
92         return fsme?fsme->path:NULL;
93 }
94 char *fsmenu_build_menu(void)
95 {
96         DynStr *ds= BLI_dynstr_new();
97         FSMenuEntry *fsme;
98         char *menustr;
99
100         for (fsme= fsmenu; fsme; fsme= fsme->next) {
101                 if (!fsme->path) {
102                                 /* clean consecutive seperators and ignore trailing ones */
103                         if (fsme->next) {
104                                 if (fsme->next->path) {
105                                         BLI_dynstr_append(ds, "%l|");
106                                 } else {
107                                         FSMenuEntry *next= fsme->next;
108                                         fsme->next= next->next;
109                                         MEM_freeN(next);
110                                 }
111                         }
112                 } else {
113                         if (fsme->save) {
114                                 BLI_dynstr_append(ds, "o ");
115                         } else {
116                                 BLI_dynstr_append(ds, "  ");
117                         }
118                         BLI_dynstr_append(ds, fsme->path);
119                         if (fsme->next) BLI_dynstr_append(ds, "|");
120                 }
121         }
122
123         menustr= BLI_dynstr_get_cstring(ds);
124         BLI_dynstr_free(ds);
125         return menustr;
126 }
127 static FSMenuEntry *fsmenu_get_last_separator(void) 
128 {
129         FSMenuEntry *fsme, *lsep=NULL;
130
131         for (fsme= fsmenu; fsme; fsme= fsme->next)
132                 if (!fsme->path)
133                         lsep= fsme;
134
135         return lsep;
136 }
137
138 static FSMenuEntry *fsmenu_get_first_separator(void) 
139 {
140         FSMenuEntry *fsme, *lsep=NULL;
141
142         for (fsme= fsmenu; fsme; fsme= fsme->next)
143                 if (!fsme->path) {
144                         lsep= fsme;
145                         break;
146                 }
147
148         return lsep;
149 }
150
151 void fsmenu_insert_entry(char *path, int sorted, short save)
152 {
153         FSMenuEntry *prev;
154         FSMenuEntry *fsme;
155
156         if (save) {
157                 prev = fsmenu_get_first_separator();
158         } else {
159                 prev = fsmenu_get_last_separator();
160         }
161         fsme= prev?prev->next:fsmenu;
162
163         for (; fsme; prev= fsme, fsme= fsme->next) {
164                 if (fsme->path) {
165                         if (BLI_streq(path, fsme->path)) {
166                                 return;
167                         } else if (sorted && strcmp(path, fsme->path)<0) {
168                                 break;
169                         }
170                 } else {
171                         // if we're bookmarking this, file should come 
172                         // before the last separator, only automatically added
173                         // current dir go after the last sep.
174                         if (save) {
175                                 break;
176                         }
177                 }
178         }
179         
180         fsme= MEM_mallocN(sizeof(*fsme), "fsme");
181         fsme->path= BLI_strdup(path);
182         fsme->save = save;
183
184         if (prev) {
185                 fsme->next= prev->next;
186                 prev->next= fsme;
187         } else {
188                 fsme->next= fsmenu;
189                 fsmenu= fsme;
190         }
191 }
192 void fsmenu_append_separator(void)
193 {
194         if (fsmenu) {
195                 FSMenuEntry *fsme= fsmenu;
196
197                 while (fsme->next) fsme= fsme->next;
198
199                 fsme->next= MEM_mallocN(sizeof(*fsme), "fsme");
200                 fsme->next->next= NULL;
201                 fsme->next->path= NULL;
202         }
203 }
204 void fsmenu_remove_entry(int idx)
205 {
206         FSMenuEntry *prev= NULL, *fsme= fsmenu;
207
208         for (fsme= fsmenu; fsme && idx; prev= fsme, fsme= fsme->next)           
209                 idx--;
210
211         if (fsme) {
212                 /* you should only be able to remove entries that were 
213                    not added by default, like windows drives.
214                    also separators (where path == NULL) shouldn't be removed */
215                 if (fsme->save && fsme->path) {
216
217                         /* remove fsme from list */
218                         if (prev) {
219                                 prev->next= fsme->next;
220                         } else {
221                                 fsmenu= fsme->next;
222                         }
223                         /* free entry */
224                         MEM_freeN(fsme->path);
225                         MEM_freeN(fsme);
226                 }
227         }
228 }
229
230 void fsmenu_write_file(const char *filename)
231 {
232         FSMenuEntry *fsme= fsmenu;
233
234         FILE *fp = fopen(filename, "w");
235         if (!fp) return;
236
237         for (fsme= fsmenu; fsme; fsme= fsme->next) {
238                 if (fsme->path && fsme->save) {
239                         fprintf(fp, "%s\n", fsme->path);
240                 }
241         }
242         fclose(fp);
243 }
244
245 void fsmenu_read_file(const char *filename)
246 {
247         char line[256];
248         FILE *fp;
249
250         #ifdef WIN32
251         /* Add the drive names to the listing */
252         {
253                 __int64 tmp;
254                 char folder[256];
255                 char tmps[4];
256                 int i;
257                         
258                 tmp= GetLogicalDrives();
259                 
260                 for (i=2; i < 26; i++) {
261                         if ((tmp>>i) & 1) {
262                                 tmps[0]='a'+i;
263                                 tmps[1]=':';
264                                 tmps[2]='\\';
265                                 tmps[3]=0;
266                                 
267                                 fsmenu_insert_entry(tmps, 0, 0);
268                         }
269                 }
270
271                 /* Adding Desktop and My Documents */
272                 fsmenu_append_separator();
273
274                 SHGetSpecialFolderPath(0, folder, CSIDL_PERSONAL, 0);
275                 fsmenu_insert_entry(folder, 0, 0);
276                 SHGetSpecialFolderPath(0, folder, CSIDL_DESKTOPDIRECTORY, 0);
277                 fsmenu_insert_entry(folder, 0, 0);
278
279                 fsmenu_append_separator();
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(line, 0, 1);
294                 }
295         }
296         fclose(fp);
297 }
298
299 void fsmenu_free(void)
300 {
301         FSMenuEntry *fsme= fsmenu;
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
314