New optional operator function, check(), it takes the same arguments as execute().
authorCampbell Barton <ideasman42@gmail.com>
Fri, 17 Sep 2010 09:27:31 +0000 (09:27 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 17 Sep 2010 09:27:31 +0000 (09:27 +0000)
 This runs after changing a property and allows correcting incompatible options.
 Returning True will redraw the UI.

Currently this is used for setting the write extension when saving files, so changing the image format also corrects the extension.
The same is accessible from python where its used when saving SVG/EPS/PNG files.

This fixes: [#23828] obj export problems, [#23760] Exporting OBJ and filetype ending
also fixed document submission operator.

Now the filename in the file selector is the one used for writing this means we remove the "Save Over" popup which could be overlooked too easily.
Instead display the filename field with red tint, and a note in the tooltip.

14 files changed:
release/scripts/modules/io_utils.py
release/scripts/op/uv.py
release/scripts/op/wm.py
source/blender/blenkernel/intern/exotic.c
source/blender/editors/space_file/file_draw.c
source/blender/editors/space_file/file_intern.h
source/blender/editors/space_file/file_ops.c
source/blender/editors/space_file/file_panels.c
source/blender/editors/space_image/image_ops.c
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_operators.c

index 04c441100d737d93111356cad8691fa2472d4916..adc3afce71d0ba24fea838baaa09bd51f2be13dc 100644 (file)
@@ -34,6 +34,14 @@ class ExportHelper:
         context.window_manager.add_fileselect(self)
         return {'RUNNING_MODAL'}
 
+    def check(self, context):
+        filepath = bpy.path.ensure_ext(self.filepath, self.filename_ext)
+        if filepath != self.filepath:
+            self.filepath = filepath
+            return True
+        else:
+            return False
+
 
 class ImportHelper:
     filepath = StringProperty(name="File Path", description="Filepath used for importing the file", maxlen=1024, default="", subtype='FILE_PATH')
index cd0c2acf75ca241368f364c66d0d36aefbbb2429..d01ef070d8768e19defc1365ead42720259de5f6 100644 (file)
@@ -343,6 +343,15 @@ class ExportUVLayout(bpy.types.Operator):
 
         return {'FINISHED'}
 
+    def check(self, context):
+        filepath = bpy.path.ensure_ext(self.filepath, "." + self.mode.lower())
+        if filepath != self.filepath:
+            self.filepath = filepath
+            return True
+        else:
+            return False
+
+
     def invoke(self, context, event):
         self.size = self._image_size(context)
         wm = context.window_manager
index 7b500d028fd9472156241dbb309f60f9ed07fff0..af752d69ae913bd69a4d02928e8cb33f7db12316 100644 (file)
@@ -632,7 +632,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
 
     def draw(self, context):
         layout = self.layout
-        props = self
+        props = self.properties # XXX, this should not be needed, api problem!
         layout.label(text="Descriptor ID: '%s'" % props.doc_id)
         layout.prop(props, "doc_new", text="")
 
@@ -641,6 +641,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
         return wm.invoke_props_dialog(self, width=600)
 
 
+
 from bpy.props import *
 
 
index 973c18531c4ef3555b8cd2a81513dd044dc1af5a..9dac409226b5b0382c7c64072eef54420ee6ea9f 100644 (file)
@@ -577,15 +577,8 @@ void write_stl(Scene *scene, char *str)
        FILE   *fpSTL;
        int    numfacets = 0;
        ReportList *reports= NULL; /* XXX */
-       
-       if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
-       if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
-       if(BLI_testextensie(str,".stl")==0) strcat(str, ".stl");
 
-       if (BLI_exists(str)) {
-               ; //XXX if(saveover(str)==0)
-               //XXX   return;
-       }
+       /* XXX, operator needs to manage filename extension */
 
        fpSTL= fopen(str, "wb");
        
@@ -872,15 +865,7 @@ void write_dxf(struct Scene *scene, char *str)
        Base *base;
        FILE *fp;
        
-       if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
-       if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
-       if(BLI_testextensie(str,".dxf")==0) strcat(str, ".dxf");
-
-       
-       if (BLI_exists(str)) {
-               ; //XXX if(saveover(str)==0)
-               //      return;
-       }
+       /* XXX, operator needs to handle overwrite & rename */
 
        fp= fopen(str, "w");
        
index 5f435aa0cbededa818186a4990b044a86235ec13..0f627bda3dcac84fa7fecba4eaf2e3868191eabd 100644 (file)
@@ -172,6 +172,10 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
        
        /* Text input fields for directory and file. */
        if (available_w > 0) {
+               int overwrite_alert= file_draw_check_exists(sfile);
+               /* callbacks for operator check functions */
+               uiBlockSetFunc(block, file_draw_check_cb, NULL, NULL);
+
                but = uiDefBut(block, TEX, B_FS_DIRNAME, "",
                                 min_x, line1_y, line1_w-chan_offs, btn_h, 
                                 params->dir, 0.0, (float)FILE_MAX-1, 0, 0, 
@@ -182,9 +186,17 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
                but = uiDefBut(block, TEX, B_FS_FILENAME, "",
                                 min_x, line2_y, line2_w-chan_offs, btn_h,
                                 params->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, 
-                                "File name.");
+                                overwrite_alert ?"File name, overwrite existing." : "File name.");
                uiButSetCompleteFunc(but, autocomplete_file, NULL);
                uiButSetFlag(but, UI_BUT_NO_UTF8);
+               
+               /* check if this overrides a file and if the operator option is used */
+               if(overwrite_alert) {
+                       uiButSetFlag(but, UI_BUT_REDALERT);
+               }
+               
+               /* clear func */
+               uiBlockSetFunc(block, NULL, NULL, NULL);
        }
        
        /* Filename number increment / decrement buttons. */
index c77379b39a06e143ed71147c5c8e8477bc8b29b9..07a24454520d25d6e2c893809fe0a35701dc1a17 100644 (file)
@@ -46,6 +46,9 @@ void file_calc_previews(const bContext *C, ARegion *ar);
 void file_draw_previews(const bContext *C, ARegion *ar);
 void file_draw_list(const bContext *C, ARegion *ar);
 
+void file_draw_check_cb(bContext *C, void *arg1, void *arg2);
+int file_draw_check_exists(SpaceFile *sfile);
+
 /* file_ops.h */
 struct wmOperatorType;
 struct wmOperator;
@@ -84,6 +87,9 @@ int file_delete_exec(bContext *C, struct wmOperator *unused);
 
 int file_hilight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my);
 
+void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
+void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
+
 
 /* filesel.c */
 float file_string_width(const char* str);
index 2a50b505c57c8e7f6b840ca8a95a10550876e266..c3e9e22eaaddf32ac629f0f7c13b10ebd10378bc 100644 (file)
@@ -206,7 +206,11 @@ static FileSelect file_select(bContext* C, const rcti* rect, short selecting, sh
                        }
                        
                }       
