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