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