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