-       } 
+       }
+       
+       /* update operator for name change event */
+       file_draw_check_cb(C, NULL, NULL);
+       
        return retval;
 }
 
@@ -541,6 +545,114 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
        ot->poll= file_operator_poll;
 }
 
+
+void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
+{
+       BLI_join_dirfile(filepath, sfile->params->dir, sfile->params->file);
+       if(RNA_struct_find_property(op->ptr, "relative_path")) {
+               if(RNA_boolean_get(op->ptr, "relative_path")) {
+                       BLI_path_rel(filepath, G.sce);
+               }
+       }
+
+       if(RNA_struct_find_property(op->ptr, "filename")) {
+               RNA_string_set(op->ptr, "filename", sfile->params->file);
+       }
+       if(RNA_struct_find_property(op->ptr, "directory")) {
+               RNA_string_set(op->ptr, "directory", sfile->params->dir);
+       }
+       if(RNA_struct_find_property(op->ptr, "filepath")) {
+               RNA_string_set(op->ptr, "filepath", filepath);
+       }
+       
+       /* some ops have multiple files to select */
+       {
+               PointerRNA itemptr;
+               int i, numfiles = filelist_numfiles(sfile->files);
+               struct direntry *file;
+               if(RNA_struct_find_property(op->ptr, "files")) {
+                       for (i=0; i<numfiles; i++) {
+                               file = filelist_file(sfile->files, i);
+                               if(file->flags & ACTIVEFILE) {
+                                       if ((file->type & S_IFDIR)==0) {
+                                               RNA_collection_add(op->ptr, "files", &itemptr);
+                                               RNA_string_set(&itemptr, "name", file->relname);
+                                       }
+                               }
+                       }
+               }
+               
+               if(RNA_struct_find_property(op->ptr, "dirs")) {
+                       for (i=0; i<numfiles; i++) {
+                               file = filelist_file(sfile->files, i);
+                               if(file->flags & ACTIVEFILE) {
+                                       if ((file->type & S_IFDIR)) {
+                                               RNA_collection_add(op->ptr, "dirs", &itemptr);
+                                               RNA_string_set(&itemptr, "name", file->relname);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
+{
+       int change= FALSE;
+       if(RNA_struct_find_property(op->ptr, "filename")) {
+               RNA_string_get(op->ptr, "filename", sfile->params->file);
+               change= TRUE;
+       }
+       if(RNA_struct_find_property(op->ptr, "directory")) {
+               RNA_string_get(op->ptr, "directory", sfile->params->dir);
+               change= TRUE;
+       }
+       
+       /* If neither of the above are set, split the filepath back */
+       if(RNA_struct_find_property(op->ptr, "filepath")) {
+               if(change==FALSE) {
+                       char filepath[FILE_MAX];
+                       RNA_string_get(op->ptr, "filepath", filepath);
+                       BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file);
+               }
+       }
+       
+       /* XXX, files and dirs updates missing, not really so important though */
+}
+
+void file_draw_check_cb(bContext *C, void *dummy1, void *dummy2)
+{
+       SpaceFile *sfile= CTX_wm_space_file(C);
+       wmOperator *op= sfile->op;
+       if(op->type->check) {
+               char filepath[FILE_MAX];
+               file_sfile_to_operator(op, sfile, filepath);
+               
+               /* redraw */
+               if(op->type->check(C, op)) {
+                       file_operator_to_sfile(sfile, op);
+
+                       /* redraw, else the changed settings wont get updated */
+                       ED_area_tag_redraw(CTX_wm_area(C));
+               }
+       }
+}
+
+int file_draw_check_exists(SpaceFile *sfile)
+{
+       if(RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
+               if(RNA_boolean_get(sfile->op->ptr, "check_existing")) {
+                       char filepath[FILE_MAX];
+                       BLI_join_dirfile(filepath, sfile->params->dir, sfile->params->file);
+                       if(BLI_exists(filepath) && !BLI_is_dir(filepath)) {
+                               return TRUE;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
 /* sends events now, so things get handled on windowqueue level */
 int file_exec(bContext *C, wmOperator *exec_op)
 {
@@ -568,53 +680,8 @@ int file_exec(bContext *C, wmOperator *exec_op)
                
                sfile->op = NULL;
 
-               BLI_join_dirfile(filepath, sfile->params->dir, sfile->params->file);
-               if(RNA_struct_find_property(op->ptr, "relative_path")) {
-                       if(RNA_boolean_get(op->ptr, "relative_path")) {
-                               BLI_path_rel(filepath, G.sce);
-                       }
-               }
+               file_sfile_to_operator(op, sfile, filepath);
 
-               if(RNA_struct_find_property(op->ptr, "filename")) {
-                       RNA_string_set(op->ptr, "filename", sfile->params->file);
-               }
-               if(RNA_struct_find_property(op->ptr, "directory")) {
-                       RNA_string_set(op->ptr, "directory", sfile->params->dir);
-               }
-               if(RNA_struct_find_property(op->ptr, "filepath")) {
-                       RNA_string_set(op->ptr, "filepath", filepath);
-               }
-               
-               /* some ops have multiple files to select */
-               {
-                       PointerRNA itemptr;
-                       int i, numfiles = filelist_numfiles(sfile->files);
-                       struct direntry *file;
-                       if(RNA_struct_find_property(op->ptr, "files")) {
-                               for (i=0; i<numfiles; i++) {
-                                       file = filelist_file(sfile->files, i);
-                                       if(file->flags & ACTIVEFILE) {
-                                               if ((file->type & S_IFDIR)==0) {
-                                                       RNA_collection_add(op->ptr, "files", &itemptr);
-                                                       RNA_string_set(&itemptr, "name", file->relname);
-                                               }
-                                       }
-                               }
-                       }
-                       
-                       if(RNA_struct_find_property(op->ptr, "dirs")) {
-                               for (i=0; i<numfiles; i++) {
-                                       file = filelist_file(sfile->files, i);
-                                       if(file->flags & ACTIVEFILE) {
-                                               if ((file->type & S_IFDIR)) {
-                                                       RNA_collection_add(op->ptr, "dirs", &itemptr);
-                                                       RNA_string_set(&itemptr, "name", file->relname);
-                                               }
-                                       }
-                               }
-                       }
-               }
-               
                folderlist_free(sfile->folders_prev);
                folderlist_free(sfile->folders_next);
 
index 4a505bc022f418f097743fa06d6b3782fa9ab449..33d740e18a66118def7eb125b6f4070e21098cc6 100644 (file)
@@ -170,7 +170,9 @@ static void file_panel_operator(const bContext *C, Panel *pa)
        SpaceFile *sfile= CTX_wm_space_file(C);
        wmOperator *op= sfile->op;
        int empty= 1, flag;
-
+       
+       uiBlockSetFunc(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
+       
        if(op->type->ui) {
                op->layout= pa->layout;
                op->type->ui((bContext*)C, op);
@@ -197,6 +199,8 @@ static void file_panel_operator(const bContext *C, Panel *pa)
                if(empty)
                        uiItemL(pa->layout, "No properties.", 0);
        }
+       
+       uiBlockSetFunc(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
 }
 
 void file_panels_register(ARegionType *art)
index 11b39af2e03e1e36f1d07e63ecdd4e1966d84c52..5a7e2e6fa1b746c20dcd197eaba1aaf03866b19c 100644 (file)
@@ -960,6 +960,18 @@ static int save_as_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
+
+static int save_as_check(bContext *C, wmOperator *op)
+{
+       char filepath[FILE_MAX];
+       RNA_string_get(op->ptr, "filepath", filepath);
+       if(BKE_add_image_extension(filepath, RNA_enum_get(op->ptr, "file_type"))) {
+               RNA_string_set(op->ptr, "filepath", filepath);
+               return TRUE;
+       }
+       return FALSE;
+}
+
 static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        SpaceImage *sima= CTX_wm_space_image(C);
@@ -1022,6 +1034,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= save_as_exec;
+       ot->check= save_as_check;
        ot->invoke= save_as_invoke;
        ot->poll= space_image_buffer_exists_poll;
 
index 900a1fd60cfce4669d9e5afaf91fc02ba43dc85d..62d0c99f6c58ca5c22efeee2b546a335b1c210bd 100644 (file)
@@ -697,7 +697,7 @@ static int operator_poll(bContext *C, wmOperatorType *ot)
        return visible;
 }
 
-static int operator_exec(bContext *C, wmOperator *op)
+static int operator_execute(bContext *C, wmOperator *op)
 {
        PointerRNA opr;
        ParameterList list;
@@ -720,6 +720,30 @@ static int operator_exec(bContext *C, wmOperator *op)
        return result;
 }
 
+/* same as execute() but no return value */
+static int operator_check(bContext *C, wmOperator *op)
+{
+       PointerRNA opr;
+       ParameterList list;
+       FunctionRNA *func;
+       void *ret;
+       int result;
+
+       RNA_pointer_create(&CTX_wm_screen(C)->id, op->type->ext.srna, op, &opr);
+       func= RNA_struct_find_function(&opr, "check");
+
+       RNA_parameter_list_create(&list, &opr, func);
+       RNA_parameter_set_lookup(&list, "context", &C);
+       op->type->ext.call(&opr, func, &list);
+
+       RNA_parameter_get_lookup(&list, "result", &ret);
+       result= *(int*)ret;
+
+       RNA_parameter_list_free(&list);
+
+       return result;
+}
+
 static int operator_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        PointerRNA opr;
@@ -796,7 +820,7 @@ static StructRNA *rna_Operator_register(const bContext *C, ReportList *reports,
        wmOperatorType dummyot = {0};
        wmOperator dummyop= {0};
        PointerRNA dummyotr;
-       int have_function[5];
+       int have_function[6];
 
        /* setup dummy operator & operator type to store static properties in */
        dummyop.type= &dummyot;
@@ -846,11 +870,11 @@ static StructRNA *rna_Operator_register(const bContext *C, ReportList *reports,
        dummyot.ext.free= free;
 
        dummyot.pyop_poll=      (have_function[0])? operator_poll: NULL;
-       dummyot.exec=           (have_function[1])? operator_exec: NULL;
-       dummyot.invoke=         (have_function[2])? operator_invoke: NULL;
-       dummyot.modal=          (have_function[3])? operator_modal: NULL;
-       dummyot.ui=                     (have_function[4])? operator_draw: NULL;
-
+       dummyot.exec=           (have_function[1])? operator_execute: NULL;
+       dummyot.check=          (have_function[2])? operator_check: NULL;
+       dummyot.invoke=         (have_function[3])? operator_invoke: NULL;
+       dummyot.modal=          (have_function[4])? operator_modal: NULL;
+       dummyot.ui=                     (have_function[5])? operator_draw: NULL;
        WM_operatortype_append_ptr(operator_wrapper, (void *)&dummyot);
 
        /* update while blender is running */
index b13d7627a34ef5684fe87954a36ebbeb64565ed8..36dd6efc2566d8e5a73bf9ca28ede7d5ea805540 100644 (file)
@@ -165,6 +165,15 @@ void RNA_api_operator(StructRNA *srna)
        RNA_def_property_flag(parm, PROP_ENUM_FLAG);
        RNA_def_function_return(func, parm);
 
+       /* check */
+       func= RNA_def_function(srna, "check", NULL);
+       RNA_def_function_ui_description(func, "Check the operator settings.");
+       RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+       RNA_def_pointer(func, "context", "Context", "", "");
+
+       parm= RNA_def_boolean(func, "result", 0, "result", ""); // better name?
+       RNA_def_function_return(func, parm);
+       
        /* invoke */
        func= RNA_def_function(srna, "invoke", NULL);
        RNA_def_function_ui_description(func, "Invoke the operator.");
index 807125765f78f21f3a30fa3a8a576c9496f15fa5..a732524ca0352b225bceac627edfa113fc53c944 100644 (file)
@@ -385,6 +385,12 @@ typedef struct wmOperatorType {
         * any interface code or input device state.
         * - see defines below for return values */
        int (*exec)(struct bContext *, struct wmOperator *);
+       
+       /* this callback executes on a running operator whenever as property
+        * is changed. It can correct its own properties or report errors for
+        * invalid settings in exceptional cases.
+        * Boolean return value, True denotes a change has been made and to redraw */
+       int (*check)(struct bContext *, struct wmOperator *);
 
        /* for modal temporary operators, initially invoke is called. then
         * any further events are handled in modal. if the operation is
index 6e8ab87f6405e49656eb903f7b97c43ddc683695..c32fb372ffd3b722305702dde074a0165d810599 100644 (file)
@@ -1241,6 +1241,8 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                /* needed for uiPupMenuReports */
 
                                if(event->val==EVT_FILESELECT_EXEC) {
+#if 0                          // use REDALERT now
+
                                        /* a bit weak, might become arg for WM_event_fileselect? */
                                        /* XXX also extension code in image-save doesnt work for this yet */
                                        if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 
@@ -1251,7 +1253,9 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                                if(path)
                                                        MEM_freeN(path);
                                        }
-                                       else {
+                                       else
+#endif
+                                       {
                                                int retval;
                                                
                                                if(handler->op->type->flag & OPTYPE_UNDO)
@@ -1820,6 +1824,12 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
        
        BLI_addhead(&win->modalhandlers, handler);
        
+       /* check props once before invoking if check is available
+        * ensures initial properties are valid */
+       if(op->type->check) {
+               op->type->check(C, op); /* ignore return value */
+       }
+
        WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
 }
 
index 95ab84c919222190a22dfc20a17afa2c6c341d28..b84b7eab55fb094c980ee3e4a1972129d77f490b 100644 (file)
@@ -928,6 +928,16 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
        uiPupBlockClose(C, block);
 }
 
+void dialog_check_cb(bContext *C, void *op_ptr, void *dummy2)
+{
+       wmOperator *op= op_ptr;
+       if(op->type->check) {
+               if(op->type->check(C, op)) {
+                       /* refresh */
+               }
+       }
+}
+
 /* Dialogs are popups that require user verification (click OK) before exec */
 static uiBlock *wm_block_create_dialog(bContext *C, ARegion *ar, void *userData)
 {
@@ -953,6 +963,8 @@ static uiBlock *wm_block_create_dialog(bContext *C, ARegion *ar, void *userData)
        RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
        layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, style);
        uiItemL(layout, op->type->name, 0);
+       
+       uiBlockSetFunc(block, dialog_check_cb, op, NULL);
 
        if (op->type->ui) {
                op->layout= layout;
@@ -961,6 +973,8 @@ static uiBlock *wm_block_create_dialog(bContext *C, ARegion *ar, void *userData)
        }
        else
                uiDefAutoButsRNA(C, layout, &ptr, columns);
+       
+       uiBlockSetFunc(block, NULL, NULL, NULL);
 
        /* Create OK button, the callback of which will execute op */
        btn= uiDefBut(block, BUT, 0, "OK", 0, 0, 0, 20, NULL, 0, 0, 0, 0, "");
@@ -1799,6 +1813,18 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
+/* function used for WM_OT_save_mainfile too */
+static int blend_save_check(bContext *C, wmOperator *op)
+{
+       char filepath[FILE_MAX];
+       RNA_string_get(op->ptr, "filepath", filepath);
+       if(BLI_replace_extension(filepath, sizeof(filepath), ".blend")) {
+               RNA_string_set(op->ptr, "filepath", filepath);
+               return TRUE;
+       }
+       return FALSE;
+}
+
 static void WM_OT_save_as_mainfile(wmOperatorType *ot)
 {
        ot->name= "Save As Blender File";
@@ -1807,6 +1833,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
        
        ot->invoke= wm_save_as_mainfile_invoke;
        ot->exec= wm_save_as_mainfile_exec;
+       ot->check= blend_save_check;
        ot->poll= WM_operator_winactive;
        
        WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
@@ -1857,6 +1884,7 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
        
        ot->invoke= wm_save_mainfile_invoke;
        ot->exec= wm_save_as_mainfile_exec;
+       ot->check= blend_save_check;
        ot->poll= NULL;
        
        WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
@@ -1872,9 +1900,10 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
 static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {      
        if(!RNA_property_is_set(op->ptr, "filepath")) {
-               char *path = BLI_replacestr(G.sce, ".blend", ".dae");
-               RNA_string_set(op->ptr, "filepath", path);
-               MEM_freeN(path);
+               char *filepath[FILE_MAX];
+               BLI_strncpy(filepath, G.sce, sizeof(filepath));
+               BLI_replace_extension(filepath, sizeof(filepath), ".dae");
+               RNA_string_set(op->ptr, "filepath", filepath);
        }
 
        WM_event_add_fileselect(C, op);