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