File Browser
[blender.git] / source / blender / editors / space_file / file_ops.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) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "BKE_context.h"
30 #include "BKE_screen.h"
31 #include "BKE_global.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_storage_types.h"
35 #ifdef WIN32
36 #include "BLI_winstuff.h"
37 #endif
38 #include "DNA_space_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "ED_space_api.h"
42 #include "ED_screen.h"
43 #include "ED_fileselect.h"
44
45 #include "MEM_guardedalloc.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49
50 #include "UI_interface.h"
51 #include "UI_view2d.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "file_intern.h"
57 #include "filelist.h"
58 #include "fsmenu.h"
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdio.h>
63
64 /* for events */
65 #define NOTACTIVE                       0
66 #define ACTIVATE                        1
67 #define INACTIVATE                      2
68
69 /* ---------- FILE SELECTION ------------ */
70
71 static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y, short clamp)
72 {
73         float fx,fy;
74         int active_file = -1;
75         int numfiles = filelist_numfiles(sfile->files);
76         View2D* v2d = &ar->v2d;
77
78         UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
79
80         active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy);
81
82         if(active_file < 0) {
83                 if(clamp)       active_file=  0;
84                 else            active_file= -1;
85         }
86         else if(active_file >= numfiles) {
87                 if(clamp)       active_file=  numfiles-1;
88                 else            active_file= -1;
89         }
90         
91         return active_file;
92 }
93
94
95 static void file_deselect_all(SpaceFile* sfile)
96 {
97         int numfiles = filelist_numfiles(sfile->files);
98         int i;
99
100         for ( i=0; i < numfiles; ++i) {
101                 struct direntry* file = filelist_file(sfile->files, i);
102                 if (file && (file->flags & ACTIVE)) {
103                         file->flags &= ~ACTIVE;
104                 }
105         }
106 }
107
108 typedef enum FileSelect { FILE_SELECT_DIR = 1, 
109   FILE_SELECT_FILE = 2 } FileSelect;
110
111
112 static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val)
113 {
114         int first_file = -1;
115         int last_file = -1;
116         int act_file;
117         short selecting = (val == LEFTMOUSE);
118         FileSelect retval = FILE_SELECT_FILE;
119
120         FileSelectParams *params = ED_fileselect_get_params(sfile);
121         // FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
122
123         int numfiles = filelist_numfiles(sfile->files);
124
125         params->selstate = NOTACTIVE;
126         first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax, 1);
127         last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin, 1);
128         
129         /* select all valid files between first and last indicated */
130         if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) {
131                 for (act_file = first_file; act_file <= last_file; act_file++) {
132                         struct direntry* file = filelist_file(sfile->files, act_file);
133                         if (selecting) 
134                                 file->flags |= ACTIVE;
135                         else
136                                 file->flags &= ~ACTIVE;
137                 }
138         }
139
140         /* make the last file active */
141         if (selecting && (last_file >= 0 && last_file < numfiles)) {
142                 struct direntry* file = filelist_file(sfile->files, last_file);
143                 params->active_file = last_file;
144
145                 if(file && S_ISDIR(file->type)) {
146                         /* the path is too long and we are not going up! */
147                         if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
148                         {
149                                 // XXX error("Path too long, cannot enter this directory");
150                         } else {
151                                 if (strcmp(file->relname, "..")==0) {    
152                                         /* avoids /../../ */     
153                                         BLI_parent_dir(params->dir);     
154                                 } else {
155                                         BLI_cleanup_dir(G.sce, params->dir);
156                                         strcat(params->dir, file->relname);
157                                         BLI_add_slash(params->dir);
158                                 }
159
160                                 file_change_dir(sfile);
161                                 retval = FILE_SELECT_DIR;
162                         }
163                 }
164                 else if (file)
165                 {
166                         if (file->relname) {
167                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
168                         }
169                         
170                 }       
171         }
172         return retval;
173 }
174
175
176
177 static int file_border_select_exec(bContext *C, wmOperator *op)
178 {
179         ARegion *ar= CTX_wm_region(C);
180         SpaceFile *sfile= CTX_wm_space_file(C);
181         short val;
182         rcti rect;
183
184         val= RNA_int_get(op->ptr, "event_type");
185         rect.xmin= RNA_int_get(op->ptr, "xmin");
186         rect.ymin= RNA_int_get(op->ptr, "ymin");
187         rect.xmax= RNA_int_get(op->ptr, "xmax");
188         rect.ymax= RNA_int_get(op->ptr, "ymax");
189
190         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
191         
192         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
193                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
194         } else {
195                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
196         }
197         return OPERATOR_FINISHED;
198 }
199
200 void FILE_OT_select_border(wmOperatorType *ot)
201 {
202         /* identifiers */
203         ot->name= "Activate/Select File";
204         ot->idname= "FILE_OT_select_border";
205         
206         /* api callbacks */
207         ot->invoke= WM_border_select_invoke;
208         ot->exec= file_border_select_exec;
209         ot->modal= WM_border_select_modal;
210
211         /* rna */
212         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
213         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
214         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
215         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
216         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
217
218         ot->poll= ED_operator_file_active;
219 }
220
221 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
222 {
223         ARegion *ar= CTX_wm_region(C);
224         SpaceFile *sfile= CTX_wm_space_file(C);
225         short val;
226         rcti rect;
227
228         if(ar->regiontype != RGN_TYPE_WINDOW)
229                 return OPERATOR_CANCELLED;
230
231         rect.xmin = rect.xmax = event->x - ar->winrct.xmin;
232         rect.ymin = rect.ymax = event->y - ar->winrct.ymin;
233         val = event->val;
234
235         if(!BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin))
236                 return OPERATOR_CANCELLED;
237
238         /* single select, deselect all selected first */
239         file_deselect_all(sfile);
240
241         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val ))
242                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
243         else
244                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
245
246         WM_event_add_mousemove(C); /* for directory changes */
247         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
248
249         return OPERATOR_FINISHED;
250 }
251
252 void FILE_OT_select(wmOperatorType *ot)
253 {
254         /* identifiers */
255         ot->name= "Activate/Select File";
256         ot->idname= "FILE_OT_select";
257         
258         /* api callbacks */
259         ot->invoke= file_select_invoke;
260
261         /* rna */
262
263         ot->poll= ED_operator_file_active;
264 }
265
266 static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
267 {
268         ScrArea *sa= CTX_wm_area(C);
269         SpaceFile *sfile= CTX_wm_space_file(C);
270         int numfiles = filelist_numfiles(sfile->files);
271         int i;
272         int select = 1;
273
274         /* if any file is selected, deselect all first */
275         for ( i=0; i < numfiles; ++i) {
276                 struct direntry* file = filelist_file(sfile->files, i);
277                 if (file && (file->flags & ACTIVE)) {
278                         file->flags &= ~ACTIVE;
279                         select = 0;
280                         ED_area_tag_redraw(sa);
281                 }
282         }
283         /* select all only if previously no file was selected */
284         if (select) {
285                 for ( i=0; i < numfiles; ++i) {
286                         struct direntry* file = filelist_file(sfile->files, i);
287                         if(file && !S_ISDIR(file->type)) {
288                                 file->flags |= ACTIVE;
289                                 ED_area_tag_redraw(sa);
290                         }
291                 }
292         }
293         return OPERATOR_FINISHED;
294 }
295
296 void FILE_OT_select_all_toggle(wmOperatorType *ot)
297 {
298         /* identifiers */
299         ot->name= "Select/Deselect all files";
300         ot->idname= "FILE_OT_select_all_toggle";
301         
302         /* api callbacks */
303         ot->invoke= file_select_all_invoke;
304
305         /* rna */
306
307         ot->poll= ED_operator_file_active;
308 }
309
310 /* ---------- BOOKMARKS ----------- */
311
312 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
313 {
314         SpaceFile *sfile= CTX_wm_space_file(C);
315
316         if(RNA_struct_find_property(op->ptr, "dir")) {
317                 char entry[256];
318                 FileSelectParams* params = sfile->params;
319
320                 RNA_string_get(op->ptr, "dir", entry);
321                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
322                 BLI_cleanup_dir(G.sce, params->dir);
323                 file_change_dir(sfile);                         
324
325                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
326         }
327         
328         return OPERATOR_FINISHED;
329 }
330
331 void FILE_OT_select_bookmark(wmOperatorType *ot)
332 {
333         /* identifiers */
334         ot->name= "Select Directory";
335         ot->idname= "FILE_OT_select_bookmark";
336         
337         /* api callbacks */
338         ot->invoke= bookmark_select_invoke;
339         ot->poll= ED_operator_file_active;
340
341         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
342 }
343
344 static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
345 {
346         ScrArea *sa= CTX_wm_area(C);
347         SpaceFile *sfile= CTX_wm_space_file(C);
348         struct FSMenu* fsmenu = fsmenu_get();
349         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
350
351         if (params->dir[0] != '\0') {
352                 char name[FILE_MAX];
353         
354                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
355                 BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
356                 fsmenu_write_file(fsmenu, name);
357         }
358
359         ED_area_tag_redraw(sa);
360         return OPERATOR_FINISHED;
361 }
362
363 void FILE_OT_add_bookmark(wmOperatorType *ot)
364 {
365         /* identifiers */
366         ot->name= "Add Bookmark";
367         ot->idname= "FILE_OT_add_bookmark";
368         
369         /* api callbacks */
370         ot->invoke= bookmark_add_invoke;
371         ot->poll= ED_operator_file_active;
372 }
373
374 static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
375 {
376         ScrArea *sa= CTX_wm_area(C);
377         struct FSMenu* fsmenu = fsmenu_get();
378         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
379         
380         if(RNA_struct_find_property(op->ptr, "index")) {
381                 int index = RNA_int_get(op->ptr, "index");
382                 if ( (index >-1) && (index < nentries)) {
383                         char name[FILE_MAX];
384                         
385                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
386                         BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
387                         fsmenu_write_file(fsmenu, name);
388                         ED_area_tag_redraw(sa);
389                 }
390         }
391
392         return OPERATOR_FINISHED;
393 }
394
395 void FILE_OT_delete_bookmark(wmOperatorType *ot)
396 {
397         /* identifiers */
398         ot->name= "Delete Bookmark";
399         ot->idname= "FILE_OT_delete_bookmark";
400         
401         /* api callbacks */
402         ot->invoke= bookmark_delete_invoke;
403         ot->poll= ED_operator_file_active;
404
405         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
406 }
407
408
409 static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
410 {
411         ScrArea *sa= CTX_wm_area(C);
412         SpaceFile *sfile= CTX_wm_space_file(C);
413         if (sfile->files) {
414                 filelist_loadimage_timer(sfile->files);
415                 if (filelist_changed(sfile->files)) {
416                         ED_area_tag_redraw(sa);
417                 }
418         }
419
420         return OPERATOR_FINISHED;
421 }
422
423 void FILE_OT_loadimages(wmOperatorType *ot)
424 {
425         
426         /* identifiers */
427         ot->name= "Load Images";
428         ot->idname= "FILE_OT_loadimages";
429         
430         /* api callbacks */
431         ot->invoke= loadimages_invoke;
432         
433         ot->poll= ED_operator_file_active;
434 }
435
436 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
437 {
438         FileSelectParams* params;
439         int numfiles, actfile, origfile;
440         
441         if(sfile==NULL || sfile->files==NULL) return 0;
442
443         numfiles = filelist_numfiles(sfile->files);
444         params = ED_fileselect_get_params(sfile);
445
446         origfile= params->active_file;
447
448         mx -= ar->winrct.xmin;
449         my -= ar->winrct.ymin;
450
451         if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
452                 actfile = find_file_mouse(sfile, ar, mx , my, 0);
453
454                 if((actfile >= 0) && (actfile < numfiles))
455                         params->active_file=actfile;
456                 else
457                         params->active_file= -1;
458         }
459         else
460                 params->active_file= -1;
461
462         return (params->active_file != origfile);
463 }
464
465 static int file_highlight_invoke(bContext *C, wmOperator *op, wmEvent *event)
466 {
467         ARegion *ar= CTX_wm_region(C);
468         SpaceFile *sfile= CTX_wm_space_file(C);
469
470         if(!file_hilight_set(sfile, ar, event->x, event->y))
471                 return OPERATOR_CANCELLED;
472
473         ED_area_tag_redraw(CTX_wm_area(C));
474         
475         return OPERATOR_FINISHED;
476 }
477
478 void FILE_OT_highlight(struct wmOperatorType *ot)
479 {
480         /* identifiers */
481         ot->name= "Highlight File";
482         ot->idname= "FILE_OT_highlight";
483         
484         /* api callbacks */
485         ot->invoke= file_highlight_invoke;
486         ot->poll= ED_operator_file_active;
487 }
488
489 int file_cancel_exec(bContext *C, wmOperator *unused)
490 {
491         SpaceFile *sfile= CTX_wm_space_file(C);
492
493         folderlist_free(sfile->folders_prev);
494         folderlist_free(sfile->folders_next);
495
496         WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL);
497         sfile->op = NULL;
498         
499         if (sfile->files) {
500                 filelist_free(sfile->files);
501                 MEM_freeN(sfile->files);
502                 sfile->files= NULL;
503         }
504         
505         return OPERATOR_FINISHED;
506 }
507
508 void FILE_OT_cancel(struct wmOperatorType *ot)
509 {
510         /* identifiers */
511         ot->name= "Cancel File Load";
512         ot->idname= "FILE_OT_cancel";
513         
514         /* api callbacks */
515         ot->exec= file_cancel_exec;
516         ot->poll= ED_operator_file_active;
517 }
518
519 /* sends events now, so things get handled on windowqueue level */
520 int file_exec(bContext *C, wmOperator *unused)
521 {
522         SpaceFile *sfile= CTX_wm_space_file(C);
523         char name[FILE_MAX];
524         
525         if(sfile->op) {
526                 wmOperator *op= sfile->op;
527                 
528                 sfile->op = NULL;
529                 RNA_string_set(op->ptr, "filename", sfile->params->file);
530                 BLI_strncpy(name, sfile->params->dir, sizeof(name));
531                 RNA_string_set(op->ptr, "directory", name);
532                 strcat(name, sfile->params->file);
533
534                 if(RNA_struct_find_property(op->ptr, "relative_paths"))
535                         if(RNA_boolean_get(op->ptr, "relative_paths"))
536                                 BLI_makestringcode(G.sce, name);
537
538                 RNA_string_set(op->ptr, "path", name);
539                 
540                 /* some ops have multiple files to select */
541                 {
542                         PointerRNA itemptr;
543                         int i, numfiles = filelist_numfiles(sfile->files);
544                         struct direntry *file;
545                         if(RNA_struct_find_property(op->ptr, "files")) {
546                                 for (i=0; i<numfiles; i++) {
547                                         file = filelist_file(sfile->files, i);
548                                         if(file->flags & ACTIVE) {
549                                                 if ((file->type & S_IFDIR)==0) {
550                                                         RNA_collection_add(op->ptr, "files", &itemptr);
551                                                         RNA_string_set(&itemptr, "name", file->relname);
552                                                 }
553                                         }
554                                 }
555                         }
556                         
557                         if(RNA_struct_find_property(op->ptr, "dirs")) {
558                                 for (i=0; i<numfiles; i++) {
559                                         file = filelist_file(sfile->files, i);
560                                         if(file->flags & ACTIVE) {
561                                                 if ((file->type & S_IFDIR)) {
562                                                         RNA_collection_add(op->ptr, "dirs", &itemptr);
563                                                         RNA_string_set(&itemptr, "name", file->relname);
564                                                 }
565                                         }
566                                 }
567                         }
568                 }
569                 
570                 folderlist_free(sfile->folders_prev);
571                 folderlist_free(sfile->folders_next);
572
573                 fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
574                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
575                 fsmenu_write_file(fsmenu_get(), name);
576                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
577
578                 filelist_free(sfile->files);
579                 MEM_freeN(sfile->files);
580                 sfile->files= NULL;
581         }
582                                 
583         return OPERATOR_FINISHED;
584 }
585
586 void FILE_OT_execute(struct wmOperatorType *ot)
587 {
588         /* identifiers */
589         ot->name= "Execute File Window";
590         ot->idname= "FILE_OT_execute";
591         
592         /* api callbacks */
593         ot->exec= file_exec;
594         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
595 }
596
597
598 int file_parent_exec(bContext *C, wmOperator *unused)
599 {
600         SpaceFile *sfile= CTX_wm_space_file(C);
601         
602         if(sfile->params) {
603                 if (BLI_has_parent(sfile->params->dir)) {
604                         BLI_parent_dir(sfile->params->dir);
605                         BLI_cleanup_dir(G.sce, sfile->params->dir);
606                         file_change_dir(sfile);
607                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
608                 }
609         }               
610         
611         return OPERATOR_FINISHED;
612
613 }
614
615
616 void FILE_OT_parent(struct wmOperatorType *ot)
617 {
618         /* identifiers */
619         ot->name= "Parent File";
620         ot->idname= "FILE_OT_parent";
621         
622         /* api callbacks */
623         ot->exec= file_parent_exec;
624         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
625 }
626
627
628 int file_refresh_exec(bContext *C, wmOperator *unused)
629 {
630         SpaceFile *sfile= CTX_wm_space_file(C);
631         
632         file_change_dir(sfile);
633
634         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
635
636         return OPERATOR_FINISHED;
637
638 }
639
640 void FILE_OT_previous(struct wmOperatorType *ot)
641 {
642         /* identifiers */
643         ot->name= "Previous Folder";
644         ot->idname= "FILE_OT_previous";
645         
646         /* api callbacks */
647         ot->exec= file_previous_exec;
648         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
649 }
650
651 int file_previous_exec(bContext *C, wmOperator *unused)
652 {
653         SpaceFile *sfile= CTX_wm_space_file(C);
654
655         if(sfile->params) {
656                 if (!sfile->folders_next)
657                         sfile->folders_next = folderlist_new();
658
659                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
660                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
661                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
662
663                 file_change_dir(sfile);
664         }
665         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
666
667         return OPERATOR_FINISHED;
668 }
669
670 void FILE_OT_next(struct wmOperatorType *ot)
671 {
672         /* identifiers */
673         ot->name= "Next Folder";
674         ot->idname= "FILE_OT_next";
675         
676         /* api callbacks */
677         ot->exec= file_next_exec;
678         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
679 }
680
681 int file_next_exec(bContext *C, wmOperator *unused)
682 {
683         SpaceFile *sfile= CTX_wm_space_file(C);
684                 if(sfile->params) {
685                         if (!sfile->folders_next)
686                         sfile->folders_next = folderlist_new();
687
688                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
689                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
690
691                 // update folder_prev so we can check for it in folderlist_clear_next()
692                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
693
694                 file_change_dir(sfile);
695         }               
696         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
697
698         return OPERATOR_FINISHED;
699 }
700
701 int file_directory_new_exec(bContext *C, wmOperator *unused)
702 {
703         char tmpstr[FILE_MAX];
704         char tmpdir[FILE_MAXFILE];
705         int i = 1;
706
707         SpaceFile *sfile= CTX_wm_space_file(C);
708         
709         if(sfile->params) {
710                  
711                 BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
712                 BLI_join_dirfile(tmpstr, tmpstr, "New Folder");
713                 while (BLI_exists(tmpstr)) {
714                         BLI_snprintf(tmpdir, FILE_MAXFILE, "New Folder(%d)", i++);
715                         BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
716                         BLI_join_dirfile(tmpstr, tmpstr, tmpdir);
717                 }
718                 BLI_recurdir_fileops(tmpstr);
719                 if (BLI_exists(tmpstr)) {
720                         BLI_strncpy(sfile->params->renamefile, tmpdir, FILE_MAXFILE);
721                 } else {
722                         filelist_free(sfile->files);
723                         filelist_parent(sfile->files);
724                         BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), FILE_MAX);
725                 } 
726         }               
727         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
728
729         return OPERATOR_FINISHED;
730 }
731
732
733 void FILE_OT_directory_new(struct wmOperatorType *ot)
734 {
735         /* identifiers */
736         ot->name= "Create New Directory";
737         ot->idname= "FILE_OT_directory_new";
738         ot->description= "Create a new directory";
739         
740         /* api callbacks */
741         ot->invoke= WM_operator_confirm;
742         ot->exec= file_directory_new_exec;
743         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
744 }
745
746 int file_directory_exec(bContext *C, wmOperator *unused)
747 {
748         char tmpstr[FILE_MAX];
749
750         SpaceFile *sfile= CTX_wm_space_file(C);
751         
752         if(sfile->params) {
753
754                 if ( sfile->params->dir[0] == '~' ) {
755                         if (sfile->params->dir[1] == '\0') {
756                                 BLI_strncpy(sfile->params->dir, BLI_gethome(), sizeof(sfile->params->dir) );
757                         } else {
758                                 /* replace ~ with home */
759                                 char homestr[FILE_MAX];
760                                 char *d = &sfile->params->dir[1];
761
762                                 while ( (*d == '\\') || (*d == '/') )
763                                         d++;
764                                 BLI_strncpy(homestr,  BLI_gethome(), FILE_MAX);
765                                 BLI_join_dirfile(tmpstr, homestr, d);
766                                 BLI_strncpy(sfile->params->dir, tmpstr, sizeof(sfile->params->dir));
767                         }
768                 }
769 #ifdef WIN32
770                 if (sfile->params->dir[0] == '\0')
771                         get_default_root(sfile->params->dir);
772 #endif
773                 BLI_cleanup_dir(G.sce, sfile->params->dir);
774                 BLI_add_slash(sfile->params->dir);
775                 file_change_dir(sfile);
776                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
777         }               
778         
779
780         return OPERATOR_FINISHED;
781 }
782
783 int file_filename_exec(bContext *C, wmOperator *unused)
784 {
785         SpaceFile *sfile= CTX_wm_space_file(C);
786         
787         if(sfile->params) {
788                 if (file_select_match(sfile, sfile->params->file))
789                 {
790                         sfile->params->file[0] = '\0';
791                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
792                 }
793         }               
794
795         return OPERATOR_FINISHED;
796 }
797
798
799 void FILE_OT_refresh(struct wmOperatorType *ot)
800 {
801         /* identifiers */
802         ot->name= "Refresh Filelist";
803         ot->idname= "FILE_OT_refresh";
804         
805         /* api callbacks */
806         ot->exec= file_refresh_exec;
807         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
808 }
809
810 int file_hidedot_exec(bContext *C, wmOperator *unused)
811 {
812         SpaceFile *sfile= CTX_wm_space_file(C);
813         
814         if(sfile->params) {
815                 sfile->params->flag ^= FILE_HIDE_DOT;
816                 filelist_free(sfile->files);
817                 sfile->params->active_file = -1;
818                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
819         }
820         
821         return OPERATOR_FINISHED;
822
823 }
824
825
826 void FILE_OT_hidedot(struct wmOperatorType *ot)
827 {
828         /* identifiers */
829         ot->name= "Toggle Hide Dot Files";
830         ot->idname= "FILE_OT_hidedot";
831         
832         /* api callbacks */
833         ot->exec= file_hidedot_exec;
834         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
835 }
836
837 struct ARegion *file_buttons_region(struct ScrArea *sa)
838 {
839         ARegion *ar, *arnew;
840         
841         for(ar= sa->regionbase.first; ar; ar= ar->next)
842                 if(ar->regiontype==RGN_TYPE_CHANNELS)
843                         return ar;
844
845         /* add subdiv level; after header */
846         for(ar= sa->regionbase.first; ar; ar= ar->next)
847                 if(ar->regiontype==RGN_TYPE_HEADER)
848                         break;
849         
850         /* is error! */
851         if(ar==NULL) return NULL;
852         
853         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
854         
855         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
856         arnew->regiontype= RGN_TYPE_CHANNELS;
857         arnew->alignment= RGN_ALIGN_LEFT;
858         
859         arnew->flag = RGN_FLAG_HIDDEN;
860         
861         return arnew;
862 }
863
864 int file_bookmark_toggle_exec(bContext *C, wmOperator *unused)
865 {
866         ScrArea *sa= CTX_wm_area(C);
867         ARegion *ar= file_buttons_region(sa);
868         
869         if(ar)
870                 ED_region_toggle_hidden(C, ar);
871
872         return OPERATOR_FINISHED;
873 }
874
875 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
876 {
877         /* identifiers */
878         ot->name= "Toggle Bookmarks";
879         ot->idname= "FILE_OT_bookmark_toggle";
880         
881         /* api callbacks */
882         ot->exec= file_bookmark_toggle_exec;
883         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
884 }
885
886
887 int file_filenum_exec(bContext *C, wmOperator *op)
888 {
889         SpaceFile *sfile= CTX_wm_space_file(C);
890         ScrArea *sa= CTX_wm_area(C);
891         
892         int inc = RNA_int_get(op->ptr, "increment");
893         if(sfile->params && (inc != 0)) {
894                 BLI_newname(sfile->params->file, inc);
895                 ED_area_tag_redraw(sa);
896                 // WM_event_add_notifier(C, NC_WINDOW, NULL);
897         }
898         
899         return OPERATOR_FINISHED;
900
901 }
902
903 void FILE_OT_filenum(struct wmOperatorType *ot)
904 {
905         /* identifiers */
906         ot->name= "Increment Number in Filename";
907         ot->idname= "FILE_OT_filenum";
908         
909         /* api callbacks */
910         ot->exec= file_filenum_exec;
911         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
912
913         /* props */
914         RNA_def_int(ot->srna, "increment", 1, 0, 100, "Increment", "", 0,100);
915 }
916
917 int file_rename_exec(bContext *C, wmOperator *op)
918 {
919         ScrArea *sa= CTX_wm_area(C);
920         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
921         
922         if(sfile->params) {
923                 int idx = sfile->params->active_file;
924                 int numfiles = filelist_numfiles(sfile->files);
925                 if ( (0<=idx) && (idx<numfiles) ) {
926                         struct direntry *file= filelist_file(sfile->files, idx);
927                         file->flags |= EDITING;
928                 }
929                 ED_area_tag_redraw(sa);
930         }
931         
932         return OPERATOR_FINISHED;
933
934 }
935
936 int file_rename_poll(bContext *C)
937 {
938         int poll = ED_operator_file_active(C);
939         SpaceFile *sfile= CTX_wm_space_file(C);
940
941         if (sfile && sfile->params) {
942                 if (sfile->params->active_file < 0) { 
943                         poll= 0;
944                 } else {
945                         char dir[FILE_MAX], group[FILE_MAX];    
946                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
947                 }
948         }
949         else
950                 poll= 0;
951         return poll;
952 }
953
954 void FILE_OT_rename(struct wmOperatorType *ot)
955 {
956         /* identifiers */
957         ot->name= "Rename File or Directory";
958         ot->idname= "FILE_OT_rename";
959         
960         /* api callbacks */
961         ot->exec= file_rename_exec;
962         ot->poll= file_rename_poll; 
963
964 }
965
966 int file_delete_poll(bContext *C)
967 {
968         int poll = ED_operator_file_active(C);
969         SpaceFile *sfile= CTX_wm_space_file(C);
970         struct direntry* file;
971
972         if (sfile && sfile->params) {
973                 if (sfile->params->active_file < 0) { 
974                         poll= 0;
975                 } else {
976                         char dir[FILE_MAX], group[FILE_MAX];    
977                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
978                         file = filelist_file(sfile->files, sfile->params->active_file);
979                         if (file && S_ISDIR(file->type)) poll= 0;
980                 }
981         }
982         else
983                 poll= 0;
984                 
985         return poll;
986 }
987
988 int file_delete_exec(bContext *C, wmOperator *op)
989 {
990         char str[FILE_MAX];
991         SpaceFile *sfile= CTX_wm_space_file(C);
992         struct direntry* file;
993         
994         
995         file = filelist_file(sfile->files, sfile->params->active_file);
996         BLI_make_file_string(G.sce, str, sfile->params->dir, file->relname);
997         BLI_delete(str, 0, 0);  
998         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
999         
1000         return OPERATOR_FINISHED;
1001
1002 }
1003
1004 void FILE_OT_delete(struct wmOperatorType *ot)
1005 {
1006         /* identifiers */
1007         ot->name= "Delete File";
1008         ot->idname= "FILE_OT_delete";
1009         
1010         /* api callbacks */
1011         ot->invoke= WM_operator_confirm;
1012         ot->exec= file_delete_exec;
1013         ot->poll= file_delete_poll; /* <- important, handler is on window level */
1014 }
1015