Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2019-09-02 14:31:44 +0300
committermeta-androcto <meta.androcto1@gmail.com>2019-09-02 14:31:44 +0300
commite529809cf6513748776a878338109ecf960d1326 (patch)
tree779c76d1ab3c91235a1ca7ad32aff8bc08d2086b
parent6ed2b0e2b5b30d88b2dc10ac4c399837111e2ffc (diff)
development_edit_operator: returned to release: T63750 c983a2472846 T68541
-rw-r--r--development_edit_operator.py337
1 files changed, 337 insertions, 0 deletions
diff --git a/development_edit_operator.py b/development_edit_operator.py
new file mode 100644
index 00000000..08e91d87
--- /dev/null
+++ b/development_edit_operator.py
@@ -0,0 +1,337 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+bl_info = {
+ "name": "Edit Operator Source",
+ "author": "scorpion81",
+ "version": (1, 2, 2),
+ "blender": (2, 80, 0),
+ "location": "Text Editor > Edit > Edit Operator",
+ "description": "Opens source file of chosen operator or call locations, if source not available",
+ "warning": "",
+ "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
+ "Py/Scripts/Development/Edit_Operator_Source",
+ "category": "Development"}
+
+import bpy
+import sys
+import os
+import inspect
+from bpy.types import (
+ Operator,
+ Panel,
+ Header,
+ Menu,
+ PropertyGroup
+ )
+from bpy.props import (
+ EnumProperty,
+ StringProperty,
+ IntProperty
+ )
+
+def stdlib_excludes():
+ #need a handy list of modules to avoid walking into
+ import distutils.sysconfig as sysconfig
+ excludes = []
+ std_lib = sysconfig.get_python_lib(standard_lib=True)
+ for top, dirs, files in os.walk(std_lib):
+ for nm in files:
+ if nm != '__init__.py' and nm[-3:] == '.py':
+ excludes.append(os.path.join(top, nm)[len(std_lib)+1:-3].replace('\\','.'))
+
+ return excludes
+
+def make_loc(prefix, c):
+ #too long and not helpful... omitting for now
+ space = ""
+ #if hasattr(c, "bl_space_type"):
+ # space = c.bl_space_type
+
+ region = ""
+ #if hasattr(c, "bl_region_type"):
+ # region = c.bl_region_type
+
+ label = ""
+ if hasattr(c, "bl_label"):
+ label = c.bl_label
+
+ return prefix+": " + space + " " + region + " " + label
+
+def walk_module(opname, mod, calls=[], exclude=[]):
+
+ for name, m in inspect.getmembers(mod):
+ if inspect.ismodule(m):
+ if m.__name__ not in exclude:
+ #print(name, m.__name__)
+ walk_module(opname, m, calls, exclude)
+ elif inspect.isclass(m):
+ if (issubclass(m, Panel) or \
+ issubclass(m, Header) or \
+ issubclass(m, Menu)) and mod.__name__ != "bl_ui":
+ if hasattr(m, "draw"):
+ loc = ""
+ file = ""
+ line = -1
+ src, n = inspect.getsourcelines(m.draw)
+ for i, s in enumerate(src):
+ if opname in s:
+ file = mod.__file__
+ line = n + i
+
+ if issubclass(m, Panel) and name != "Panel":
+ loc = make_loc("Panel", m)
+ calls.append([opname, loc, file, line])
+ if issubclass(m, Header) and name != "Header":
+ loc = make_loc("Header", m)
+ calls.append([opname, loc, file, line])
+ if issubclass(m, Menu) and name != "Menu":
+ loc = make_loc("Menu", m)
+ calls.append([opname, loc, file, line])
+
+
+def getclazz(opname):
+ opid = opname.split(".")
+ opmod = getattr(bpy.ops, opid[0])
+ op = getattr(opmod, opid[1])
+ id = op.get_rna_type().bl_rna.identifier
+ try:
+ clazz = getattr(bpy.types, id)
+ return clazz
+ except AttributeError:
+ return None
+
+
+def getmodule(opname):
+ addon = True
+ clazz = getclazz(opname)
+
+ if clazz is None:
+ return "", -1, False
+
+ modn = clazz.__module__
+
+ try:
+ line = inspect.getsourcelines(clazz)[1]
+ except IOError:
+ line = -1
+ except TypeError:
+ line = -1
+
+ if modn == 'bpy.types':
+ mod = 'C operator'
+ addon = False
+ elif modn != '__main__':
+ mod = sys.modules[modn].__file__
+ else:
+ addon = False
+ mod = modn
+
+ return mod, line, addon
+
+
+def get_ops():
+ allops = []
+ opsdir = dir(bpy.ops)
+ for opmodname in opsdir:
+ opmod = getattr(bpy.ops, opmodname)
+ opmoddir = dir(opmod)
+ for o in opmoddir:
+ name = opmodname + "." + o
+ clazz = getclazz(name)
+ #if (clazz is not None) :# and clazz.__module__ != 'bpy.types'):
+ allops.append(name)
+ del opmoddir
+
+ # add own operator name too, since its not loaded yet when this is called
+ allops.append("text.edit_operator")
+ l = sorted(allops)
+ del allops
+ del opsdir
+
+ return [(y, y, "", x) for x, y in enumerate(l)]
+
+class OperatorEntry(PropertyGroup):
+
+ label : StringProperty(
+ name="Label",
+ description="",
+ default=""
+ )
+
+ path : StringProperty(
+ name="Path",
+ description="",
+ default=""
+ )
+
+ line : IntProperty(
+ name="Line",
+ description="",
+ default=-1
+ )
+
+class TEXT_OT_EditOperator(Operator):
+ bl_idname = "text.edit_operator"
+ bl_label = "Edit Operator"
+ bl_description = "Opens the source file of operators chosen from Menu"
+ bl_property = "op"
+
+ items = get_ops()
+
+ op : EnumProperty(
+ name="Op",
+ description="",
+ items=items
+ )
+
+ path : StringProperty(
+ name="Path",
+ description="",
+ default=""
+ )
+
+ line : IntProperty(
+ name="Line",
+ description="",
+ default=-1
+ )
+
+ def show_text(self, context, path, line):
+ found = False
+
+ for t in bpy.data.texts:
+ if t.filepath == path:
+ #switch to the wanted text first
+ context.space_data.text = t
+ ctx = context.copy()
+ ctx['edit_text'] = t
+ bpy.ops.text.jump(ctx, line=line)
+ found = True
+ break
+
+ if (found is False):
+ self.report({'INFO'},
+ "Opened file: " + path)
+ bpy.ops.text.open(filepath=path)
+ bpy.ops.text.jump(line=line)
+
+ def show_calls(self, context):
+ import bl_ui
+ import addon_utils
+
+ exclude = stdlib_excludes()
+ exclude.append("bpy")
+ exclude.append("sys")
+
+ calls = []
+ walk_module(self.op, bl_ui, calls, exclude)
+
+ for m in addon_utils.modules():
+ try:
+ mod = sys.modules[m.__name__]
+ walk_module(self.op, mod, calls, exclude)
+ except KeyError:
+ continue
+
+ for c in calls:
+ cl = context.scene.calls.add()
+ cl.name = c[0]
+ cl.label = c[1]
+ cl.path = c[2]
+ cl.line = c[3]
+
+ def invoke(self, context, event):
+ context.window_manager.invoke_search_popup(self)
+ return {'PASS_THROUGH'}
+
+ def execute(self, context):
+ if self.path != "" and self.line != -1:
+ #invocation of one of the "found" locations
+ self.show_text(context, self.path, self.line)
+ return {'FINISHED'}
+ else:
+ context.scene.calls.clear()
+ path, line, addon = getmodule(self.op)
+
+ if addon:
+ self.show_text(context, path, line)
+
+ #add convenient "source" button, to toggle back from calls to source
+ c = context.scene.calls.add()
+ c.name = self.op
+ c.label = "Source"
+ c.path = path
+ c.line = line
+
+ self.show_calls(context)
+ context.area.tag_redraw()
+
+ return {'FINISHED'}
+ else:
+
+ self.report({'WARNING'},
+ "Found no source file for " + self.op)
+
+ self.show_calls(context)
+ context.area.tag_redraw()
+
+ return {'FINISHED'}
+
+
+class TEXT_PT_EditOperatorPanel(Panel):
+ bl_space_type = 'TEXT_EDITOR'
+ bl_region_type = 'UI'
+ bl_label = "Edit Operator"
+ bl_category = "Text"
+
+ def draw(self, context):
+ layout = self.layout
+ op = layout.operator("text.edit_operator")
+ op.path = ""
+ op.line = -1
+
+ if len(context.scene.calls) > 0:
+ box = layout.box()
+ box.label(text="Calls of: " + context.scene.calls[0].name)
+ box.operator_context = 'EXEC_DEFAULT'
+ for c in context.scene.calls:
+ op = box.operator("text.edit_operator", text=c.label)
+ op.path = c.path
+ op.line = c.line
+ op.op = c.name
+
+
+def register():
+ bpy.utils.register_class(OperatorEntry)
+ bpy.types.Scene.calls = bpy.props.CollectionProperty(name="Calls",
+ type=OperatorEntry)
+ bpy.utils.register_class(TEXT_OT_EditOperator)
+ bpy.utils.register_class(TEXT_PT_EditOperatorPanel)
+
+
+def unregister():
+ bpy.utils.unregister_class(TEXT_PT_EditOperatorPanel)
+ bpy.utils.unregister_class(TEXT_OT_EditOperator)
+ del bpy.types.Scene.calls
+ bpy.utils.unregister_class(OperatorEntry)
+
+
+if __name__ == "__main__":
+ register()