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