Keyconfig import and remove
authorMartin Poirier <theeth@yahoo.com>
Thu, 28 Jan 2010 19:54:06 +0000 (19:54 +0000)
committerMartin Poirier <theeth@yahoo.com>
Thu, 28 Jan 2010 19:54:06 +0000 (19:54 +0000)
- Keyconfig are now marked as user_defined when it is the case
- Import keyconfig operator: select an exported keyconfig .py file, copies it to the scripts folder (keep the original copy if wanted, default True), imports and select as active config. The active keyconfig is stored in the user default file, so that still has to be saved after import.
- Remove keyconfig operator and button next to the keyconfig name (poll False if not user_defined). Removes the keyconfig from the list and deletes the file from the folder.

Remaining bug: The file is copied in the user defined script folder (if present) or the /scripts/ui folder. The problem is that it might be imported before operators defined in python are imported themselves. One solution would be to use a separate folder for keyconfigs that is imported after all others.

release/scripts/ui/space_userpref.py
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_keymap.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index a8b49cafc473a23ea899dcaa1426cd946d8fe7f9..52b8d6583eabda706630a70ad648cec034d6b95a 100644 (file)
@@ -18,7 +18,7 @@
 
 # <pep8 compliant>
 import bpy
-import os.path
+import os, re, shutil
 
 # General UI Theme Settings (User Interface)
 def ui_items_general(col, context):
@@ -164,6 +164,8 @@ class USERPREF_HT_header(bpy.types.Header):
             layout.operator_context = 'INVOKE_DEFAULT'
             op = layout.operator("wm.keyconfig_export", "Export Key Configuration...")
             op.path = "keymap.py"
+            op = layout.operator("wm.keyconfig_import", "Import Key Configuration...")
+            op.path = "keymap.py"
 
 
 class USERPREF_PT_tabs(bpy.types.Panel):
@@ -1306,10 +1308,13 @@ class USERPREF_PT_input(bpy.types.Panel):
 
         subsplit = sub.split()
         subcol = subsplit.column()
-        subcol.prop_object(wm, "active_keyconfig", wm, "keyconfigs", text="Configuration:")
+        row = subcol.row()
+        row.prop_object(wm, "active_keyconfig", wm, "keyconfigs", text="Configuration:")
 
-        subcol = subsplit.column()
-        subcol.prop(kc, "filter", icon="VIEWZOOM")
+        layout.set_context_pointer("keyconfig", wm.active_keyconfig) 
+        row.operator("wm.keyconfig_remove", text="", icon='X')
+
+        row.prop(kc, "filter", icon="VIEWZOOM")
 
         col.separator()
 
@@ -1465,7 +1470,62 @@ def _string_value(value):
 
     return result
 
+class WM_OT_keyconfig_import(bpy.types.Operator):
+    "Import key configuration from a python script."
+    bl_idname = "wm.keyconfig_import"
+    bl_label = "Import Key Configuration..."
+
+    path = bpy.props.StringProperty(name="File Path", description="File path to write file to.")
+    filename = bpy.props.StringProperty(name="File Name", description="Name of the file.")
+    directory = bpy.props.StringProperty(name="Directory", description="Directory of the file.")
+    filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, hidden=True)
+    filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, hidden=True)
+    filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, hidden=True)
+
+    keep_original = bpy.props.BoolProperty(name="Keep original", description="Keep original file after copying to configuration folder", default=True)
+
+    def execute(self, context):
+        if not self.properties.path:
+            raise Exception("File path not set.")
+
+        f = open(self.properties.path, "r")
+        if not f:
+            raise Exception("Could not open file.")
+
+        name_pattern = re.compile("^kc = wm.add_keyconfig\('(.*)'\)$")
+
+        for line in f.readlines():
+            match = name_pattern.match(line)
+            
+            if match:
+                config_name = match.groups()[0]
+        
+        f.close()
+        
+        path = bpy.context.user_preferences.filepaths.python_scripts_directory
+        
+        if not path:
+            path = os.path.split(__file__)[0]
+            
+        path += os.path.sep + config_name + ".py"
+            
+        if self.properties.keep_original:
+            shutil.copy(self.properties.path, path)
+        else:
+            shutil.move(self.properties.path, path)
+        
+        __import__(config_name) 
+        
+        wm = bpy.data.window_managers[0]
+        wm.active_keyconfig = wm.keyconfigs[config_name]
+
+        return {'FINISHED'}
 
+    def invoke(self, context, event):
+        wm = context.manager
+        wm.add_fileselect(self)
+        return {'RUNNING_MODAL'}
+    
 class WM_OT_keyconfig_export(bpy.types.Operator):
     "Export key configuration to a python script."
     bl_idname = "wm.keyconfig_export"
