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