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