Code cleanup: remove BLI_exist, now there is only BLI_exists. One function just
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/space_file/file_ops.c
30  *  \ingroup spfile
31  */
32
33
34 #include "BKE_context.h"
35 #include "BKE_screen.h"
36 #include "BKE_global.h"
37 #include "BKE_report.h"
38 #include "BKE_main.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
42 #include "BLI_storage_types.h"
43 #ifdef WIN32
44 #include "BLI_winstuff.h"
45 #endif
46
47 #include "ED_screen.h"
48 #include "ED_fileselect.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54
55 #include "UI_view2d.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "file_intern.h"
61 #include "filelist.h"
62 #include "fsmenu.h"
63
64 #include <stdlib.h>
65 #include <string.h>
66 #include <stdio.h>
67 #include <ctype.h>
68
69 /* for events */
70 #define NOTACTIVEFILE                   0
71 #define ACTIVATE                        1
72 #define INACTIVATE                      2
73
74 /* ---------- FILE SELECTION ------------ */
75 static FileSelection find_file_mouse_rect(SpaceFile *sfile, struct ARegion* ar, const rcti* rect)
76 {
77         FileSelection sel;
78         float fxmin,fymin,fxmax, fymax;
79         
80         View2D* v2d = &ar->v2d;
81         rcti rect_view;
82
83         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin, &fxmin, &fymin);
84         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax, &fxmax, &fymax);
85
86         BLI_init_rcti(&rect_view, (int)(v2d->tot.xmin + fxmin), (int)(v2d->tot.xmin + fxmax), (int)(v2d->tot.ymax - fymin), (int)(v2d->tot.ymax - fymax));
87
88         sel  = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
89         
90         return sel;
91 }
92
93 static void file_deselect_all(SpaceFile* sfile, unsigned int flag)
94 {
95         FileSelection sel;
96         sel.first = 0;
97         sel.last = filelist_numfiles(sfile->files)-1;
98         
99         filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
100 }
101
102 typedef enum FileSelect { 
103         FILE_SELECT_NOTHING = 0,
104         FILE_SELECT_DIR = 1, 
105         FILE_SELECT_FILE = 2 
106 } FileSelect;
107
108 static void clamp_to_filelist(int numfiles, FileSelection* sel)
109 {
110         /* border select before the first file */
111         if ( (sel->first < 0) && (sel->last >=0 ) ) {
112                 sel->first = 0;
113         }
114         /* don't select if everything is outside filelist */
115         if ( (sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles)) ) {
116                 sel->first = -1;
117                 sel->last = -1;
118         }
119         
120         /* fix if last file invalid */
121         if ( (sel->first > 0) && (sel->last < 0) )
122                 sel->last = numfiles-1;
123
124         /* clamp */
125         if ( (sel->first >= numfiles) ) {
126                 sel->first = numfiles-1;
127         }
128         if ( (sel->last >= numfiles) ) {
129                 sel->last = numfiles-1;
130         }
131 }
132
133 static FileSelection file_selection_get(bContext* C, const rcti* rect, short fill)
134 {
135         ARegion *ar= CTX_wm_region(C);
136         SpaceFile *sfile= CTX_wm_space_file(C);
137         int numfiles = filelist_numfiles(sfile->files);
138         FileSelection sel;
139
140         sel = find_file_mouse_rect(sfile, ar, rect);
141         if ( !((sel.first == -1) && (sel.last == -1)) ) {
142                 clamp_to_filelist(numfiles, &sel);
143         }
144
145
146         /* if desired, fill the selection up from the last selected file to the current one */
147         if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
148                 int f= sel.last;
149                 while (f >= 0) {
150                         if ( filelist_is_selected(sfile->files, f, CHECK_ALL) )
151                                 break;
152                         f--;
153                 }
154                 if (f >= 0) {
155                         sel.first = f+1;
156                 }
157         }
158         return sel;
159 }
160
161 static FileSelect file_select_do(bContext* C, int selected_idx)
162 {
163         FileSelect retval = FILE_SELECT_NOTHING;
164         SpaceFile *sfile= CTX_wm_space_file(C);
165         FileSelectParams *params = ED_fileselect_get_params(sfile);
166         int numfiles = filelist_numfiles(sfile->files);
167         struct direntry* file;
168
169         /* make the selected file active */
170         if (            (selected_idx >= 0) &&
171                     (selected_idx < numfiles) &&
172                     (file= filelist_file(sfile->files, selected_idx)))
173         {
174                 params->active_file = selected_idx;
175
176                 if(S_ISDIR(file->type)) {
177                         /* the path is too long and we are not going up! */
178                         if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX )  {
179                                 // XXX error("Path too long, cannot enter this directory");
180                         }
181                         else {
182                                 if (strcmp(file->relname, "..")==0) {
183                                         /* avoids /../../ */
184                                         BLI_parent_dir(params->dir);
185                                 }
186                                 else {
187                                         BLI_cleanup_dir(G.main->name, params->dir);
188                                         strcat(params->dir, file->relname);
189                                         BLI_add_slash(params->dir);
190                                 }
191
192                                 file_change_dir(C, 0);
193                                 retval = FILE_SELECT_DIR;
194                         }
195                 }
196                 else  {
197                         if (file->relname) {
198                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
199                         }
200                         retval = FILE_SELECT_FILE;
201                 }
202         }
203         return retval;
204 }
205
206
207 static FileSelect file_select(bContext* C, const rcti* rect, FileSelType select, short fill)
208 {
209         SpaceFile *sfile= CTX_wm_space_file(C);
210         FileSelect retval = FILE_SELECT_NOTHING;
211         FileSelection sel= file_selection_get(C, rect, fill); /* get the selection */
212         const FileCheckType check_type= (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
213         
214         /* flag the files as selected in the filelist */
215         filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type);
216         
217         /* Don't act on multiple selected files */
218         if (sel.first != sel.last) select = 0;
219
220         /* Do we have a valid selection and are we actually selecting */
221         if ( (sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE)) )
222         {
223                 /* Check last selection, if selected, act on the file or dir */
224                 if (filelist_is_selected(sfile->files, sel.last, check_type)) {
225                         retval = file_select_do(C, sel.last);
226                 }
227         }
228
229         /* update operator for name change event */
230         file_draw_check_cb(C, NULL, NULL);
231         
232         return retval;
233 }
234
235 static int file_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
236 {
237         ARegion *ar= CTX_wm_region(C);
238         SpaceFile *sfile= CTX_wm_space_file(C);
239         FileSelectParams *params = ED_fileselect_get_params(sfile);
240         FileSelection sel;
241         rcti rect;
242
243         int result;
244
245         result= WM_border_select_modal(C, op, event);
246
247         if(result==OPERATOR_RUNNING_MODAL)      {
248
249                 rect.xmin= RNA_int_get(op->ptr, "xmin");
250                 rect.ymin= RNA_int_get(op->ptr, "ymin");
251                 rect.xmax= RNA_int_get(op->ptr, "xmax");
252                 rect.ymax= RNA_int_get(op->ptr, "ymax");
253
254                 BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
255
256                 sel = file_selection_get(C, &rect, 0);
257                 if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
258                         file_deselect_all(sfile, HILITED_FILE);
259                         filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL);
260                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
261                 }
262                 params->sel_first = sel.first; params->sel_last = sel.last;
263
264         }else {
265                 params->active_file = -1;
266                 params->sel_first = params->sel_last = -1;
267                 file_deselect_all(sfile, HILITED_FILE);
268                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
269         }
270
271         return result;
272 }
273
274 static int file_border_select_exec(bContext *C, wmOperator *op)
275 {
276         ARegion *ar= CTX_wm_region(C);
277         rcti rect;
278         FileSelect ret;
279
280         short select= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
281         rect.xmin= RNA_int_get(op->ptr, "xmin");
282         rect.ymin= RNA_int_get(op->ptr, "ymin");
283         rect.xmax= RNA_int_get(op->ptr, "xmax");
284         rect.ymax= RNA_int_get(op->ptr, "ymax");
285
286         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
287
288         ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, 0);
289         if (FILE_SELECT_DIR == ret) {
290                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
291         } else if (FILE_SELECT_FILE == ret) {
292                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
293         }
294         return OPERATOR_FINISHED;
295 }
296
297 void FILE_OT_select_border(wmOperatorType *ot)
298 {
299         /* identifiers */
300         ot->name= "Activate/Select File";
301         ot->description= "Activate/select the file(s) contained in the border";
302         ot->idname= "FILE_OT_select_border";
303         
304         /* api callbacks */
305         ot->invoke= WM_border_select_invoke;
306         ot->exec= file_border_select_exec;
307         ot->modal= file_border_select_modal;
308         ot->poll= ED_operator_file_active;
309         ot->cancel= WM_border_select_cancel;
310
311         /* rna */
312         WM_operator_properties_gesture_border(ot, 0);
313 }
314
315 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
316 {
317         ARegion *ar= CTX_wm_region(C);
318         SpaceFile *sfile= CTX_wm_space_file(C);
319         FileSelect ret;
320         rcti rect;
321         int extend = RNA_boolean_get(op->ptr, "extend");
322         int fill = RNA_boolean_get(op->ptr, "fill");
323
324         if(ar->regiontype != RGN_TYPE_WINDOW)
325                 return OPERATOR_CANCELLED;
326
327         rect.xmin = rect.xmax = event->mval[0];
328         rect.ymin = rect.ymax = event->mval[1];
329
330         if(!BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin))
331                 return OPERATOR_CANCELLED;
332
333         /* single select, deselect all selected first */
334         if (!extend) file_deselect_all(sfile, SELECTED_FILE);
335
336         ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill);
337         if (FILE_SELECT_DIR == ret)
338                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
339         else if (FILE_SELECT_FILE == ret)
340                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
341
342         WM_event_add_mousemove(C); /* for directory changes */
343         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
344
345         return OPERATOR_FINISHED;
346 }
347
348 void FILE_OT_select(wmOperatorType *ot)
349 {
350         /* identifiers */
351         ot->name= "Activate/Select File";
352         ot->description= "Activate/select file";
353         ot->idname= "FILE_OT_select";
354         
355         /* api callbacks */
356         ot->invoke= file_select_invoke;
357         ot->poll= ED_operator_file_active;
358
359         /* rna */
360         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
361         RNA_def_boolean(ot->srna, "fill", 0, "Fill", "Select everything beginning with the last selection");
362 }
363
364 static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
365 {
366         ScrArea *sa= CTX_wm_area(C);
367         SpaceFile *sfile= CTX_wm_space_file(C);
368         FileSelection sel;
369         int numfiles = filelist_numfiles(sfile->files);
370         int i;
371         int is_selected = 0;
372
373         sel.first = 0; 
374         sel.last = numfiles-1;
375
376         /* Is any file selected ? */
377         for ( i=0; i < numfiles; ++i) {
378                 if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
379                         is_selected = 1;
380                         break;
381                 }
382         }
383         /* select all only if previously no file was selected */
384         if (is_selected) {
385                 filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL);
386         }
387         else {
388                 const FileCheckType check_type= (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
389                 filelist_select(sfile->files, &sel, FILE_SEL_ADD, SELECTED_FILE, check_type);
390         }
391         ED_area_tag_redraw(sa);
392         return OPERATOR_FINISHED;
393 }
394
395 void FILE_OT_select_all_toggle(wmOperatorType *ot)
396 {
397         /* identifiers */
398         ot->name= "Select/Deselect All Files";
399         ot->description= "Select/deselect all files";
400         ot->idname= "FILE_OT_select_all_toggle";
401         
402         /* api callbacks */
403         ot->exec= file_select_all_exec;
404         ot->poll= ED_operator_file_active;
405
406         /* rna */
407
408         
409 }
410
411 /* ---------- BOOKMARKS ----------- */
412
413 static int bookmark_select_exec(bContext *C, wmOperator *op)
414 {
415         SpaceFile *sfile= CTX_wm_space_file(C);
416
417         if(RNA_struct_find_property(op->ptr, "dir")) {
418                 char entry[256];
419                 FileSelectParams* params = sfile->params;
420
421                 RNA_string_get(op->ptr, "dir", entry);
422                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
423                 BLI_cleanup_dir(G.main->name, params->dir);
424                 file_change_dir(C, 1);
425
426                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
427         }
428         
429         return OPERATOR_FINISHED;
430 }
431
432 void FILE_OT_select_bookmark(wmOperatorType *ot)
433 {
434         /* identifiers */
435         ot->name= "Select Directory";
436         ot->description= "Select a bookmarked directory";
437         ot->idname= "FILE_OT_select_bookmark";
438         
439         /* api callbacks */
440         ot->exec= bookmark_select_exec;
441         ot->poll= ED_operator_file_active;
442
443         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
444 }
445
446 static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
447 {
448         ScrArea *sa= CTX_wm_area(C);
449         SpaceFile *sfile= CTX_wm_space_file(C);
450         struct FSMenu* fsmenu = fsmenu_get();
451         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
452
453         if (params->dir[0] != '\0') {
454                 char name[FILE_MAX];
455         
456                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
457                 BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
458                 fsmenu_write_file(fsmenu, name);
459         }
460
461         ED_area_tag_redraw(sa);
462         return OPERATOR_FINISHED;
463 }
464
465 void FILE_OT_bookmark_add(wmOperatorType *ot)
466 {
467         /* identifiers */
468         ot->name= "Add Bookmark";
469         ot->description= "Add a bookmark for the selected/active directory";
470         ot->idname= "FILE_OT_bookmark_add";
471         
472         /* api callbacks */
473         ot->exec= bookmark_add_exec;
474         ot->poll= ED_operator_file_active;
475 }
476
477 static int bookmark_delete_exec(bContext *C, wmOperator *op)
478 {
479         ScrArea *sa= CTX_wm_area(C);
480         struct FSMenu* fsmenu = fsmenu_get();
481         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
482         
483         if(RNA_struct_find_property(op->ptr, "index")) {
484                 int index = RNA_int_get(op->ptr, "index");
485                 if ( (index >-1) && (index < nentries)) {
486                         char name[FILE_MAX];
487                         
488                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
489                         BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
490                         fsmenu_write_file(fsmenu, name);
491                         ED_area_tag_redraw(sa);
492                 }
493         }
494
495         return OPERATOR_FINISHED;
496 }
497
498 void FILE_OT_delete_bookmark(wmOperatorType *ot)
499 {
500         /* identifiers */
501         ot->name= "Delete Bookmark";
502         ot->description= "Delete selected bookmark";
503         ot->idname= "FILE_OT_delete_bookmark";
504         
505         /* api callbacks */
506         ot->exec= bookmark_delete_exec;
507         ot->poll= ED_operator_file_active;
508
509         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
510 }
511
512 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
513 {
514         View2D* v2d = &ar->v2d;
515         FileSelectParams* params;
516         int numfiles, origfile; 
517
518         if(sfile==NULL || sfile->files==NULL) return 0;
519
520         numfiles = filelist_numfiles(sfile->files);
521         params = ED_fileselect_get_params(sfile);
522
523         origfile= params->active_file;
524
525         mx -= ar->winrct.xmin;
526         my -= ar->winrct.ymin;
527
528         if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
529                 float fx, fy;
530                 int active_file;
531
532                 UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
533
534                 active_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
535
536                 if((active_file >= 0) && (active_file < numfiles))
537                         params->active_file=active_file;
538                 else
539                         params->active_file= -1;
540         }
541         else
542                 params->active_file= -1;
543
544         return (params->active_file != origfile);
545 }
546
547 static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
548 {
549         ARegion *ar= CTX_wm_region(C);
550         SpaceFile *sfile= CTX_wm_space_file(C);
551
552         if(!file_hilight_set(sfile, ar, event->x, event->y))
553                 return OPERATOR_CANCELLED;
554
555         ED_area_tag_redraw(CTX_wm_area(C));
556         
557         return OPERATOR_FINISHED;
558 }
559
560 void FILE_OT_highlight(struct wmOperatorType *ot)
561 {
562         /* identifiers */
563         ot->name= "Highlight File";
564         ot->description= "Highlight selected file(s)";
565         ot->idname= "FILE_OT_highlight";
566         
567         /* api callbacks */
568         ot->invoke= file_highlight_invoke;
569         ot->poll= ED_operator_file_active;
570 }
571
572 int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
573 {
574         SpaceFile *sfile= CTX_wm_space_file(C);
575         wmOperator *op = sfile->op;
576         
577         sfile->op = NULL;
578
579         WM_event_fileselect_event(C, op, EVT_FILESELECT_CANCEL);
580         
581         return OPERATOR_FINISHED;
582 }
583
584 static int file_operator_poll(bContext *C)
585 {
586         int poll = ED_operator_file_active(C);
587         SpaceFile *sfile= CTX_wm_space_file(C);
588
589         if (!sfile || !sfile->op) poll= 0;
590
591         return poll;
592 }
593
594 void FILE_OT_cancel(struct wmOperatorType *ot)
595 {
596         /* identifiers */
597         ot->name= "Cancel File Load";
598         ot->description= "Cancel loading of selected file";
599         ot->idname= "FILE_OT_cancel";
600         
601         /* api callbacks */
602         ot->exec= file_cancel_exec;
603         ot->poll= file_operator_poll;
604 }
605
606
607 void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
608 {
609         BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
610         if(RNA_struct_find_property(op->ptr, "relative_path")) {
611                 if(RNA_boolean_get(op->ptr, "relative_path")) {
612                         BLI_path_rel(filepath, G.main->name);
613                 }
614         }
615
616         if(RNA_struct_find_property(op->ptr, "filename")) {
617                 RNA_string_set(op->ptr, "filename", sfile->params->file);
618         }
619         if(RNA_struct_find_property(op->ptr, "directory")) {
620                 RNA_string_set(op->ptr, "directory", sfile->params->dir);
621         }
622         if(RNA_struct_find_property(op->ptr, "filepath")) {
623                 RNA_string_set(op->ptr, "filepath", filepath);
624         }
625         
626         /* some ops have multiple files to select */
627         /* this is called on operators check() so clear collections first since
628          * they may be already set. */
629         {
630                 PointerRNA itemptr;
631                 PropertyRNA *prop_files= RNA_struct_find_property(op->ptr, "files");
632                 PropertyRNA *prop_dirs= RNA_struct_find_property(op->ptr, "dirs");
633                 int i, numfiles = filelist_numfiles(sfile->files);
634
635                 if(prop_files) {
636                         RNA_property_collection_clear(op->ptr, prop_files);
637                         for (i=0; i<numfiles; i++) {
638                                 if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
639                                         struct direntry *file= filelist_file(sfile->files, i);
640                                         RNA_property_collection_add(op->ptr, prop_files, &itemptr);
641                                         RNA_string_set(&itemptr, "name", file->relname);
642                                 }
643                         }
644                 }
645
646                 if(prop_dirs) {
647                         RNA_property_collection_clear(op->ptr, prop_dirs);
648                         for (i=0; i<numfiles; i++) {
649                                 if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
650                                         struct direntry *file= filelist_file(sfile->files, i);
651                                         RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
652                                         RNA_string_set(&itemptr, "name", file->relname);
653                                 }
654                         }
655                 }
656
657
658         }
659 }
660
661 void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
662 {
663         PropertyRNA *prop;
664
665         /* If neither of the above are set, split the filepath back */
666         if((prop= RNA_struct_find_property(op->ptr, "filepath"))) {
667                 char filepath[FILE_MAX];
668                 RNA_property_string_get(op->ptr, prop, filepath);
669                 BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
670         }
671         else {
672                 if((prop= RNA_struct_find_property(op->ptr, "filename"))) {
673                         RNA_property_string_get(op->ptr, prop, sfile->params->file);
674                 }
675                 if((prop= RNA_struct_find_property(op->ptr, "directory"))) {
676                         RNA_property_string_get(op->ptr, prop, sfile->params->dir);
677                 }
678         }
679         
680         /* we could check for relative_path property which is used when converting
681          * in the other direction but doesnt hurt to do this every time */
682         BLI_path_abs(sfile->params->dir, G.main->name);
683
684         /* XXX, files and dirs updates missing, not really so important though */
685 }
686
687 void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
688 {
689         SpaceFile *sfile= CTX_wm_space_file(C);
690         wmOperator *op= sfile->op;
691         if(op) { /* fail on reload */
692                 if(op->type->check) {
693                         char filepath[FILE_MAX];
694                         file_sfile_to_operator(op, sfile, filepath);
695                         
696                         /* redraw */
697                         if(op->type->check(C, op)) {
698                                 file_operator_to_sfile(sfile, op);
699         
700                                 /* redraw, else the changed settings wont get updated */
701                                 ED_area_tag_redraw(CTX_wm_area(C));
702                         }
703                 }
704         }
705 }
706
707 int file_draw_check_exists(SpaceFile *sfile)
708 {
709         if(sfile->op) { /* fails on reload */
710                 if(RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
711                         if(RNA_boolean_get(sfile->op->ptr, "check_existing")) {
712                                 char filepath[FILE_MAX];
713                                 BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
714                                 if(BLI_exists(filepath) && !BLI_is_dir(filepath)) {
715                                         return TRUE;
716                                 }
717                         }
718                 }
719         }
720
721         return FALSE;
722 }
723
724 /* sends events now, so things get handled on windowqueue level */
725 int file_exec(bContext *C, wmOperator *exec_op)
726 {
727         SpaceFile *sfile= CTX_wm_space_file(C);
728         char filepath[FILE_MAX];
729         
730         if(sfile->op) {
731                 wmOperator *op= sfile->op;
732         
733                 /* when used as a macro, for doubleclick, 
734                  to prevent closing when doubleclicking on .. item */
735                 if (RNA_boolean_get(exec_op->ptr, "need_active")) {
736                         int i, active=0;
737                         
738                         for (i=0; i<filelist_numfiles(sfile->files); i++) {
739                                 if(filelist_is_selected(sfile->files, i, CHECK_ALL)) {
740                                         active=1;
741                                         break;
742                                 }
743                         }
744                         if (active == 0)
745                                 return OPERATOR_CANCELLED;
746                 }
747                 
748                 sfile->op = NULL;
749
750                 file_sfile_to_operator(op, sfile, filepath);
751
752                 if (BLI_exists(sfile->params->dir))
753                         fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, 0, 1);
754
755                 BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
756                 fsmenu_write_file(fsmenu_get(), filepath);
757                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
758
759         }
760                                 
761         return OPERATOR_FINISHED;
762 }
763
764 void FILE_OT_execute(struct wmOperatorType *ot)
765 {
766         /* identifiers */
767         ot->name= "Execute File Window";
768         ot->description= "Execute selected file";
769         ot->idname= "FILE_OT_execute";
770         
771         /* api callbacks */
772         ot->exec= file_exec;
773         ot->poll= file_operator_poll; 
774         
775         RNA_def_boolean(ot->srna, "need_active", 0, "Need Active", "Only execute if there's an active selected file in the file list");
776 }
777
778
779 int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
780 {
781         SpaceFile *sfile= CTX_wm_space_file(C);
782         
783         if(sfile->params) {
784                 if (BLI_has_parent(sfile->params->dir)) {
785                         BLI_parent_dir(sfile->params->dir);
786                         BLI_cleanup_dir(G.main->name, sfile->params->dir);
787                         file_change_dir(C, 0);
788                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
789                 }
790         }               
791         
792         return OPERATOR_FINISHED;
793
794 }
795
796
797 void FILE_OT_parent(struct wmOperatorType *ot)
798 {
799         /* identifiers */
800         ot->name= "Parent File";
801         ot->description= "Move to parent directory";
802         ot->idname= "FILE_OT_parent";
803         
804         /* api callbacks */
805         ot->exec= file_parent_exec;
806         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
807 }
808
809
810 static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
811 {
812         SpaceFile *sfile= CTX_wm_space_file(C);
813
814         ED_fileselect_clear(C, sfile);
815
816         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
817
818         return OPERATOR_FINISHED;
819
820 }
821
822 void FILE_OT_previous(struct wmOperatorType *ot)
823 {
824         /* identifiers */
825         ot->name= "Previous Folder";
826         ot->description= "Move to previous folder";
827         ot->idname= "FILE_OT_previous";
828         
829         /* api callbacks */
830         ot->exec= file_previous_exec;
831         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
832 }
833
834 int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
835 {
836         SpaceFile *sfile= CTX_wm_space_file(C);
837
838         if(sfile->params) {
839                 if (!sfile->folders_next)
840                         sfile->folders_next = folderlist_new();
841
842                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
843                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
844                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
845
846                 file_change_dir(C, 1);
847         }
848         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
849
850         return OPERATOR_FINISHED;
851 }
852
853 void FILE_OT_next(struct wmOperatorType *ot)
854 {
855         /* identifiers */
856         ot->name= "Next Folder";
857         ot->description= "Move to next folder";
858         ot->idname= "FILE_OT_next";
859         
860         /* api callbacks */
861         ot->exec= file_next_exec;
862         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
863 }
864
865 int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
866 {
867         SpaceFile *sfile= CTX_wm_space_file(C);
868         if(sfile->params) {
869                 if (!sfile->folders_next)
870                         sfile->folders_next = folderlist_new();
871
872                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
873                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
874
875                 // update folders_prev so we can check for it in folderlist_clear_next()
876                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
877
878                 file_change_dir(C, 1);
879         }               
880         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
881
882         return OPERATOR_FINISHED;
883 }
884
885
886 /* only meant for timer usage */
887 static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
888 {
889         ScrArea *sa = CTX_wm_area(C);
890         SpaceFile *sfile= CTX_wm_space_file(C);
891         ARegion *ar, *oldar= CTX_wm_region(C);
892         int offset;
893         int numfiles, numfiles_layout;
894         int edit_idx = 0;
895         int i;
896
897         /* escape if not our timer */
898         if(sfile->smoothscroll_timer==NULL || sfile->smoothscroll_timer!=event->customdata)
899                 return OPERATOR_PASS_THROUGH;
900         
901         numfiles = filelist_numfiles(sfile->files);
902
903         /* check if we are editing a name */
904         for (i=0; i < numfiles; ++i)
905         {
906                 if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
907                         edit_idx=i;
908                         break;
909                 }
910         }
911
912         /* if we are not editing, we are done */
913         if (0==edit_idx) {
914                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
915                 sfile->smoothscroll_timer=NULL;
916                 return OPERATOR_PASS_THROUGH;
917         }
918
919         /* we need the correct area for scrolling */
920         ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
921         if (!ar || ar->regiontype != RGN_TYPE_WINDOW) {
922                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
923                 sfile->smoothscroll_timer=NULL;
924                 return OPERATOR_PASS_THROUGH;
925         }
926
927         offset = ED_fileselect_layout_offset(sfile->layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax);
928         if (offset<0) offset=0;
929
930         /* scroll offset is the first file in the row/column we are editing in */
931         if (sfile->scroll_offset == 0) {
932                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
933                         sfile->scroll_offset = (edit_idx/sfile->layout->rows)*sfile->layout->rows;
934                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->rows;
935                 } else {
936                         sfile->scroll_offset = (edit_idx/sfile->layout->columns)*sfile->layout->columns;
937                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->columns;
938                 }
939         }
940         
941         numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar);
942         
943         /* check if we have reached our final scroll position */
944         if ( (sfile->scroll_offset >= offset) && (sfile->scroll_offset < offset + numfiles_layout) ) {
945                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
946                 sfile->smoothscroll_timer=NULL;
947                 return OPERATOR_FINISHED;
948         }
949
950         /* temporarily set context to the main window region, 
951          * so the scroll operators work */
952         CTX_wm_region_set(C, ar);
953         
954         /* scroll one step in the desired direction */
955         if (sfile->scroll_offset < offset) {
956                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
957                         WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL);
958                 } else {
959                         WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL);
960                 }
961                 
962         } else {
963                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
964                         WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL);
965                 } else {
966                         WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL);
967                 }
968         }
969         
970         ED_region_tag_redraw(CTX_wm_region(C));
971         
972         /* and restore context */
973         CTX_wm_region_set(C, oldar);
974         
975         return OPERATOR_FINISHED;
976 }
977
978
979 void FILE_OT_smoothscroll(wmOperatorType *ot)
980 {
981         
982         /* identifiers */
983         ot->name= "Smooth Scroll";
984         ot->idname= "FILE_OT_smoothscroll";
985         ot->description="Smooth scroll to make editable file visible";
986         
987         /* api callbacks */
988         ot->invoke= file_smoothscroll_invoke;
989         
990         ot->poll= ED_operator_file_active;
991 }
992
993
994 /* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
995    The actual name is returned in 'name', 'folder' contains the complete path, including the new folder name.
996 */
997 static int new_folder_path(const char* parent, char *folder, char *name)
998 {
999         int i = 1;
1000         int len = 0;
1001
1002         BLI_strncpy(name, "New Folder", FILE_MAXFILE);
1003         BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
1004         /* check whether folder with the name already exists, in this case
1005            add number to the name. Check length of generated name to avoid
1006            crazy case of huge number of folders each named 'New Folder (x)' */
1007         while (BLI_exists(folder) && (len<FILE_MAXFILE)) {
1008                 len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
1009                 BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
1010                 i++;
1011         }
1012
1013         return (len<FILE_MAXFILE);
1014 }
1015
1016 int file_directory_new_exec(bContext *C, wmOperator *op)
1017 {
1018         char name[FILE_MAXFILE];
1019         char path[FILE_MAX];
1020         int generate_name= 1;
1021
1022         SpaceFile *sfile= CTX_wm_space_file(C);
1023         
1024         if(!sfile->params) {
1025                 BKE_report(op->reports,RPT_WARNING, "No parent directory given");
1026                 return OPERATOR_CANCELLED;
1027         }
1028         
1029         path[0] = '\0';
1030
1031         if(RNA_struct_find_property(op->ptr, "directory")) {
1032                 RNA_string_get(op->ptr, "directory", path);
1033                 if (path[0] != '\0') generate_name= 0;
1034         }
1035
1036         if (generate_name) {
1037                 /* create a new, non-existing folder name */
1038                 if (!new_folder_path(sfile->params->dir, path, name)) {
1039                         BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder name");
1040                         return OPERATOR_CANCELLED;
1041                 }
1042         }
1043
1044         /* create the file */
1045         BLI_recurdir_fileops(path);
1046
1047         if (!BLI_exists(path)) {
1048                 BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder");
1049                 return OPERATOR_CANCELLED;
1050         } 
1051
1052         /* now remember file to jump into editing */
1053         BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
1054
1055         /* set timer to smoothly view newly generated file */
1056         sfile->smoothscroll_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0/1000.0);        /* max 30 frs/sec */
1057         sfile->scroll_offset=0;
1058
1059         /* reload dir to make sure we're seeing what's in the directory */
1060         ED_fileselect_clear(C, sfile);
1061         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1062
1063         return OPERATOR_FINISHED;
1064 }
1065
1066
1067 void FILE_OT_directory_new(struct wmOperatorType *ot)
1068 {
1069         /* identifiers */
1070         ot->name= "Create New Directory";
1071         ot->description= "Create a new directory";
1072         ot->idname= "FILE_OT_directory_new";
1073         
1074         /* api callbacks */
1075         ot->invoke= WM_operator_confirm;
1076         ot->exec= file_directory_new_exec;
1077         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1078
1079         RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Name of new directory");
1080
1081 }
1082
1083
1084 static void file_expand_directory(bContext *C)
1085 {
1086         SpaceFile *sfile= CTX_wm_space_file(C);
1087         
1088         if(sfile->params) {
1089                 if ( sfile->params->dir[0] == '~' ) {
1090                         char tmpstr[sizeof(sfile->params->dir)-1];
1091                         BLI_strncpy(tmpstr, sfile->params->dir+1, sizeof(tmpstr));
1092                         BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr);
1093                 }
1094
1095 #ifdef WIN32
1096                 if (sfile->params->dir[0] == '\0') {
1097                         get_default_root(sfile->params->dir);
1098                 }
1099                 /* change "C:" --> "C:\", [#28102] */
1100                 else if (   (isalpha(sfile->params->dir[0]) &&
1101                             (sfile->params->dir[1] == ':')) &&
1102                             (sfile->params->dir[2] == '\0')
1103
1104                 ) {
1105                         sfile->params->dir[2]= '\\';
1106                         sfile->params->dir[3]= '\0';
1107                 }
1108 #endif
1109         }
1110 }
1111
1112 static int file_directory_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1113 {
1114         SpaceFile *sfile= CTX_wm_space_file(C);
1115
1116         if(sfile->params) {
1117                 file_expand_directory(C);
1118                 
1119                 if (!BLI_exists(sfile->params->dir)) {
1120                         return WM_operator_confirm_message(C, op, "Create new directory?");
1121                 } 
1122
1123                 return file_directory_exec(C, op);
1124         }
1125
1126         return OPERATOR_CANCELLED;
1127 }
1128
1129
1130
1131 int file_directory_exec(bContext *C, wmOperator *UNUSED(unused))
1132 {
1133         SpaceFile *sfile= CTX_wm_space_file(C);
1134         
1135         if(sfile->params) {
1136                 file_expand_directory(C);
1137
1138                 if (!BLI_exists(sfile->params->dir)) {
1139                         BLI_recurdir_fileops(sfile->params->dir);
1140                 }
1141
1142                 /* special case, user may have pasted a fulepath into the directory */
1143                 if(BLI_exists(sfile->params->dir) && BLI_is_dir(sfile->params->dir) == 0) {
1144                         char path[sizeof(sfile->params->dir)];
1145                         BLI_strncpy(path, sfile->params->dir, sizeof(path));
1146                         BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
1147                 }
1148
1149                 BLI_cleanup_dir(G.main->name, sfile->params->dir);
1150                 BLI_add_slash(sfile->params->dir);
1151                 file_change_dir(C, 1);
1152
1153                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1154         }               
1155         
1156
1157         return OPERATOR_FINISHED;
1158 }
1159
1160 int file_filename_exec(bContext *C, wmOperator *UNUSED(unused))
1161 {
1162         SpaceFile *sfile= CTX_wm_space_file(C);
1163         
1164         if(sfile->params) {
1165                 if (file_select_match(sfile, sfile->params->file))
1166                 {
1167                         sfile->params->file[0] = '\0';
1168                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
1169                 }
1170         }               
1171
1172         return OPERATOR_FINISHED;
1173 }
1174
1175 /* TODO, directory operator is non-functional while a library is loaded
1176  * until this is properly supported just disable it. */
1177 static int file_directory_poll(bContext *C)
1178 {
1179         /* sfile->files can be NULL on file load */
1180         SpaceFile *sfile= CTX_wm_space_file(C);
1181         return ED_operator_file_active(C) && (sfile->files==NULL || filelist_lib(sfile->files)==NULL);
1182 }
1183
1184 void FILE_OT_directory(struct wmOperatorType *ot)
1185 {
1186         /* identifiers */
1187         ot->name= "Enter Directory Name";
1188         ot->description= "Enter a directory name";
1189         ot->idname= "FILE_OT_directory";
1190         
1191         /* api callbacks */
1192         ot->invoke= file_directory_invoke;
1193         ot->exec= file_directory_exec;
1194         ot->poll= file_directory_poll; /* <- important, handler is on window level */
1195 }
1196
1197 void FILE_OT_refresh(struct wmOperatorType *ot)
1198 {
1199         /* identifiers */
1200         ot->name= "Refresh Filelist";
1201         ot->description= "Refresh the file list";
1202         ot->idname= "FILE_OT_refresh";
1203         
1204         /* api callbacks */
1205         ot->exec= file_refresh_exec;
1206         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1207 }
1208
1209 static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
1210 {
1211         SpaceFile *sfile= CTX_wm_space_file(C);
1212         
1213         if(sfile->params) {
1214                 sfile->params->flag ^= FILE_HIDE_DOT;
1215                 ED_fileselect_clear(C, sfile);
1216                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1217         }
1218         
1219         return OPERATOR_FINISHED;
1220 }
1221
1222
1223 void FILE_OT_hidedot(struct wmOperatorType *ot)
1224 {
1225         /* identifiers */
1226         ot->name= "Toggle Hide Dot Files";
1227         ot->description= "Toggle hide hidden dot files";
1228         ot->idname= "FILE_OT_hidedot";
1229         
1230         /* api callbacks */
1231         ot->exec= file_hidedot_exec;
1232         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1233 }
1234
1235 struct ARegion *file_buttons_region(struct ScrArea *sa)
1236 {
1237         ARegion *ar, *arnew;
1238         
1239         for(ar= sa->regionbase.first; ar; ar= ar->next)
1240                 if(ar->regiontype==RGN_TYPE_CHANNELS)
1241                         return ar;
1242
1243         /* add subdiv level; after header */
1244         for(ar= sa->regionbase.first; ar; ar= ar->next)
1245                 if(ar->regiontype==RGN_TYPE_HEADER)
1246                         break;
1247         
1248         /* is error! */
1249         if(ar==NULL) return NULL;
1250         
1251         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
1252         
1253         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
1254         arnew->regiontype= RGN_TYPE_CHANNELS;
1255         arnew->alignment= RGN_ALIGN_LEFT;
1256         
1257         arnew->flag = RGN_FLAG_HIDDEN;
1258         
1259         return arnew;
1260 }
1261
1262 static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
1263 {
1264         ScrArea *sa= CTX_wm_area(C);
1265         ARegion *ar= file_buttons_region(sa);
1266         
1267         if(ar)
1268                 ED_region_toggle_hidden(C, ar);
1269
1270         return OPERATOR_FINISHED;
1271 }
1272
1273 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
1274 {
1275         /* identifiers */
1276         ot->name= "Toggle Bookmarks";
1277         ot->description= "Toggle bookmarks display";
1278         ot->idname= "FILE_OT_bookmark_toggle";
1279         
1280         /* api callbacks */
1281         ot->exec= file_bookmark_toggle_exec;
1282         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1283 }
1284
1285
1286 static int file_filenum_exec(bContext *C, wmOperator *op)
1287 {
1288         SpaceFile *sfile= CTX_wm_space_file(C);
1289         ScrArea *sa= CTX_wm_area(C);
1290         
1291         int inc = RNA_int_get(op->ptr, "increment");
1292         if(sfile->params && (inc != 0)) {
1293                 BLI_newname(sfile->params->file, inc);
1294                 ED_area_tag_redraw(sa);
1295                 file_draw_check_cb(C, NULL, NULL);
1296                 // WM_event_add_notifier(C, NC_WINDOW, NULL);
1297         }
1298         
1299         return OPERATOR_FINISHED;
1300
1301 }
1302
1303 void FILE_OT_filenum(struct wmOperatorType *ot)
1304 {
1305         /* identifiers */
1306         ot->name= "Increment Number in Filename";
1307         ot->description= "Increment number in filename";
1308         ot->idname= "FILE_OT_filenum";
1309         
1310         /* api callbacks */
1311         ot->exec= file_filenum_exec;
1312         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1313
1314         /* props */
1315         RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100,100);
1316 }
1317
1318 static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
1319 {
1320         ScrArea *sa= CTX_wm_area(C);
1321         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
1322         
1323         if(sfile->params) {
1324                 int idx = sfile->params->active_file;
1325                 int numfiles = filelist_numfiles(sfile->files);
1326                 if ( (0<=idx) && (idx<numfiles) ) {
1327                         struct direntry *file= filelist_file(sfile->files, idx);
1328                         filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL);
1329                         BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
1330                         sfile->params->renamefile[0]= '\0';
1331                 }
1332                 ED_area_tag_redraw(sa);
1333         }
1334         
1335         return OPERATOR_FINISHED;
1336
1337 }
1338
1339 static int file_rename_poll(bContext *C)
1340 {
1341         int poll = ED_operator_file_active(C);
1342         SpaceFile *sfile= CTX_wm_space_file(C);
1343
1344         if (sfile && sfile->params) {
1345                 if (sfile->params->active_file < 0) { 
1346                         poll= 0;
1347                 } else {
1348                         char dir[FILE_MAX], group[FILE_MAX];    
1349                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
1350                 }
1351         }
1352         else
1353                 poll= 0;
1354         return poll;
1355 }
1356
1357 void FILE_OT_rename(struct wmOperatorType *ot)
1358 {
1359         /* identifiers */
1360         ot->name= "Rename File or Directory";
1361         ot->description= "Rename file or file directory";
1362         ot->idname= "FILE_OT_rename";
1363         
1364         /* api callbacks */
1365         ot->exec= file_rename_exec;
1366         ot->poll= file_rename_poll; 
1367
1368 }
1369
1370 static int file_delete_poll(bContext *C)
1371 {
1372         int poll = ED_operator_file_active(C);
1373         SpaceFile *sfile= CTX_wm_space_file(C);
1374         struct direntry* file;
1375
1376         if (sfile && sfile->params) {
1377                 if (sfile->params->active_file < 0) { 
1378                         poll= 0;
1379                 } else {
1380                         char dir[FILE_MAX], group[FILE_MAX];    
1381                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
1382                         file = filelist_file(sfile->files, sfile->params->active_file);
1383                         if (file && S_ISDIR(file->type)) poll= 0;
1384                 }
1385         }
1386         else
1387                 poll= 0;
1388                 
1389         return poll;
1390 }
1391
1392 int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
1393 {
1394         char str[FILE_MAX];
1395         SpaceFile *sfile= CTX_wm_space_file(C);
1396         struct direntry* file;
1397         
1398         
1399         file = filelist_file(sfile->files, sfile->params->active_file);
1400         BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
1401         BLI_delete(str, 0, 0);  
1402         ED_fileselect_clear(C, sfile);
1403         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1404         
1405         return OPERATOR_FINISHED;
1406
1407 }
1408
1409 void FILE_OT_delete(struct wmOperatorType *ot)
1410 {
1411         /* identifiers */
1412         ot->name= "Delete File";
1413         ot->description= "Delete selected file";
1414         ot->idname= "FILE_OT_delete";
1415         
1416         /* api callbacks */
1417         ot->invoke= WM_operator_confirm;
1418         ot->exec= file_delete_exec;
1419         ot->poll= file_delete_poll; /* <- important, handler is on window level */
1420 }
1421
1422
1423 void ED_operatormacros_file(void)
1424 {
1425 //      wmOperatorType *ot;
1426 //      wmOperatorTypeMacro *otmacro;
1427         
1428         /* future macros */
1429 }