diff options
Diffstat (limited to 'release/scripts/startup/bl_operators/wm.py')
-rw-r--r-- | release/scripts/startup/bl_operators/wm.py | 657 |
1 files changed, 583 insertions, 74 deletions
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index fae38eb1cef..85e79914ce3 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -172,7 +172,7 @@ class BRUSH_OT_active_index_set(Operator): class WM_OT_context_set_boolean(Operator): - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_boolean" bl_label = "Context Set Boolean" bl_options = {'UNDO', 'INTERNAL'} @@ -188,7 +188,7 @@ class WM_OT_context_set_boolean(Operator): class WM_OT_context_set_int(Operator): # same as enum - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_int" bl_label = "Context Set" bl_options = {'UNDO', 'INTERNAL'} @@ -205,7 +205,7 @@ class WM_OT_context_set_int(Operator): # same as enum class WM_OT_context_scale_int(Operator): - '''Scale an int context value.''' + '''Scale an int context value''' bl_idname = "wm.context_scale_int" bl_label = "Context Set" bl_options = {'UNDO', 'INTERNAL'} @@ -248,7 +248,7 @@ class WM_OT_context_scale_int(Operator): class WM_OT_context_set_float(Operator): # same as enum - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_float" bl_label = "Context Set Float" bl_options = {'UNDO', 'INTERNAL'} @@ -265,7 +265,7 @@ class WM_OT_context_set_float(Operator): # same as enum class WM_OT_context_set_string(Operator): # same as enum - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_string" bl_label = "Context Set String" bl_options = {'UNDO', 'INTERNAL'} @@ -281,7 +281,7 @@ class WM_OT_context_set_string(Operator): # same as enum class WM_OT_context_set_enum(Operator): - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_enum" bl_label = "Context Set Enum" bl_options = {'UNDO', 'INTERNAL'} @@ -297,7 +297,7 @@ class WM_OT_context_set_enum(Operator): class WM_OT_context_set_value(Operator): - '''Set a context value.''' + '''Set a context value''' bl_idname = "wm.context_set_value" bl_label = "Context Set Value" bl_options = {'UNDO', 'INTERNAL'} @@ -318,7 +318,7 @@ class WM_OT_context_set_value(Operator): class WM_OT_context_toggle(Operator): - '''Toggle a context value.''' + '''Toggle a context value''' bl_idname = "wm.context_toggle" bl_label = "Context Toggle" bl_options = {'UNDO', 'INTERNAL'} @@ -337,7 +337,7 @@ class WM_OT_context_toggle(Operator): class WM_OT_context_toggle_enum(Operator): - '''Toggle a context value.''' + '''Toggle a context value''' bl_idname = "wm.context_toggle_enum" bl_label = "Context Toggle Values" bl_options = {'UNDO', 'INTERNAL'} @@ -371,7 +371,7 @@ class WM_OT_context_toggle_enum(Operator): class WM_OT_context_cycle_int(Operator): '''Set a context value. Useful for cycling active material, ''' - '''vertex keys, groups' etc.''' + '''vertex keys, groups' etc''' bl_idname = "wm.context_cycle_int" bl_label = "Context Int Cycle" bl_options = {'UNDO', 'INTERNAL'} @@ -405,7 +405,7 @@ class WM_OT_context_cycle_int(Operator): class WM_OT_context_cycle_enum(Operator): - '''Toggle a context value.''' + '''Toggle a context value''' bl_idname = "wm.context_cycle_enum" bl_label = "Context Enum Cycle" bl_options = {'UNDO', 'INTERNAL'} @@ -458,7 +458,7 @@ class WM_OT_context_cycle_enum(Operator): class WM_OT_context_cycle_array(Operator): '''Set a context array value. - Useful for cycling the active mesh edit mode.''' + Useful for cycling the active mesh edit mode''' bl_idname = "wm.context_cycle_array" bl_label = "Context Array Cycle" bl_options = {'UNDO', 'INTERNAL'} @@ -518,7 +518,7 @@ class WM_OT_context_menu_enum(Operator): class WM_OT_context_set_id(Operator): - '''Toggle a context value.''' + '''Toggle a context value''' bl_idname = "wm.context_set_id" bl_label = "Set Library ID" bl_options = {'UNDO', 'INTERNAL'} @@ -1144,67 +1144,6 @@ class WM_OT_sysinfo(Operator): return {'FINISHED'} -class WM_OT_get_messages(Operator): - bl_idname = "wm.get_messages" - bl_label = "Get Messages" - - def _putMessage(self, messages, msg): - if len(msg): - messages[msg] = True - - def _walkProperties(self, properties, messages): - for prop in properties: - self._putMessage(messages, prop.name) - self._putMessage(messages, prop.description) - - if isinstance(prop, bpy.types.EnumProperty): - for item in prop.enum_items: - self._putMessage(messages, item.name) - self._putMessage(messages, item.description) - - def _walkRNA(self, bl_rna, messages): - if bl_rna.name and bl_rna.name != bl_rna.identifier: - self._putMessage(messages, bl_rna.name) - - if bl_rna.description: - self._putMessage(messages, bl_rna.description) - - self._walkProperties(bl_rna.properties, messages) - - def _walkClass(self, cls, messages): - self._walkRNA(cls.bl_rna, messages) - - def _walk_keymap_hierarchy(self, hier, messages): - for lvl in hier: - self._putMessage(messages, lvl[0]) - - if lvl[3]: - self._walk_keymap_hierarchy(lvl[3], messages) - - def execute(self, context): - messages = {} - - for cls in type(bpy.context).__base__.__subclasses__(): - self._walkClass(cls, messages) - - for cls in bpy.types.Space.__subclasses__(): - self._walkClass(cls, messages) - - for cls in bpy.types.Operator.__subclasses__(): - self._walkClass(cls, messages) - - from bl_ui.space_userpref_keymap import KM_HIERARCHY - - self._walk_keymap_hierarchy(KM_HIERARCHY, messages) - - text = bpy.data.texts.new(name="messages.txt") - for message in messages: - text.write(message + "\n") - self._walkClass(bpy.types.SpaceDopeSheetEditor, messages) - - return {'FINISHED'} - - class WM_OT_copy_prev_settings(Operator): '''Copy settings from previous version''' bl_idname = "wm.copy_prev_settings" @@ -1240,3 +1179,573 @@ class WM_OT_copy_prev_settings(Operator): return {'FINISHED'} return {'CANCELLED'} + + +class WM_OT_keyconfig_test(Operator): + "Test keyconfig for conflicts" + bl_idname = "wm.keyconfig_test" + bl_label = "Test Key Configuration for Conflicts" + + def execute(self, context): + from bpy_extras import keyconfig_utils + + wm = context.window_manager + kc = wm.keyconfigs.default + + if keyconfig_utils.keyconfig_test(kc): + print("CONFLICT") + + return {'FINISHED'} + + +class WM_OT_keyconfig_import(Operator): + "Import key configuration from a python script" + bl_idname = "wm.keyconfig_import" + bl_label = "Import Key Configuration..." + + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + keep_original = BoolProperty( + name="Keep original", + description="Keep original file after copying to configuration folder", + default=True, + ) + + def execute(self, context): + import os + from os.path import basename + import shutil + + if not self.filepath: + self.report({'ERROR'}, "Filepath not set") + return {'CANCELLED'} + + config_name = basename(self.filepath) + + path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", "keyconfig"), create=True) + path = os.path.join(path, config_name) + + try: + if self.keep_original: + shutil.copy(self.filepath, path) + else: + shutil.move(self.filepath, path) + except Exception as e: + self.report({'ERROR'}, "Installing keymap failed: %s" % e) + return {'CANCELLED'} + + # sneaky way to check we're actually running the code. + bpy.utils.keyconfig_set(path) + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + +# This operator is also used by interaction presets saving - AddPresetBase + + +class WM_OT_keyconfig_export(Operator): + "Export key configuration to a python script" + bl_idname = "wm.keyconfig_export" + bl_label = "Export Key Configuration..." + + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + + def execute(self, context): + from bpy_extras import keyconfig_utils + + if not self.filepath: + raise Exception("Filepath not set") + + if not self.filepath.endswith('.py'): + self.filepath += '.py' + + wm = context.window_manager + + keyconfig_utils.keyconfig_export(wm, + wm.keyconfigs.active, + self.filepath, + ) + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_keymap_restore(Operator): + "Restore key map(s)" + bl_idname = "wm.keymap_restore" + bl_label = "Restore Key Map(s)" + + all = BoolProperty( + name="All Keymaps", + description="Restore all keymaps to default", + ) + + def execute(self, context): + wm = context.window_manager + + if self.all: + for km in wm.keyconfigs.user.keymaps: + km.restore_to_default() + else: + km = context.keymap + km.restore_to_default() + + return {'FINISHED'} + + +class WM_OT_keyitem_restore(Operator): + "Restore key map item" + bl_idname = "wm.keyitem_restore" + bl_label = "Restore Key Map Item" + + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + keymap = getattr(context, "keymap", None) + return keymap + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + + if (not kmi.is_user_defined) and kmi.is_user_modified: + km.restore_item_to_default(kmi) + + return {'FINISHED'} + + +class WM_OT_keyitem_add(Operator): + "Add key map item" + bl_idname = "wm.keyitem_add" + bl_label = "Add Key Map Item" + + def execute(self, context): + km = context.keymap + + if km.is_modal: + km.keymap_items.new_modal("", 'A', 'PRESS') # kmi + else: + km.keymap_items.new("none", 'A', 'PRESS') # kmi + + # clear filter and expand keymap so we can see the newly added item + if context.space_data.filter_text != "": + context.space_data.filter_text = "" + km.show_expanded_items = True + km.show_expanded_children = True + + return {'FINISHED'} + + +class WM_OT_keyitem_remove(Operator): + "Remove key map item" + bl_idname = "wm.keyitem_remove" + bl_label = "Remove Key Map Item" + + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.remove(kmi) + return {'FINISHED'} + + +class WM_OT_keyconfig_remove(Operator): + "Remove key config" + bl_idname = "wm.keyconfig_remove" + bl_label = "Remove Key Config" + + @classmethod + def poll(cls, context): + wm = context.window_manager + keyconf = wm.keyconfigs.active + return keyconf and keyconf.is_user_defined + + def execute(self, context): + wm = context.window_manager + keyconfig = wm.keyconfigs.active + wm.keyconfigs.remove(keyconfig) + return {'FINISHED'} + + +class WM_OT_operator_cheat_sheet(Operator): + bl_idname = "wm.operator_cheat_sheet" + bl_label = "Operator Cheat Sheet" + + def execute(self, context): + op_strings = [] + tot = 0 + for op_module_name in dir(bpy.ops): + op_module = getattr(bpy.ops, op_module_name) + for op_submodule_name in dir(op_module): + op = getattr(op_module, op_submodule_name) + text = repr(op) + if text.split("\n")[-1].startswith('bpy.ops.'): + op_strings.append(text) + tot += 1 + + op_strings.append('') + + textblock = bpy.data.texts.new("OperatorList.txt") + textblock.write('# %d Operators\n\n' % tot) + textblock.write('\n'.join(op_strings)) + self.report({'INFO'}, "See OperatorList.txt textblock") + return {'FINISHED'} + + +class WM_OT_addon_enable(Operator): + "Enable an addon" + bl_idname = "wm.addon_enable" + bl_label = "Enable Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to enable", + ) + + def execute(self, context): + import addon_utils + + mod = addon_utils.enable(self.module) + + if mod: + info = addon_utils.module_bl_info(mod) + + info_ver = info.get("blender", (0, 0, 0)) + + if info_ver > bpy.app.version: + self.report({'WARNING'}, ("This script was written Blender " + "version %d.%d.%d and might not " + "function (correctly), " + "though it is enabled") % + info_ver) + return {'FINISHED'} + else: + return {'CANCELLED'} + + +class WM_OT_addon_disable(Operator): + "Disable an addon" + bl_idname = "wm.addon_disable" + bl_label = "Disable Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to disable", + ) + + def execute(self, context): + import addon_utils + + addon_utils.disable(self.module) + return {'FINISHED'} + + +class WM_OT_addon_install(Operator): + "Install an addon" + bl_idname = "wm.addon_install" + bl_label = "Install Add-On..." + + overwrite = BoolProperty( + name="Overwrite", + description="Remove existing addons with the same ID", + default=True, + ) + target = EnumProperty( + name="Target Path", + items=(('DEFAULT', "Default", ""), + ('PREFS', "User Prefs", "")), + ) + + filepath = StringProperty( + name="File Path", + description="File path to write file to", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + filter_glob = StringProperty( + default="*.py;*.zip", + options={'HIDDEN'}, + ) + + @staticmethod + def _module_remove(path_addons, module): + import os + module = os.path.splitext(module)[0] + for f in os.listdir(path_addons): + f_base = os.path.splitext(f)[0] + if f_base == module: + f_full = os.path.join(path_addons, f) + + if os.path.isdir(f_full): + os.rmdir(f_full) + else: + os.remove(f_full) + + def execute(self, context): + import addon_utils + import traceback + import zipfile + import shutil + import os + + pyfile = self.filepath + + if self.target == 'DEFAULT': + # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. + path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) + else: + path_addons = bpy.context.user_preferences.filepaths.script_directory + if path_addons: + path_addons = os.path.join(path_addons, "addons") + + if not path_addons: + self.report({'ERROR'}, "Failed to get addons path") + return {'CANCELLED'} + + # create dir is if missing. + if not os.path.exists(path_addons): + os.makedirs(path_addons) + + # Check if we are installing from a target path, + # doing so causes 2+ addons of same name or when the same from/to + # location is used, removal of the file! + addon_path = "" + pyfile_dir = os.path.dirname(pyfile) + for addon_path in addon_utils.paths(): + if os.path.samefile(pyfile_dir, addon_path): + self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path) + return {'CANCELLED'} + del addon_path + del pyfile_dir + # done checking for exceptional case + + addons_old = {mod.__name__ for mod in addon_utils.modules(addon_utils.addons_fake_modules)} + + #check to see if the file is in compressed format (.zip) + if zipfile.is_zipfile(pyfile): + try: + file_to_extract = zipfile.ZipFile(pyfile, 'r') + except: + traceback.print_exc() + return {'CANCELLED'} + + if self.overwrite: + for f in file_to_extract.namelist(): + WM_OT_addon_install._module_remove(path_addons, f) + else: + for f in file_to_extract.namelist(): + path_dest = os.path.join(path_addons, os.path.basename(f)) + if os.path.exists(path_dest): + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) + return {'CANCELLED'} + + try: # extract the file to "addons" + file_to_extract.extractall(path_addons) + + # zip files can create this dir with metadata, don't need it + macosx_dir = os.path.join(path_addons, '__MACOSX') + if os.path.isdir(macosx_dir): + shutil.rmtree(macosx_dir) + + except: + traceback.print_exc() + return {'CANCELLED'} + + else: + path_dest = os.path.join(path_addons, os.path.basename(pyfile)) + + if self.overwrite: + WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) + elif os.path.exists(path_dest): + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) + return {'CANCELLED'} + + #if not compressed file just copy into the addon path + try: + shutil.copyfile(pyfile, path_dest) + + except: + traceback.print_exc() + return {'CANCELLED'} + + addons_new = {mod.__name__ for mod in addon_utils.modules(addon_utils.addons_fake_modules)} - addons_old + addons_new.discard("modules") + + # disable any addons we may have enabled previously and removed. + # this is unlikely but do just incase. bug [#23978] + for new_addon in addons_new: + addon_utils.disable(new_addon) + + # possible the zip contains multiple addons, we could disallow this + # but for now just use the first + for mod in addon_utils.modules(addon_utils.addons_fake_modules): + if mod.__name__ in addons_new: + info = addon_utils.module_bl_info(mod) + + # show the newly installed addon. + context.window_manager.addon_filter = 'All' + context.window_manager.addon_search = info["name"] + break + + # incase a new module path was created to install this addon. + bpy.utils.refresh_script_paths() + + # TODO, should not be a warning. + # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_addon_remove(Operator): + "Disable an addon" + bl_idname = "wm.addon_remove" + bl_label = "Remove Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to remove", + ) + + @staticmethod + def path_from_addon(module): + import os + import addon_utils + + for mod in addon_utils.modules(addon_utils.addons_fake_modules): + if mod.__name__ == module: + filepath = mod.__file__ + if os.path.exists(filepath): + if os.path.splitext(os.path.basename(filepath))[0] == "__init__": + return os.path.dirname(filepath), True + else: + return filepath, False + return None, False + + def execute(self, context): + import addon_utils + import os + + path, isdir = WM_OT_addon_remove.path_from_addon(self.module) + if path is None: + self.report('WARNING', "Addon path %r could not be found" % path) + return {'CANCELLED'} + + # incase its enabled + addon_utils.disable(self.module) + + import shutil + if isdir: + shutil.rmtree(path) + else: + os.remove(path) + + context.area.tag_redraw() + return {'FINISHED'} + + # lame confirmation check + def draw(self, context): + self.layout.label(text="Remove Addon: %r?" % self.module) + path, isdir = WM_OT_addon_remove.path_from_addon(self.module) + self.layout.label(text="Path: %r" % path) + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self, width=600) + + +class WM_OT_addon_expand(Operator): + "Display more information on this add-on" + bl_idname = "wm.addon_expand" + bl_label = "" + + module = StringProperty( + name="Module", + description="Module name of the addon to expand", + ) + + def execute(self, context): + import addon_utils + + module_name = self.module + + # unlikely to fail, module should have already been imported + try: + # mod = __import__(module_name) + mod = addon_utils.addons_fake_modules.get(module_name) + except: + import traceback + traceback.print_exc() + return {'CANCELLED'} + + info = addon_utils.module_bl_info(mod) + info["show_expanded"] = not info["show_expanded"] + return {'FINISHED'} |