Merging r50522 through r50572 from trunk into soc-2011-tomato
[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
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, 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_rcti_init(&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, short do_diropen)
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                         if (do_diropen == FALSE) {
176                                 params->file[0] = '\0';
177                                 retval = FILE_SELECT_DIR;
178                         }
179                         /* the path is too long and we are not going up! */
180                         else if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
181                                 // XXX error("Path too long, cannot enter this directory");
182                         }
183                         else {
184                                 if (strcmp(file->relname, "..") == 0) {
185                                         /* avoids /../../ */
186                                         BLI_parent_dir(params->dir);
187                                 }
188                                 else {
189                                         BLI_cleanup_dir(G.main->name, params->dir);
190                                         strcat(params->dir, file->relname);
191                                         BLI_add_slash(params->dir);
192                                 }
193
194                                 file_change_dir(C, 0);
195                                 retval = FILE_SELECT_DIR;
196                         }
197                 }
198                 else {
199                         if (file->relname) {
200                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
201                         }
202                         retval = FILE_SELECT_FILE;
203                 }
204         }
205         return retval;
206 }
207
208
209 static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, short fill, short do_diropen)
210 {
211         SpaceFile *sfile = CTX_wm_space_file(C);
212         FileSelect retval = FILE_SELECT_NOTHING;
213         FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
214         const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
215         
216         /* flag the files as selected in the filelist */
217         filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type);
218         
219         /* Don't act on multiple selected files */
220         if (sel.first != sel.last) select = 0;
221
222         /* Do we have a valid selection and are we actually selecting */
223         if ((sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE))) {
224                 /* Check last selection, if selected, act on the file or dir */
225                 if (filelist_is_selected(sfile->files, sel.last, check_type)) {
226                         retval = file_select_do(C, sel.last, do_diropen);
227                 }
228         }
229
230         /* update operator for name change event */
231         file_draw_check_cb(C, NULL, NULL);
232         
233         return retval;
234 }
235
236 static int file_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
237 {
238         ARegion *ar = CTX_wm_region(C);
239         SpaceFile *sfile = CTX_wm_space_file(C);
240         FileSelectParams *params = ED_fileselect_get_params(sfile);
241         FileSelection sel;
242         rcti rect;
243
244         int result;
245
246         result = WM_border_select_modal(C, op, event);
247
248         if (result == OPERATOR_RUNNING_MODAL) {
249
250                 WM_operator_properties_border_to_rcti(op, &rect);
251
252                 BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
253
254                 sel = file_selection_get(C, &rect, 0);
255                 if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
256                         file_deselect_all(sfile, HILITED_FILE);
257                         filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL);
258                         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
259                 }
260                 params->sel_first = sel.first; params->sel_last = sel.last;
261
262         }
263         else {
264                 params->active_file = -1;
265                 params->sel_first = params->sel_last = -1;
266                 file_deselect_all(sfile, HILITED_FILE);
267                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
268         }
269
270         return result;
271 }
272
273 static int file_border_select_exec(bContext *C, wmOperator *op)
274 {
275         ARegion *ar = CTX_wm_region(C);
276         rcti rect;
277         FileSelect ret;
278         int extend = RNA_boolean_get(op->ptr, "extend");
279         short select = (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
280
281         WM_operator_properties_border_to_rcti(op, &rect);
282
283         if (!extend) {
284                 SpaceFile *sfile = CTX_wm_space_file(C);
285
286                 file_deselect_all(sfile, SELECTED_FILE);
287         }
288
289         BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
290
291         ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, FALSE, FALSE);
292         if (FILE_SELECT_DIR == ret) {
293                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
294         }
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         int do_diropen = RNA_boolean_get(op->ptr, "open");
328
329         if (ar->regiontype != RGN_TYPE_WINDOW)
330                 return OPERATOR_CANCELLED;
331
332         rect.xmin = rect.xmax = event->mval[0];
333         rect.ymin = rect.ymax = event->mval[1];
334
335         if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin))
336                 return OPERATOR_CANCELLED;
337
338         /* single select, deselect all selected first */
339         if (!extend) file_deselect_all(sfile, SELECTED_FILE);
340
341         ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
342         if (FILE_SELECT_DIR == ret)
343                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
344         else if (FILE_SELECT_FILE == ret)
345                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
346
347         WM_event_add_mousemove(C); /* for directory changes */
348         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
349
350         return OPERATOR_FINISHED;
351 }
352
353 void FILE_OT_select(wmOperatorType *ot)
354 {
355         /* identifiers */
356         ot->name = "Activate/Select File";
357         ot->description = "Activate/select file";
358         ot->idname = "FILE_OT_select";
359         
360         /* api callbacks */
361         ot->invoke = file_select_invoke;
362         ot->poll = ED_operator_file_active;
363
364         /* rna */
365         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
366         RNA_def_boolean(ot->srna, "fill", FALSE, "Fill", "Select everything beginning with the last selection");
367         RNA_def_boolean(ot->srna, "open", TRUE, "Open", "Open a directory when selecting it");
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_highlight_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_rcti_isect_pt(&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_highlight_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                         int num_files = 0;
643                         RNA_property_collection_clear(op->ptr, prop_files);
644                         for (i = 0; i < numfiles; i++) {
645                                 if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
646                                         struct direntry *file = filelist_file(sfile->files, i);
647                                         RNA_property_collection_add(op->ptr, prop_files, &itemptr);
648                                         RNA_string_set(&itemptr, "name", file->relname);
649                                         num_files++;
650                                 }
651                         }
652                         /* make sure the file specified in the filename button is added even if no files selected */
653                         if (0 == num_files) {
654                                 RNA_property_collection_add(op->ptr, prop_files, &itemptr);
655                                 RNA_string_set(&itemptr, "name", sfile->params->file);
656                         }
657                 }
658
659                 if (prop_dirs) {
660                         int num_dirs = 0;
661                         RNA_property_collection_clear(op->ptr, prop_dirs);
662                         for (i = 0; i < numfiles; i++) {
663                                 if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
664                                         struct direntry *file = filelist_file(sfile->files, i);
665                                         RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
666                                         RNA_string_set(&itemptr, "name", file->relname);
667                                         num_dirs++;
668                                 }
669                         }
670                         
671                         /* make sure the directory specified in the button is added even if no directory selected */
672                         if (0 == num_dirs) {
673                                 RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
674                                 RNA_string_set(&itemptr, "name", sfile->params->dir);
675                         }
676                 }
677
678
679         }
680 }
681
682 void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
683 {
684         PropertyRNA *prop;
685
686         /* If neither of the above are set, split the filepath back */
687         if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
688                 char filepath[FILE_MAX];
689                 RNA_property_string_get(op->ptr, prop, filepath);
690                 BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
691         }
692         else {
693                 if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
694                         RNA_property_string_get(op->ptr, prop, sfile->params->file);
695                 }
696                 if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
697                         RNA_property_string_get(op->ptr, prop, sfile->params->dir);
698                 }
699         }
700         
701         /* we could check for relative_path property which is used when converting
702          * in the other direction but doesnt hurt to do this every time */
703         BLI_path_abs(sfile->params->dir, G.main->name);
704
705         /* XXX, files and dirs updates missing, not really so important though */
706 }
707
708 void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
709 {
710         SpaceFile *sfile = CTX_wm_space_file(C);
711         wmOperator *op = sfile->op;
712         if (op) { /* fail on reload */
713                 if (op->type->check) {
714                         char filepath[FILE_MAX];
715                         file_sfile_to_operator(op, sfile, filepath);
716                         
717                         /* redraw */
718                         if (op->type->check(C, op)) {
719                                 file_operator_to_sfile(sfile, op);
720         
721                                 /* redraw, else the changed settings wont get updated */
722                                 ED_area_tag_redraw(CTX_wm_area(C));
723                         }
724                 }
725         }
726 }
727
728 int file_draw_check_exists(SpaceFile *sfile)
729 {
730         if (sfile->op) { /* fails on reload */
731                 if (RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
732                         if (RNA_boolean_get(sfile->op->ptr, "check_existing")) {
733                                 char filepath[FILE_MAX];
734                                 BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
735                                 if (BLI_is_file(filepath)) {
736                                         return TRUE;
737                                 }
738                         }
739                 }
740         }
741
742         return FALSE;
743 }
744
745 /* sends events now, so things get handled on windowqueue level */
746 int file_exec(bContext *C, wmOperator *exec_op)
747 {
748         SpaceFile *sfile = CTX_wm_space_file(C);
749         char filepath[FILE_MAX];
750         
751         if (sfile->op) {
752                 wmOperator *op = sfile->op;
753         
754                 /* when used as a macro, for doubleclick, 
755                  * to prevent closing when doubleclicking on .. item */
756                 if (RNA_boolean_get(exec_op->ptr, "need_active")) {
757                         int i, active = 0;
758                         
759                         for (i = 0; i < filelist_numfiles(sfile->files); i++) {
760                                 if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
761                                         active = 1;
762                                         break;
763                                 }
764                         }
765                         if (active == 0)
766                                 return OPERATOR_CANCELLED;
767                 }
768                 
769                 sfile->op = NULL;
770
771                 file_sfile_to_operator(op, sfile, filepath);
772
773                 if (BLI_exists(sfile->params->dir))
774                         fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, 0, 1);
775
776                 BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
777                 fsmenu_write_file(fsmenu_get(), filepath);
778                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
779
780         }
781                                 
782         return OPERATOR_FINISHED;
783 }
784
785 void FILE_OT_execute(struct wmOperatorType *ot)
786 {
787         PropertyRNA *prop;
788
789         /* identifiers */
790         ot->name = "Execute File Window";
791         ot->description = "Execute selected file";
792         ot->idname = "FILE_OT_execute";
793         
794         /* api callbacks */
795         ot->exec = file_exec;
796         ot->poll = file_operator_poll; 
797         
798         prop = RNA_def_boolean(ot->srna, "need_active", 0, "Need Active",
799                                "Only execute if there's an active selected file in the file list");
800         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
801 }
802
803
804 int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
805 {
806         SpaceFile *sfile = CTX_wm_space_file(C);
807         
808         if (sfile->params) {
809                 if (BLI_has_parent(sfile->params->dir)) {
810                         BLI_parent_dir(sfile->params->dir);
811                         BLI_cleanup_dir(G.main->name, sfile->params->dir);
812                         file_change_dir(C, 0);
813                         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
814                 }
815         }               
816         
817         return OPERATOR_FINISHED;
818
819 }
820
821
822 void FILE_OT_parent(struct wmOperatorType *ot)
823 {
824         /* identifiers */
825         ot->name = "Parent File";
826         ot->description = "Move to parent directory";
827         ot->idname = "FILE_OT_parent";
828         
829         /* api callbacks */
830         ot->exec = file_parent_exec;
831         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
832 }
833
834
835 static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
836 {
837         SpaceFile *sfile = CTX_wm_space_file(C);
838         struct FSMenu *fsmenu = fsmenu_get();
839
840         ED_fileselect_clear(C, sfile);
841
842         /* refresh system directory menu */
843         fsmenu_refresh_system_category(fsmenu);
844
845         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
846
847         return OPERATOR_FINISHED;
848
849 }
850
851 void FILE_OT_previous(struct wmOperatorType *ot)
852 {
853         /* identifiers */
854         ot->name = "Previous Folder";
855         ot->description = "Move to previous folder";
856         ot->idname = "FILE_OT_previous";
857         
858         /* api callbacks */
859         ot->exec = file_previous_exec;
860         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
861 }
862
863 int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
864 {
865         SpaceFile *sfile = CTX_wm_space_file(C);
866
867         if (sfile->params) {
868                 if (!sfile->folders_next)
869                         sfile->folders_next = folderlist_new();
870
871                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
872                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
873                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
874
875                 file_change_dir(C, 1);
876         }
877         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
878
879         return OPERATOR_FINISHED;
880 }
881
882 void FILE_OT_next(struct wmOperatorType *ot)
883 {
884         /* identifiers */
885         ot->name = "Next Folder";
886         ot->description = "Move to next folder";
887         ot->idname = "FILE_OT_next";
888         
889         /* api callbacks */
890         ot->exec = file_next_exec;
891         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
892 }
893
894 int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
895 {
896         SpaceFile *sfile = CTX_wm_space_file(C);
897         if (sfile->params) {
898                 if (!sfile->folders_next)
899                         sfile->folders_next = folderlist_new();
900
901                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
902                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
903
904                 // update folders_prev so we can check for it in folderlist_clear_next()
905                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
906
907                 file_change_dir(C, 1);
908         }               
909         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
910
911         return OPERATOR_FINISHED;
912 }
913
914
915 /* only meant for timer usage */
916 static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
917 {
918         ScrArea *sa = CTX_wm_area(C);
919         SpaceFile *sfile = CTX_wm_space_file(C);
920         ARegion *ar, *oldar = CTX_wm_region(C);
921         int offset;
922         int numfiles, numfiles_layout;
923         int edit_idx = 0;
924         int i;
925
926         /* escape if not our timer */
927         if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
928                 return OPERATOR_PASS_THROUGH;
929         
930         numfiles = filelist_numfiles(sfile->files);
931
932         /* check if we are editing a name */
933         for (i = 0; i < numfiles; ++i) {
934                 if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
935                         edit_idx = i;
936                         break;
937                 }
938         }
939
940         /* if we are not editing, we are done */
941         if (0 == edit_idx) {
942                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
943                 sfile->smoothscroll_timer = NULL;
944                 return OPERATOR_PASS_THROUGH;
945         }
946
947         /* we need the correct area for scrolling */
948         ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
949         if (!ar || ar->regiontype != RGN_TYPE_WINDOW) {
950                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
951                 sfile->smoothscroll_timer = NULL;
952                 return OPERATOR_PASS_THROUGH;
953         }
954
955         offset = ED_fileselect_layout_offset(sfile->layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax);
956         if (offset < 0) offset = 0;
957
958         /* scroll offset is the first file in the row/column we are editing in */
959         if (sfile->scroll_offset == 0) {
960                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
961                         sfile->scroll_offset = (edit_idx / sfile->layout->rows) * sfile->layout->rows;
962                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->rows;
963                 }
964                 else {
965                         sfile->scroll_offset = (edit_idx / sfile->layout->columns) * sfile->layout->columns;
966                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->columns;
967                 }
968         }
969         
970         numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar);
971         
972         /* check if we have reached our final scroll position */
973         if ( (sfile->scroll_offset >= offset) && (sfile->scroll_offset < offset + numfiles_layout) ) {
974                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
975                 sfile->smoothscroll_timer = NULL;
976                 return OPERATOR_FINISHED;
977         }
978
979         /* temporarily set context to the main window region, 
980          * so the scroll operators work */
981         CTX_wm_region_set(C, ar);
982         
983         /* scroll one step in the desired direction */
984         if (sfile->scroll_offset < offset) {
985                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
986                         WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL);
987                 }
988                 else {
989                         WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL);
990                 }
991                 
992         }
993         else {
994                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
995                         WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL);
996                 }
997                 else {
998                         WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL);
999                 }
1000         }
1001         
1002         ED_region_tag_redraw(CTX_wm_region(C));
1003         
1004         /* and restore context */
1005         CTX_wm_region_set(C, oldar);
1006         
1007         return OPERATOR_FINISHED;
1008 }
1009
1010
1011 void FILE_OT_smoothscroll(wmOperatorType *ot)
1012 {
1013         
1014         /* identifiers */
1015         ot->name = "Smooth Scroll";
1016         ot->idname = "FILE_OT_smoothscroll";
1017         ot->description = "Smooth scroll to make editable file visible";
1018         
1019         /* api callbacks */
1020         ot->invoke = file_smoothscroll_invoke;
1021         
1022         ot->poll = ED_operator_file_active;
1023 }
1024
1025
1026 /* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
1027  * The actual name is returned in 'name', 'folder' contains the complete path, including the new folder name.
1028  */
1029 static int new_folder_path(const char *parent, char *folder, char *name)
1030 {
1031         int i = 1;
1032         int len = 0;
1033
1034         BLI_strncpy(name, "New Folder", FILE_MAXFILE);
1035         BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
1036         /* check whether folder with the name already exists, in this case
1037          * add number to the name. Check length of generated name to avoid
1038          * crazy case of huge number of folders each named 'New Folder (x)' */
1039         while (BLI_exists(folder) && (len < FILE_MAXFILE)) {
1040                 len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
1041                 BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
1042                 i++;
1043         }
1044
1045         return (len < FILE_MAXFILE);
1046 }
1047
1048 int file_directory_new_exec(bContext *C, wmOperator *op)
1049 {
1050         char name[FILE_MAXFILE];
1051         char path[FILE_MAX];
1052         int generate_name = 1;
1053
1054         SpaceFile *sfile = CTX_wm_space_file(C);
1055         
1056         if (!sfile->params) {
1057                 BKE_report(op->reports, RPT_WARNING, "No parent directory given");
1058                 return OPERATOR_CANCELLED;
1059         }
1060         
1061         path[0] = '\0';
1062
1063         if (RNA_struct_find_property(op->ptr, "directory")) {
1064                 RNA_string_get(op->ptr, "directory", path);
1065                 if (path[0] != '\0') generate_name = 0;
1066         }
1067
1068         if (generate_name) {
1069                 /* create a new, non-existing folder name */
1070                 if (!new_folder_path(sfile->params->dir, path, name)) {
1071                         BKE_report(op->reports, RPT_ERROR, "Couldn't create new folder name");
1072                         return OPERATOR_CANCELLED;
1073                 }
1074         }
1075
1076         /* create the file */
1077         BLI_dir_create_recursive(path);
1078
1079         if (!BLI_exists(path)) {
1080                 BKE_report(op->reports, RPT_ERROR, "Couldn't create new folder");
1081                 return OPERATOR_CANCELLED;
1082         } 
1083
1084         /* now remember file to jump into editing */
1085         BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
1086
1087         /* set timer to smoothly view newly generated file */
1088         sfile->smoothscroll_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0 / 1000.0);    /* max 30 frs/sec */
1089         sfile->scroll_offset = 0;
1090
1091         /* reload dir to make sure we're seeing what's in the directory */
1092         ED_fileselect_clear(C, sfile);
1093         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
1094
1095         return OPERATOR_FINISHED;
1096 }
1097
1098
1099 void FILE_OT_directory_new(struct wmOperatorType *ot)
1100 {
1101         /* identifiers */
1102         ot->name = "Create New Directory";
1103         ot->description = "Create a new directory";
1104         ot->idname = "FILE_OT_directory_new";
1105         
1106         /* api callbacks */
1107         ot->invoke = WM_operator_confirm;
1108         ot->exec = file_directory_new_exec;
1109         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
1110
1111         RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Name of new directory");
1112
1113 }
1114
1115
1116 static void file_expand_directory(bContext *C)
1117 {
1118         SpaceFile *sfile = CTX_wm_space_file(C);
1119         
1120         if (sfile->params) {
1121                 /* TODO, what about // when relbase isn't valid? */
1122                 if (G.relbase_valid && BLI_path_is_rel(sfile->params->dir)) {
1123                         BLI_path_abs(sfile->params->dir, G.main->name);
1124                 }
1125                 else if (sfile->params->dir[0] == '~') {
1126                         char tmpstr[sizeof(sfile->params->dir) - 1];
1127                         BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr));
1128                         BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr);
1129                 }
1130
1131                 else if (sfile->params->dir[0] == '\0')
1132 #ifndef WIN32
1133                 {
1134                         sfile->params->dir[0] = '/';
1135                         sfile->params->dir[1] = '\0';
1136                 }
1137 #else
1138                 {
1139                         get_default_root(sfile->params->dir);
1140                 }
1141                 /* change "C:" --> "C:\", [#28102] */
1142                 else if (   (isalpha(sfile->params->dir[0]) &&
1143                              (sfile->params->dir[1] == ':')) &&
1144                             (sfile->params->dir[2] == '\0')
1145
1146                             ) {
1147                         sfile->params->dir[2] = '\\';
1148                         sfile->params->dir[3] = '\0';
1149                 }
1150 #endif
1151         }
1152 }
1153
1154 static int file_directory_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1155 {
1156         SpaceFile *sfile = CTX_wm_space_file(C);
1157
1158         if (sfile->params) {
1159                 file_expand_directory(C);
1160                 
1161                 if (!BLI_exists(sfile->params->dir)) {
1162                         return WM_operator_confirm_message(C, op, "Create new directory?");
1163                 }
1164
1165                 return file_directory_exec(C, op);
1166         }
1167
1168         return OPERATOR_CANCELLED;
1169 }
1170
1171
1172
1173 int file_directory_exec(bContext *C, wmOperator *UNUSED(unused))
1174 {
1175         SpaceFile *sfile = CTX_wm_space_file(C);
1176         
1177         if (sfile->params) {
1178                 file_expand_directory(C);
1179
1180                 if (!BLI_exists(sfile->params->dir)) {
1181                         BLI_dir_create_recursive(sfile->params->dir);
1182                 }
1183
1184                 /* special case, user may have pasted a filepath into the directory */
1185                 if (BLI_is_file(sfile->params->dir)) {
1186                         char path[sizeof(sfile->params->dir)];
1187                         BLI_strncpy(path, sfile->params->dir, sizeof(path));
1188                         BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
1189                 }
1190
1191                 BLI_cleanup_dir(G.main->name, sfile->params->dir);
1192                 BLI_add_slash(sfile->params->dir);
1193                 file_change_dir(C, 1);
1194
1195                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
1196         }
1197
1198         return OPERATOR_FINISHED;
1199 }
1200
1201 int file_filename_exec(bContext *C, wmOperator *UNUSED(unused))
1202 {
1203         SpaceFile *sfile = CTX_wm_space_file(C);
1204         char matched_file[FILE_MAX];
1205         if (sfile->params) {
1206                 matched_file[0] = '\0';
1207                 if (file_select_match(sfile, sfile->params->file, matched_file)) {
1208                         /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
1209                         sfile->params->file[0] = '\0';
1210                         /* replace the pattern (or filename that the user typed in, with the first selected file of the match */
1211                         BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
1212                         
1213                         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
1214                 }
1215         }
1216
1217         return OPERATOR_FINISHED;
1218 }
1219
1220 /* TODO, directory operator is non-functional while a library is loaded
1221  * until this is properly supported just disable it. */
1222 static int file_directory_poll(bContext *C)
1223 {
1224         /* sfile->files can be NULL on file load */
1225         SpaceFile *sfile = CTX_wm_space_file(C);
1226         return ED_operator_file_active(C) && (sfile->files == NULL || filelist_lib(sfile->files) == NULL);
1227 }
1228
1229 void FILE_OT_directory(struct wmOperatorType *ot)
1230 {
1231         /* identifiers */
1232         ot->name = "Enter Directory Name";
1233         ot->description = "Enter a directory name";
1234         ot->idname = "FILE_OT_directory";
1235         
1236         /* api callbacks */
1237         ot->invoke = file_directory_invoke;
1238         ot->exec = file_directory_exec;
1239         ot->poll = file_directory_poll; /* <- important, handler is on window level */
1240 }
1241
1242 void FILE_OT_refresh(struct wmOperatorType *ot)
1243 {
1244         /* identifiers */
1245         ot->name = "Refresh Filelist";
1246         ot->description = "Refresh the file list";
1247         ot->idname = "FILE_OT_refresh";
1248         
1249         /* api callbacks */
1250         ot->exec = file_refresh_exec;
1251         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
1252 }
1253
1254 static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
1255 {
1256         SpaceFile *sfile = CTX_wm_space_file(C);
1257         
1258         if (sfile->params) {
1259                 sfile->params->flag ^= FILE_HIDE_DOT;
1260                 ED_fileselect_clear(C, sfile);
1261                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
1262         }
1263         
1264         return OPERATOR_FINISHED;
1265 }
1266
1267
1268 void FILE_OT_hidedot(struct wmOperatorType *ot)
1269 {
1270         /* identifiers */
1271         ot->name = "Toggle Hide Dot Files";
1272         ot->description = "Toggle hide hidden dot files";
1273         ot->idname = "FILE_OT_hidedot";
1274         
1275         /* api callbacks */
1276         ot->exec = file_hidedot_exec;
1277         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
1278 }
1279
1280 ARegion *file_buttons_region(ScrArea *sa)
1281 {
1282         ARegion *ar, *arnew;
1283         
1284         for (ar = sa->regionbase.first; ar; ar = ar->next)
1285                 if (ar->regiontype == RGN_TYPE_CHANNELS)
1286                         return ar;
1287
1288         /* add subdiv level; after header */
1289         for (ar = sa->regionbase.first; ar; ar = ar->next)
1290                 if (ar->regiontype == RGN_TYPE_HEADER)
1291                         break;
1292         
1293         /* is error! */
1294         if (ar == NULL) return NULL;
1295         
1296         arnew = MEM_callocN(sizeof(ARegion), "buttons for file panels");
1297         
1298         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
1299         arnew->regiontype = RGN_TYPE_CHANNELS;
1300         arnew->alignment = RGN_ALIGN_LEFT;
1301         
1302         arnew->flag = RGN_FLAG_HIDDEN;
1303         
1304         return arnew;
1305 }
1306
1307 static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
1308 {
1309         ScrArea *sa = CTX_wm_area(C);
1310         ARegion *ar = file_buttons_region(sa);
1311         
1312         if (ar)
1313                 ED_region_toggle_hidden(C, ar);
1314
1315         return OPERATOR_FINISHED;
1316 }
1317
1318 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
1319 {
1320         /* identifiers */
1321         ot->name = "Toggle Bookmarks";
1322         ot->description = "Toggle bookmarks display";
1323         ot->idname = "FILE_OT_bookmark_toggle";
1324         
1325         /* api callbacks */
1326         ot->exec = file_bookmark_toggle_exec;
1327         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
1328 }
1329
1330
1331 static int file_filenum_exec(bContext *C, wmOperator *op)
1332 {
1333         SpaceFile *sfile = CTX_wm_space_file(C);
1334         ScrArea *sa = CTX_wm_area(C);
1335         
1336         int inc = RNA_int_get(op->ptr, "increment");
1337         if (sfile->params && (inc != 0)) {
1338                 BLI_newname(sfile->params->file, inc);
1339                 ED_area_tag_redraw(sa);
1340                 file_draw_check_cb(C, NULL, NULL);
1341                 // WM_event_add_notifier(C, NC_WINDOW, NULL);
1342         }
1343         
1344         return OPERATOR_FINISHED;
1345
1346 }
1347
1348 void FILE_OT_filenum(struct wmOperatorType *ot)
1349 {
1350         /* identifiers */
1351         ot->name = "Increment Number in Filename";
1352         ot->description = "Increment number in filename";
1353         ot->idname = "FILE_OT_filenum";
1354         
1355         /* api callbacks */
1356         ot->exec = file_filenum_exec;
1357         ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
1358
1359         /* props */
1360         RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
1361 }
1362
1363 static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
1364 {
1365         ScrArea *sa = CTX_wm_area(C);
1366         SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
1367         
1368         if (sfile->params) {
1369                 int idx = sfile->params->active_file;
1370                 int numfiles = filelist_numfiles(sfile->files);
1371                 if ( (0 <= idx) && (idx < numfiles) ) {
1372                         struct direntry *file = filelist_file(sfile->files, idx);
1373                         filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL);
1374                         BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
1375                         sfile->params->renamefile[0] = '\0';
1376                 }
1377                 ED_area_tag_redraw(sa);
1378         }
1379         
1380         return OPERATOR_FINISHED;
1381
1382 }
1383
1384 static int file_rename_poll(bContext *C)
1385 {
1386         int poll = ED_operator_file_active(C);
1387         SpaceFile *sfile = CTX_wm_space_file(C);
1388
1389         if (sfile && sfile->params) {
1390                 if (sfile->params->active_file < 0) { 
1391                         poll = 0;
1392                 }
1393                 else {
1394                         char dir[FILE_MAX], group[FILE_MAX];    
1395                         if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
1396                 }
1397         }
1398         else
1399                 poll = 0;
1400         return poll;
1401 }
1402
1403 void FILE_OT_rename(struct wmOperatorType *ot)
1404 {
1405         /* identifiers */
1406         ot->name = "Rename File or Directory";
1407         ot->description = "Rename file or file directory";
1408         ot->idname = "FILE_OT_rename";
1409         
1410         /* api callbacks */
1411         ot->exec = file_rename_exec;
1412         ot->poll = file_rename_poll; 
1413
1414 }
1415
1416 static int file_delete_poll(bContext *C)
1417 {
1418         int poll = ED_operator_file_active(C);
1419         SpaceFile *sfile = CTX_wm_space_file(C);
1420         struct direntry *file;
1421
1422         if (sfile && sfile->params) {
1423                 if (sfile->params->active_file < 0) { 
1424                         poll = 0;
1425                 }
1426                 else {
1427                         char dir[FILE_MAX], group[FILE_MAX];    
1428                         if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
1429                         file = filelist_file(sfile->files, sfile->params->active_file);
1430                         if (file && S_ISDIR(file->type)) poll = 0;
1431                 }
1432         }
1433         else
1434                 poll = 0;
1435                 
1436         return poll;
1437 }
1438
1439 int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
1440 {
1441         char str[FILE_MAX];
1442         SpaceFile *sfile = CTX_wm_space_file(C);
1443         struct direntry *file;
1444         
1445         
1446         file = filelist_file(sfile->files, sfile->params->active_file);
1447         BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
1448         BLI_delete(str, 0, 0);  
1449         ED_fileselect_clear(C, sfile);
1450         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
1451         
1452         return OPERATOR_FINISHED;
1453
1454 }
1455
1456 void FILE_OT_delete(struct wmOperatorType *ot)
1457 {
1458         /* identifiers */
1459         ot->name = "Delete File";
1460         ot->description = "Delete selected file";
1461         ot->idname = "FILE_OT_delete";
1462         
1463         /* api callbacks */
1464         ot->invoke = WM_operator_confirm;
1465         ot->exec = file_delete_exec;
1466         ot->poll = file_delete_poll; /* <- important, handler is on window level */
1467 }
1468
1469
1470 void ED_operatormacros_file(void)
1471 {
1472 //      wmOperatorType *ot;
1473 //      wmOperatorTypeMacro *otmacro;
1474         
1475         /* future macros */
1476 }