Split addon code up by purpose

This commit is contained in:
gandalf3
2017-07-07 17:56:49 -07:00
parent bbc1c8b3bf
commit fcf90a0e75
4 changed files with 103 additions and 134 deletions

View File

@@ -1,54 +1,26 @@
# -*- coding: utf-8 -*-
bl_info = { bl_info = {
'name': 'Package Manager', 'name': 'Package Manager',
'description': 'Testing package management', 'description': 'Testing package management',
'category': 'System', 'category': 'System',
'support': 'TESTING', 'support': 'TESTING',
} }
import bpy
from bpy.props import CollectionProperty
from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences
class RepositoryProperty(PropertyGroup): # from bpy.utils import register_class, unregister_class
url = bpy.props.StringProperty(name="URL") import importlib
import sys
import logging
class PACKAGE_UL_repositories(UIList): log = logging.getLogger(__name__)
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
split = layout.split(0.3)
split.prop(item, "name")
split.prop(item, "url")
def invoke(self, onctext, event):
pass
class PackagePreferences(AddonPreferences):
bl_idname = __package__
repositories = CollectionProperty(type=RepositoryProperty)
active_repository = bpy.props.IntProperty()
def draw(self, context):
layout = self.layout
row = layout.row()
row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
col = row.column(align=True)
col.operator("package.add_repository", icon="ZOOMIN", text="")
col.operator("package.remove_repository", icon="ZOOMOUT", text="")
# class PackageManager:
# # For some reason accessing *Property objects stored in this class gives a TypeError:
# # UILayout.prop(): error with argument 1, "data" - Function.data expected a AnyType type, not tuple
# # But accessing them when not stored in a class or dict is fine?
# settings = bpy.props.PointerProperty(type=PackageSettings)
# last_response_code = bpy.props.PointerProperty(type=bpy.types.StringProperty)
def register(): def register():
# Reload support # Reload support
import sys if '%s.blender_common' % __name__ in sys.modules:
if '%s.pkg_ops' % __name__ in sys.modules:
import importlib
def reload_mod(name): def reload_mod(name):
print("Reloading %s" % name) log.debug("Reloading %s", name)
modname = '%s.%s' % (__name__, name) modname = '%s.%s' % (__name__, name)
try: try:
old_module = sys.modules[modname] old_module = sys.modules[modname]
@@ -61,26 +33,13 @@ def register():
sys.modules[modname] = new_module sys.modules[modname] = new_module
return new_module return new_module
pkg_ops = reload_mod('pkg_ops') blender_common = reload_mod('blender_common')
pkg_ui = reload_mod('pkg_ui')
else: else:
from . import (pkg_ops, pkg_ui) from . import blender_common
bpy.utils.register_class(RepositoryProperty) blender_common.register()
bpy.utils.register_class(PACKAGE_UL_repositories)
bpy.utils.register_class(PackagePreferences)
pkg_ops.register()
pkg_ui.register()
def unregister(): def unregister():
from . import (pkg_ops, pkg_ui) blender_common.unregister()
pkg_ops.unregister()
pkg_ui.unregister();
bpy.utils.unregister_class(RepositoryProperty)
bpy.utils.unregister_class(PACKAGE_UL_repositories)
bpy.utils.unregister_class(PackagePreferences)
del bpy.types.Scene.custom
del bpy.types.Scene.custom_idx

View File

