2.5: 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                                 params->file[0] = '\0';
161                                 file_change_dir(sfile);
162                                 retval = FILE_SELECT_DIR;
163                         }
164                 }
165                 else if (file)
166                 {
167                         if (file->relname) {
168                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
169                         }
170                         
171                 }       
172         }
173         return retval;
174 }
175
176
177
178 static int file_border_select_exec(bContext *C, wmOperator *op)
179 {
180         ARegion *ar= CTX_wm_region(C);
181         SpaceFile *sfile= CTX_wm_space_file(C);
182         short val;
183         rcti rect;
184
185         val= RNA_int_get(op->ptr, "event_type");
186         rect.xmin= RNA_int_get(op->ptr, "xmin");
187         rect.ymin= RNA_int_get(op->ptr, "ymin");
188         rect.xmax= RNA_int_get(op->ptr, "xmax");
189         rect.ymax= RNA_int_get(op->ptr, "ymax");
190
191         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
192         
193         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
194                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
195         } else {
196                 WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
197         }
198         return OPERATOR_FINISHED;
199 }
200
201 void FILE_OT_select_border(wmOperatorType *ot)
202 {
203         /* identifiers */
204         ot->name= "Activate/Select File";
205         ot->idname= "FILE_OT_select_border";
206         
207         /* api callbacks */
208         ot->invoke= WM_border_select_invoke;
209         ot->exec= file_border_select_exec;
210         ot->modal= WM_border_select_modal;
211
212         /* rna */
213         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
214         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
215         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
216         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
217         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
218
219         ot->poll= ED_operator_file_active;
220 }
221
222 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
223 {
224         ARegion *ar= CTX_wm_region(C);
225         SpaceFile *sfile= CTX_wm_space_file(C);
226         short val;
227         rcti rect;
228
229         if(ar->regiontype != RGN_TYPE_WINDOW)
230                 return OPERATOR_CANCELLED;
231
232         rect.xmin = rect.xmax = event->x - ar->winrct.xmin;
233         rect.ymin = rect.ymax = event->y - ar->winrct.ymin;
234         val = event->val;
235
236         if(!BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin))
237                 return OPERATOR_CANCELLED;
238
239         /* single select, deselect all selected first */
240         file_deselect_all(sfile);
241
242         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val ))
243                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
244         else
245                 WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
246
247         WM_event_add_mousemove(C); /* for directory changes */
248         WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
249
250         return OPERATOR_FINISHED;
251 }
252
253 void FILE_OT_select(wmOperatorType *ot)
254 {
255         /* identifiers */
256         ot->name= "Activate/Select File";
257         ot->idname= "FILE_OT_select";
258         
259         /* api callbacks */
260         ot->invoke= file_select_invoke;
261
262         /* rna */
263
264         ot->poll= ED_operator_file_active;
265 }
266
267 static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
268 {
269         ScrArea *sa= CTX_wm_area(C);
270         SpaceFile *sfile= CTX_wm_space_file(C);
271         int numfiles = filelist_numfiles(sfile->files);
272         int i;
273         int select = 1;
274
275         /* if any file is selected, deselect all first */
276         for ( i=0; i < numfiles; ++i) {
277                 struct direntry* file = filelist_file(sfile->files, i);
278                 if (file && (file->flags & ACTIVE)) {
279                         file->flags &= ~ACTIVE;
280                         select = 0;
281                         ED_area_tag_redraw(sa);
282                 }
283         }
284         /* select all only if previously no file was selected */
285         if (select) {
286                 for ( i=0; i < numfiles; ++i) {
287                         struct direntry* file = filelist_file(sfile->files, i);
288                         if(file && !S_ISDIR(file->type)) {
289                                 file->flags |= ACTIVE;
290                                 ED_area_tag_redraw(sa);
291                         }
292                 }
293         }
294         return OPERATOR_FINISHED;
295 }
296
297 void FILE_OT_select_all_toggle(wmOperatorType *ot)
298 {
299         /* identifiers */
300         ot->name= "Select/Deselect all files";
301         ot->idname= "FILE_OT_select_all_toggle";
302         
303         /* api callbacks */
304         ot->invoke= file_select_all_invoke;
305
306         /* rna */
307
308         ot->poll= ED_operator_file_active;
309 }
310
311 /* ---------- BOOKMARKS ----------- */
312
313 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
314 {
315         SpaceFile *sfile= CTX_wm_space_file(C);
316
317         if(RNA_struct_find_property(op->ptr, "dir")) {
318                 char entry[256];
319                 FileSelectParams* params = sfile->params;
320
321                 RNA_string_get(op->ptr, "dir", entry);
322                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
323                 BLI_cleanup_dir(G.sce, params->dir);
324                 file_change_dir(sfile);                         
325                 params->file[0] = '\0';
326
327                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
328         }
329         
330         return OPERATOR_FINISHED;
331 }
332
333 void FILE_OT_select_bookmark(wmOperatorType *ot)
334 {
335         /* identifiers */
336         ot->name= "Select Directory";
337         ot->idname= "FILE_OT_select_bookmark";
338         
339         /* api callbacks */
340         ot->invoke= bookmark_select_invoke;
341         ot->poll= ED_operator_file_active;
342
343         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
344 }
345
346 static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
347 {
348         ScrArea *sa= CTX_wm_area(C);
349         SpaceFile *sfile= CTX_wm_space_file(C);
350         struct FSMenu* fsmenu = fsmenu_get();
351         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
352
353         if (params->dir[0] != '\0') {
354                 char name[FILE_MAX];
355         
356                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
357                 BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
358                 fsmenu_write_file(fsmenu, name);
359         }
360
361         ED_area_tag_redraw(sa);
362         return OPERATOR_FINISHED;
363 }
364
365 void FILE_OT_add_bookmark(wmOperatorType *ot)
366 {
367         /* identifiers */
368         ot->name= "Add Bookmark";
369         ot->idname= "FILE_OT_add_bookmark";
370         
371         /* api callbacks */
372         ot->invoke= bookmark_add_invoke;
373         ot->poll= ED_operator_file_active;
374 }
375
376 static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
377 {
378         ScrArea *sa= CTX_wm_area(C);
379         struct FSMenu* fsmenu = fsmenu_get();
380         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
381         
382         if(RNA_struct_find_property(op->ptr, "index")) {
383                 int index = RNA_int_get(op->ptr, "index");
384                 if ( (index >-1) && (index < nentries)) {
385                         char name[FILE_MAX];
386                         
387                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
388                         BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
389                         fsmenu_write_file(fsmenu, name);
390                         ED_area_tag_redraw(sa);
391                 }
392         }
393
394         return OPERATOR_FINISHED;
395 }
396
397 void FILE_OT_delete_bookmark(wmOperatorType *ot)
398 {
399         /* identifiers */
400         ot->name= "Delete Bookmark";
401         ot->idname= "FILE_OT_delete_bookmark";
402         
403         /* api callbacks */
404         ot->invoke= bookmark_delete_invoke;
405         ot->poll= ED_operator_file_active;
406
407         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
408 }
409
410
411 static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
412 {
413         ScrArea *sa= CTX_wm_area(C);
414         SpaceFile *sfile= CTX_wm_space_file(C);
415         if (sfile->files) {
416                 filelist_loadimage_timer(sfile->files);
417                 if (filelist_changed(sfile->files)) {
418                         ED_area_tag_redraw(sa);
419                 }
420         }
421
422         return OPERATOR_FINISHED;
423 }
424
425 void FILE_OT_loadimages(wmOperatorType *ot)
426 {
427         
428         /* identifiers */
429         ot->name= "Load Images";
430         ot->idname= "FILE_OT_loadimages";
431         
432         /* api callbacks */
433         ot->invoke= loadimages_invoke;
434         
435         ot->poll= ED_operator_file_active;
436 }
437
438 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
439 {
440         FileSelectParams* params;
441         int numfiles, actfile, origfile;
442         
443         if(sfile==NULL || sfile->files==NULL) return 0;
444
445         numfiles = filelist_numfiles(sfile->files);
446         params = ED_fileselect_get_params(sfile);
447
448         origfile= params->active_file;
449
450         mx -= ar->winrct.xmin;
451         my -= ar->winrct.ymin;
452
453         if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
454                 actfile = find_file_mouse(sfile, ar, mx , my, 0);
455
456                 if((actfile >= 0) && (actfile < numfiles))
457                         params->active_file=actfile;
458                 else
459                         params->active_file= -1;
460         }
461         else
462                 params->active_file= -1;
463
464         return (params->active_file != origfile);
465 }
466
467 static int file_highlight_invoke(bContext *C, wmOperator *op, wmEvent *event)
468 {
469         ARegion *ar= CTX_wm_region(C);
470         SpaceFile *sfile= CTX_wm_space_file(C);
471
472         if(!file_hilight_set(sfile, ar, event->x, event->y))
473                 return OPERATOR_CANCELLED;
474
475         ED_area_tag_redraw(CTX_wm_area(C));
476         
477         return OPERATOR_FINISHED;
478 }
479
480 void FILE_OT_highlight(struct wmOperatorType *ot)
481 {
482         /* identifiers */
483         ot->name= "Highlight File";
484         ot->idname= "FILE_OT_highlight";
485         
486         /* api callbacks */
487         ot->invoke= file_highlight_invoke;
488         ot->poll= ED_operator_file_active;
489 }
490
491 int file_cancel_exec(bContext *C, wmOperator *unused)
492 {
493         SpaceFile *sfile= CTX_wm_space_file(C);
494
495         folderlist_free(sfile->folders_prev);
496         folderlist_free(sfile->folders_next);
497
498         WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL);
499         sfile->op = NULL;
500         
501         return OPERATOR_FINISHED;
502 }
503
504 void FILE_OT_cancel(struct wmOperatorType *ot)
505 {
506         /* identifiers */
507         ot->name= "Cancel File Load";
508         ot->idname= "FILE_OT_cancel";
509         
510         /* api callbacks */
511         ot->exec= file_cancel_exec;
512         ot->poll= ED_operator_file_active;
513 }
514
515 /* sends events now, so things get handled on windowqueue level */
516 int file_exec(bContext *C, wmOperator *unused)
517 {
518         SpaceFile *sfile= CTX_wm_space_file(C);
519         char name[FILE_MAX];
520         
521         if(sfile->op) {
522                 wmOperator *op= sfile->op;
523                 
524                 sfile->op = NULL;
525                 BLI_strncpy(name, sfile->params->dir, sizeof(name));
526                 strcat(name, sfile->params->file);
527                 RNA_string_set(op->ptr, "filename", name);
528                 
529                 /* some ops have multiple files to select */
530                 {
531                         PointerRNA itemptr;
532                         int i, numfiles = filelist_numfiles(sfile->files);
533                         struct direntry *file;
534                         if(RNA_struct_find_property(op->ptr, "files")) {
535                                 for (i=0; i<numfiles; i++) {
536                                         file = filelist_file(sfile->files, i);
537                                         if(file->flags & ACTIVE) {
538                                                 if ((file->type & S_IFDIR)==0) {
539                                                         RNA_collection_add(op->ptr, "files", &itemptr);
540                                                         RNA_string_set(&itemptr, "name", file->relname);
541                                                 }
542                                         }
543                                 }
544                         }
545                         
546                         if(RNA_struct_find_property(op->ptr, "dirs")) {
547                                 for (i=0; i<numfiles; i++) {
548                                         file = filelist_file(sfile->files, i);
549                                         if(file->flags & ACTIVE) {
550                                                 if ((file->type & S_IFDIR)) {
551                                                         RNA_collection_add(op->ptr, "dirs", &itemptr);
552                                                         RNA_string_set(&itemptr, "name", file->relname);
553                                                 }
554                                         }
555                                 }
556                         }
557                 }
558                 
559                 folderlist_free(sfile->folders_prev);
560                 folderlist_free(sfile->folders_next);
561
562                 fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
563                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
564                 fsmenu_write_file(fsmenu_get(), name);
565                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
566         }
567                                 
568         return OPERATOR_FINISHED;
569 }
570
571 void FILE_OT_exec(struct wmOperatorType *ot)
572 {
573         /* identifiers */
574         ot->name= "Execute File Window";
575         ot->idname= "FILE_OT_exec";
576         
577         /* api callbacks */
578         ot->exec= file_exec;
579         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
580 }
581
582
583 int file_parent_exec(bContext *C, wmOperator *unused)
584 {
585         SpaceFile *sfile= CTX_wm_space_file(C);
586         
587         if(sfile->params) {
588                 if (BLI_has_parent(sfile->params->dir)) {
589                         BLI_parent_dir(sfile->params->dir);
590                         BLI_cleanup_dir(G.sce, sfile->params->dir);
591                         file_change_dir(sfile);
592                         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
593                 }
594         }               
595         
596         return OPERATOR_FINISHED;
597
598 }
599
600
601 void FILE_OT_parent(struct wmOperatorType *ot)
602 {
603         /* identifiers */
604         ot->name= "Parent File";
605         ot->idname= "FILE_OT_parent";
606         
607         /* api callbacks */
608         ot->exec= file_parent_exec;
609         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
610 }
611
612
613 int file_refresh_exec(bContext *C, wmOperator *unused)
614 {
615         SpaceFile *sfile= CTX_wm_space_file(C);
616         
617         file_change_dir(sfile);
618
619         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
620
621         return OPERATOR_FINISHED;
622
623 }
624
625 void FILE_OT_previous(struct wmOperatorType *ot)
626 {
627         /* identifiers */
628         ot->name= "Previous Folder";
629         ot->idname= "FILE_OT_previous";
630         
631         /* api callbacks */
632         ot->exec= file_previous_exec;
633         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
634 }
635
636 int file_previous_exec(bContext *C, wmOperator *unused)
637 {
638         SpaceFile *sfile= CTX_wm_space_file(C);
639
640         if(sfile->params) {
641                 if (!sfile->folders_next)
642                         sfile->folders_next = folderlist_new();
643
644                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
645                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
646                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
647
648                 file_change_dir(sfile);
649         }
650         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
651
652         return OPERATOR_FINISHED;
653 }
654
655 void FILE_OT_next(struct wmOperatorType *ot)
656 {
657         /* identifiers */
658         ot->name= "Next Folder";
659         ot->idname= "FILE_OT_next";
660         
661         /* api callbacks */
662         ot->exec= file_next_exec;
663         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
664 }
665
666 int file_next_exec(bContext *C, wmOperator *unused)
667 {
668         SpaceFile *sfile= CTX_wm_space_file(C);
669                 if(sfile->params) {
670                         if (!sfile->folders_next)
671                         sfile->folders_next = folderlist_new();
672
673                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
674                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
675
676                 // update folder_prev so we can check for it in folderlist_clear_next()
677                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
678
679                 file_change_dir(sfile);
680         }               
681         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
682
683         return OPERATOR_FINISHED;
684 }
685
686 int file_directory_new_exec(bContext *C, wmOperator *unused)
687 {
688         char tmpstr[FILE_MAX];
689         char tmpdir[FILE_MAXFILE];
690         int i = 1;
691
692         SpaceFile *sfile= CTX_wm_space_file(C);
693         
694         if(sfile->params) {
695                  
696                 BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
697                 BLI_join_dirfile(tmpstr, tmpstr, "New Folder");
698                 while (BLI_exists(tmpstr)) {
699                         BLI_snprintf(tmpdir, FILE_MAXFILE, "New Folder(%d)", i++);
700                         BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
701                         BLI_join_dirfile(tmpstr, tmpstr, tmpdir);
702                 }
703                 BLI_recurdir_fileops(tmpstr);
704                 if (!BLI_exists(tmpstr)) {
705                         filelist_free(sfile->files);
706                         filelist_parent(sfile->files);
707                         BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), FILE_MAX);
708                 } 
709         }               
710         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
711
712         return OPERATOR_FINISHED;
713 }
714
715
716 void FILE_OT_directory_new(struct wmOperatorType *ot)
717 {
718         /* identifiers */
719         ot->name= "Create New Directory";
720         ot->idname= "FILE_OT_directory_new";
721         
722         /* api callbacks */
723         ot->invoke= WM_operator_confirm;
724         ot->exec= file_directory_new_exec;
725         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
726 }
727
728 int file_directory_exec(bContext *C, wmOperator *unused)
729 {
730         char tmpstr[FILE_MAX];
731
732         SpaceFile *sfile= CTX_wm_space_file(C);
733         
734         if(sfile->params) {
735
736                 if ( sfile->params->dir[0] == '~' ) {
737                         if (sfile->params->dir[1] == '\0') {
738                                 BLI_strncpy(sfile->params->dir, BLI_gethome(), sizeof(sfile->params->dir) );
739                         } else {
740                                 /* replace ~ with home */
741                                 char homestr[FILE_MAX];
742                                 char *d = &sfile->params->dir[1];
743
744                                 while ( (*d == '\\') || (*d == '/') )
745                                         d++;
746                                 BLI_strncpy(homestr,  BLI_gethome(), FILE_MAX);
747                                 BLI_join_dirfile(tmpstr, homestr, d);
748                                 BLI_strncpy(sfile->params->dir, tmpstr, sizeof(sfile->params->dir));
749                         }
750                 }
751 #ifdef WIN32
752                 if (sfile->params->dir[0] == '\0')
753                         get_default_root(sfile->params->dir);
754 #endif
755                 BLI_cleanup_dir(G.sce, sfile->params->dir);
756                 BLI_add_slash(sfile->params->dir);
757                 file_change_dir(sfile);
758                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
759         }               
760         
761
762         return OPERATOR_FINISHED;
763 }
764
765 int file_filename_exec(bContext *C, wmOperator *unused)
766 {
767         SpaceFile *sfile= CTX_wm_space_file(C);
768         
769         if(sfile->params) {
770                 if (file_select_match(sfile, sfile->params->file))
771                 {
772                         sfile->params->file[0] = '\0';
773                         WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
774                 }
775         }               
776
777         return OPERATOR_FINISHED;
778 }
779
780
781 void FILE_OT_refresh(struct wmOperatorType *ot)
782 {
783         /* identifiers */
784         ot->name= "Refresh Filelist";
785         ot->idname= "FILE_OT_refresh";
786         
787         /* api callbacks */
788         ot->exec= file_refresh_exec;
789         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
790 }
791
792 int file_hidedot_exec(bContext *C, wmOperator *unused)
793 {
794         SpaceFile *sfile= CTX_wm_space_file(C);
795         
796         if(sfile->params) {
797                 sfile->params->flag ^= FILE_HIDE_DOT;
798                 filelist_free(sfile->files);
799                 sfile->params->active_file = -1;
800                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
801         }
802         
803         return OPERATOR_FINISHED;
804
805 }
806
807
808 void FILE_OT_hidedot(struct wmOperatorType *ot)
809 {
810         /* identifiers */
811         ot->name= "Toggle Hide Dot Files";
812         ot->idname= "FILE_OT_hidedot";
813         
814         /* api callbacks */
815         ot->exec= file_hidedot_exec;
816         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
817 }
818
819 struct ARegion *file_buttons_region(struct ScrArea *sa)
820 {
821         ARegion *ar, *arnew;
822         
823         for(ar= sa->regionbase.first; ar; ar= ar->next)
824                 if(ar->regiontype==RGN_TYPE_CHANNELS)
825                         return ar;
826
827         /* add subdiv level; after header */
828         for(ar= sa->regionbase.first; ar; ar= ar->next)
829                 if(ar->regiontype==RGN_TYPE_HEADER)
830                         break;
831         
832         /* is error! */
833         if(ar==NULL) return NULL;
834         
835         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
836         
837         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
838         arnew->regiontype= RGN_TYPE_CHANNELS;
839         arnew->alignment= RGN_ALIGN_LEFT;
840         
841         arnew->flag = RGN_FLAG_HIDDEN;
842         
843         return arnew;
844 }
845
846 int file_bookmark_toggle_exec(bContext *C, wmOperator *unused)
847 {
848         ScrArea *sa= CTX_wm_area(C);
849         ARegion *ar= file_buttons_region(sa);
850         
851         if(ar) {
852                 ar->flag ^= RGN_FLAG_HIDDEN;
853                 ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
854                 
855                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
856                 ED_area_tag_redraw(sa);
857         }
858         return OPERATOR_FINISHED;
859 }
860
861 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
862 {
863         /* identifiers */
864         ot->name= "Toggle Bookmarks";
865         ot->idname= "FILE_OT_bookmark_toggle";
866         
867         /* api callbacks */
868         ot->exec= file_bookmark_toggle_exec;
869         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
870 }
871
872
873 int file_filenum_exec(bContext *C, wmOperator *op)
874 {
875         SpaceFile *sfile= CTX_wm_space_file(C);
876         
877         int inc = RNA_int_get(op->ptr, "increment");
878         if(sfile->params && (inc != 0)) {
879                 BLI_newname(sfile->params->file, inc);
880                 WM_event_add_notifier(C, NC_WINDOW, NULL);
881         }
882         
883         return OPERATOR_FINISHED;
884
885 }
886
887 void FILE_OT_filenum(struct wmOperatorType *ot)
888 {
889         /* identifiers */
890         ot->name= "Increment Number in Filename";
891         ot->idname= "FILE_OT_filenum";
892         
893         /* api callbacks */
894         ot->exec= file_filenum_exec;
895         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
896
897         /* props */
898         RNA_def_int(ot->srna, "increment", 1, 0, 100, "Increment", "", 0,100);
899 }
900
901 int file_rename_exec(bContext *C, wmOperator *op)
902 {
903         ScrArea *sa= CTX_wm_area(C);
904         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
905         
906         if(sfile->params) {
907                 int idx = sfile->params->active_file;
908                 int numfiles = filelist_numfiles(sfile->files);
909                 if ( (0<=idx) && (idx<numfiles) ) {
910                         struct direntry *file= filelist_file(sfile->files, idx);
911                         file->flags |= EDITING;
912                 }
913                 ED_area_tag_redraw(sa);
914         }
915         
916         return OPERATOR_FINISHED;
917
918 }
919
920 void FILE_OT_rename(struct wmOperatorType *ot)
921 {
922         /* identifiers */
923         ot->name= "Rename File or Directory";
924         ot->idname= "FILE_OT_rename";
925         
926         /* api callbacks */
927         ot->exec= file_rename_exec;
928         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
929
930 }
931
932 int file_delete_poll(bContext *C)
933 {
934         int poll = ED_operator_file_active(C);
935         SpaceFile *sfile= CTX_wm_space_file(C);
936         struct direntry* file;
937
938         if (sfile->params) {
939                 if (sfile->params->active_file < 0) { 
940                         poll= 0;
941                 } else {
942                         file = filelist_file(sfile->files, sfile->params->active_file);
943                         if (file && S_ISDIR(file->type)) poll= 0;
944                 }
945         }
946         else
947                 poll= 0;
948                 
949         return poll;
950 }
951
952 int file_delete_exec(bContext *C, wmOperator *op)
953 {
954         char str[FILE_MAX];
955         SpaceFile *sfile= CTX_wm_space_file(C);
956         struct direntry* file;
957         
958         
959         file = filelist_file(sfile->files, sfile->params->active_file);
960         BLI_make_file_string(G.sce, str, sfile->params->dir, file->relname);
961         BLI_delete(str, 0, 0);  
962         WM_event_add_notifier(C, NC_FILE | ND_FILELIST, NULL);
963         
964         return OPERATOR_FINISHED;
965
966 }
967
968 void FILE_OT_delete(struct wmOperatorType *ot)
969 {
970         /* identifiers */
971         ot->name= "Delete File";
972         ot->idname= "FILE_OT_delete";
973         
974         /* api callbacks */
975         ot->invoke= WM_operator_confirm;
976         ot->exec= file_delete_exec;
977         ot->poll= file_delete_poll; /* <- important, handler is on window level */
978 }
979