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