@@ -1,54 +1,36 @@
# -*- coding: utf-8 -*-
# This file is for code dealing specifically with blender
import bpy import bpy
import logging from bpy.props import CollectionProperty
from multiprocessing import Process, Pipe from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences, Operator
from . import blenderpack from .subprocess_adapter import SubprocessOperatorMixin
class SubprocessOperatorMixin: class RepositoryProperty(PropertyGroup):
timer = None url = bpy.props.StringProperty(name="URL")
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
# run once in invoke class PACKAGE_UL_repositories(UIList):
def setup(self): def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
pass split = layout.split(0.3)
# run on receipt of data from subprocess split.prop(item, "name")
def handle_response(self, resp): split.prop(item, "url")
def invoke(self, onctext, event):
pass pass
def __init__(self): class PackagePreferences(AddonPreferences):
self.pipe = Pipe() bl_idname = __package__
self.subprocess = None
def execute(self, context): repositories = CollectionProperty(type=RepositoryProperty)
return self.invoke(context, None) active_repository = bpy.props.IntProperty()
def invoke(self, context, event): def draw(self, context):
self.subprocess.start() layout = self.layout
# we have to explicitly close the end of the pipe we are NOT using, row = layout.row()
# otherwise no exception will be generated when the other process closes its end. row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
self.pipe[1].close() col = row.column(align=True)
col.operator("package.add_repository", icon="ZOOMIN", text="")
wm = context.window_manager col.operator("package.remove_repository", icon="ZOOMOUT", text="")
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(.01, context.window)
self.setup()
return {'RUNNING_MODAL'}
def modal(self, context, event):
self.log.debug("polling")
try:
if self.pipe[0].poll():
newdata = self.pipe[0].recv()
else:
newdata = None
except EOFError:
self.log.debug("done polling")
return {'FINISHED'}
if newdata is not None:
self.handle_response(newdata)
return {'PASS_THROUGH'}
class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator): class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator):
bl_idname = "package.fetch" bl_idname = "package.fetch"
@@ -88,11 +70,22 @@ class PACKAGE_OT_remove_repository(bpy.types.Operator):
def register(): def register():
bpy.utils.register_class(RepositoryProperty)
bpy.utils.register_class(PackagePreferences)
bpy.utils.register_class(PACKAGE_OT_fetch) bpy.utils.register_class(PACKAGE_OT_fetch)
bpy.utils.register_class(PACKAGE_OT_add_repository) bpy.utils.register_class(PACKAGE_OT_add_repository)
bpy.utils.register_class(PACKAGE_OT_remove_repository) bpy.utils.register_class(PACKAGE_OT_remove_repository)
bpy.utils.register_class(PACKAGE_UL_repositories)
def unregister(): def unregister():
bpy.utils.unregister_class(PACKAGE_OT_fetch) bpy.utils.unregister_class(RepositoryProperty)
bpy.utils.unregister_class(PACKAGE_OT_remove_repository) bpy.utils.unregister_class(PackagePreferences)
bpy.utils.unregister_class(PACKAGE_OT_fetch)
bpy.utils.unregister_class(PACKAGE_OT_add_repository)
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
bpy.utils.unregister_class(PACKAGE_UL_repositories)

View File

@@ -1,33 +0,0 @@
import bpy
from . import pkg_ops
class USERPREF_PT_packages(bpy.types.Panel):
bl_label = "Package Management"
bl_space_type = 'USER_PREFERENCES'
bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
userpref = context.user_preferences
return (userpref.active_section == 'PACKAGES')
def draw(self, context):
wm = context.window_manager
# see comment in __init__.py
pm_settings = wm.package_manager_settings
layout = self.layout
row = layout.row()
row.prop(pm_settings, "url")
row.operator(pkg_ops.PACKAGE_OT_fetch.bl_idname, text="Fetch")
row = layout.row()
# just a demonstration
row.label(text="Last response: %s" % pkg_ops.PACKAGE_OT_fetch.last_response)
def register():
bpy.utils.register_class(USERPREF_PT_packages)
def unregister():
bpy.utils.unregister_class(USERPREF_PT_packages)

50
subprocess_adapter.py Normal file
View File

@@ -0,0 +1,50 @@
import logging
from multiprocessing import Process, Pipe
class SubprocessOperatorMixin:
timer = None
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
# run once in invoke
def setup(self):
pass
# run on receipt of data from subprocess
def handle_response(self, resp):
pass
def __init__(self):
self.pipe = Pipe()
self.subprocess = None
def execute(self, context):
return self.invoke(context, None)
def invoke(self, context, event):
self.subprocess.start()
# we have to explicitly close the end of the pipe we are NOT using,
# otherwise no exception will be generated when the other process closes its end.
self.pipe[1].close()
wm = context.window_manager
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(.01, context.window)
self.setup()
return {'RUNNING_MODAL'}
def modal(self, context, event):
self.log.debug("polling")
try:
if self.pipe[0].poll():
newdata = self.pipe[0].recv()
else:
newdata = None
except EOFError:
self.log.debug("done polling")
return {'FINISHED'}
if newdata is not None:
self.handle_response(newdata)
return {'PASS_THROUGH'}