@@ -1474,9 +1534,9 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
     path = bpy.props.StringProperty(name="File Path", description="File path to write file to.")
     filename = bpy.props.StringProperty(name="File Name", description="Name of the file.")
     directory = bpy.props.StringProperty(name="Directory", description="Directory of the file.")
-    filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True)
-    filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True)
-    filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True)
+    filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, hidden=True)
+    filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, hidden=True)
+    filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, hidden=True)
 
     def execute(self, context):
         if not self.properties.path:
@@ -1494,20 +1554,21 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
         else:
             name = kc.name
 
-        f.write('# Configuration %s\n' % name)
+        f.write("# Configuration %s\n" % name)
 
+        f.write("import bpy\n\n")
         f.write("wm = bpy.data.window_managers[0]\n")
-        f.write("kc = wm.add_keyconfig(\'%s\')\n\n" % name)
+        f.write("kc = wm.add_keyconfig('%s')\n\n" % name)
 
         for km in kc.keymaps:
             km = km.active()
             f.write("# Map %s\n" % km.name)
-            f.write("km = kc.add_keymap(\'%s\', space_type=\'%s\', region_type=\'%s\', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.modal))
+            f.write("km = kc.add_keymap('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.modal))
             for kmi in km.items:
                 if km.modal:
-                    f.write("kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value))
+                    f.write("kmi = km.add_modal_item('%s', '%s', '%s'" % (kmi.propvalue, kmi.type, kmi.value))
                 else:
-                    f.write("kmi = km.add_item(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value))
+                    f.write("kmi = km.add_item('%s', '%s', '%s'" % (kmi.idname, kmi.type, kmi.value))
                 if kmi.any:
                     f.write(", any=True")
                 else:
@@ -1520,7 +1581,7 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
                     if kmi.oskey:
                         f.write(", oskey=True")
                 if kmi.key_modifier and kmi.key_modifier != 'NONE':
-                    f.write(", key_modifier=\'%s\'" % kmi.key_modifier)
+                    f.write(", key_modifier='%s'" % kmi.key_modifier)
                 f.write(")\n")
 
                 def export_properties(prefix, properties):
@@ -1541,7 +1602,6 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
 
             f.write("\n")
 
-        f.write("wm.active_keyconfig = wm.keyconfigs[\'%s\']\n" % name)
         f.close()
 
         return {'FINISHED'}
@@ -1640,8 +1700,31 @@ class WM_OT_keyitem_remove(bpy.types.Operator):
         km.remove_item(kmi)
         return {'FINISHED'}
 
+class WM_OT_keyconfig_remove(bpy.types.Operator):
+    "Remove key config."
+    bl_idname = "wm.keyconfig_remove"
+    bl_label = "Remove Key Config"
+
+    def poll(self, context):
+        wm = context.manager
+        return wm.active_keyconfig.user_defined
+
+    def execute(self, context):
+        wm = context.manager
+        
+        keyconfig = wm.active_keyconfig
+        
+        module = __import__(keyconfig.name)
+        
+        os.remove(module.__file__)
+        
+        wm.remove_keyconfig(keyconfig)
+        return {'FINISHED'}
+
 bpy.types.register(WM_OT_keyconfig_export)
+bpy.types.register(WM_OT_keyconfig_import)
 bpy.types.register(WM_OT_keyconfig_test)
+bpy.types.register(WM_OT_keyconfig_remove)
 bpy.types.register(WM_OT_keymap_edit)
 bpy.types.register(WM_OT_keymap_restore)
 bpy.types.register(WM_OT_keyitem_add)
index 8e1042f3e120e74c30567f90616927555c2ecee8..4a7080034ee82d293ff79b03533c1cd089eed433 100644 (file)
@@ -259,9 +259,7 @@ typedef struct wmKeyConfig {
 } wmKeyConfig;
 
 /* wmKeyConfig.flag */
-#define KEYCONF_TWOBUTTONMOUSE (1 << 1)
-#define KEYCONF_LMOUSESELECT   (1 << 2)
-#define KEYCONF_NONUMPAD               (1 << 3)
+#define KEYCONF_USER                   (1 << 1)
 
 /* this one is the operator itself, stored in files for macros etc */
 /* operator + operatortype should be able to redo entirely, but for different contextes */
index 9c52e2cb9e94d0a27440538361c303dbe609a263..a44816a558539bc162ad8e4a484117e380c77dfb 100644 (file)
@@ -1185,6 +1185,11 @@ static void rna_def_keyconfig(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "KeyMap");
        RNA_def_property_ui_text(prop, "Key Maps", "Key maps configured as part of this configuration.");
 
+       prop= RNA_def_property(srna, "user_defined", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYCONF_USER);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "User Defined", "Indicates that a keyconfig was defined by the user.");
+
        RNA_api_keyconfig(srna);
 
        /* KeyMap */
index 3fa646598d60e406b7af04dc11deeb1c224f325e..9759e72165abb44bafabf605519eb9b256cdf711 100644 (file)
@@ -182,12 +182,16 @@ void RNA_api_wm(StructRNA *srna)
        RNA_def_function_ui_description(func, "Show up the file selector.");
        rna_generic_op_invoke(func, 0, 0);
 
-       func= RNA_def_function(srna, "add_keyconfig", "WM_keyconfig_add");
+       func= RNA_def_function(srna, "add_keyconfig", "WM_keyconfig_add_user");
        parm= RNA_def_string(func, "name", "", 0, "Name", "");
        RNA_def_property_flag(parm, PROP_REQUIRED);
        parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration.");
        RNA_def_function_return(func, parm);
        
+       func= RNA_def_function(srna, "remove_keyconfig", "WM_keyconfig_remove");
+       parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
        /* invoke functions, for use with python */
        func= RNA_def_function(srna, "invoke_props_popup", "WM_operator_props_popup");
        RNA_def_function_ui_description(func, "Operator popup invoke.");
index 2b0b5fa612dfa2ac38c5602adfa65f89b49301dd..e7521db462d1183834c2a417def5286b26bb5c51 100644 (file)
@@ -97,6 +97,8 @@ void          WM_cursor_warp          (struct wmWindow *win, int x, int y);
 
                        /* keyconfig and keymap */
 wmKeyConfig *WM_keyconfig_add  (struct wmWindowManager *wm, char *idname);
+wmKeyConfig *WM_keyconfig_add_user(struct wmWindowManager *wm, char *idname);
+void           WM_keyconfig_remove     (struct wmWindowManager *wm, struct wmKeyConfig *keyconf);
 void           WM_keyconfig_free       (struct wmKeyConfig *keyconf);
 void           WM_keyconfig_userdef(struct wmWindowManager *wm);
 
index 7f0f355403d9bf68c844c4a45562dde3dbc59023..4dbc17300334277c3685cae504c3b3b31b21d848 100644 (file)
@@ -85,6 +85,27 @@ wmKeyConfig *WM_keyconfig_add(wmWindowManager *wm, char *idname)
        return keyconf;
 }
 
+wmKeyConfig *WM_keyconfig_add_user(wmWindowManager *wm, char *idname)
+{
+       wmKeyConfig *keyconf = WM_keyconfig_add(wm, idname);
+
+       keyconf->flag |= KEYCONF_USER;
+
+       return keyconf;
+}
+
+void WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
+{
+       if (keyconf) {
+               if (BLI_streq(U.keyconfigstr, keyconf->idname)) {
+                       BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
+               }
+
+               BLI_remlink(&wm->keyconfigs, keyconf);
+               WM_keyconfig_free(keyconf);
+       }
+}
+
 void WM_keyconfig_free(wmKeyConfig *keyconf)
 {
        wmKeyMap *km;
index cb5cd7bf2841276d109b8506864987c72f365985..546ebc6d51e6e32f623fbc24887ec6433d6cab9f 100644 (file)
@@ -114,6 +114,8 @@ struct wmKeyMap *WM_keymap_add_item(struct wmKeyMap *keymap, char *idname, int t
 struct wmKeyMap *WM_keymap_copy_to_user(struct wmKeyMap *kemap){return (struct wmKeyMap *) NULL;} 
 struct wmKeyMap *WM_keymap_list_find(struct ListBase *lb, char *idname, int spaceid, int regionid){return (struct wmKeyMap *) NULL;}
 struct wmKeyConfig *WM_keyconfig_add(struct wmWindowManager *wm, char *idname){return (struct wmKeyConfig *) NULL;}
+struct wmKeyConfig *WM_keyconfig_add_user(struct wmWindowManager *wm, char *idname){return (struct wmKeyConfig *) NULL;}
+void WM_keyconfig_remove(struct wmWindowManager *wm, char *idname){}
 void WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi){}
 void WM_keymap_restore_to_default(struct wmKeyMap *keymap){}
 void WM_keymap_restore_item_to_default(struct bContext *C, struct wmKeyMap *keymap, struct wmKeyMapItem *kmi){}