Improve metadata display
This commit is contained in:
@@ -14,12 +14,13 @@ bl_info = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
if 'bpy' in locals():
|
if 'bpy' in locals():
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
|
log.debug("Reloading")
|
||||||
subproc = importlib.reload(subproc)
|
subproc = importlib.reload(subproc)
|
||||||
|
|
||||||
bpkg = importlib.reload(bpkg)
|
bpkg = importlib.reload(bpkg)
|
||||||
Package = bpkg.Package
|
Package = bpkg.Package
|
||||||
else:
|
else:
|
||||||
@@ -30,6 +31,32 @@ else:
|
|||||||
import bpy
|
import bpy
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
class ConsolidatedPackage:
|
||||||
|
"""
|
||||||
|
Stores a grouping of different versions of the same package
|
||||||
|
"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".ConsolidatedPackage")
|
||||||
|
|
||||||
|
def __init__(self, pkg=None):
|
||||||
|
self.versions = []
|
||||||
|
self.expanded = False
|
||||||
|
self.installed = False
|
||||||
|
|
||||||
|
if pkg is not None:
|
||||||
|
self.add_version(pkg)
|
||||||
|
|
||||||
|
def get_latest_version(self) -> bpkg.Package:
|
||||||
|
"""Get package with highest version number"""
|
||||||
|
return self.versions[0] # this is always sorted with the highest on top
|
||||||
|
|
||||||
|
def add_version(self, pkg: Package):
|
||||||
|
self.versions.append(pkg)
|
||||||
|
self.versions.sort(key=lambda v: v.version, reverse=True)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (pkg for pkg in self.versions)
|
||||||
|
|
||||||
class SubprocMixin:
|
class SubprocMixin:
|
||||||
"""Mix-in class for things that need to be run in a subprocess."""
|
"""Mix-in class for things that need to be run in a subprocess."""
|
||||||
|
|
||||||
@@ -565,97 +592,72 @@ class USERPREF_PT_packages(bpy.types.Panel):
|
|||||||
|
|
||||||
return startswith + contains
|
return startswith + contains
|
||||||
|
|
||||||
def draw_package(pkg: ConsolidatedPackage, layout: bpy.types.UILayout):# {{{
|
def draw_package(metapkg: ConsolidatedPackage, layout: bpy.types.UILayout):# {{{
|
||||||
"""Draws the given package"""
|
"""Draws the given package"""
|
||||||
pkgbox = layout.box()
|
|
||||||
spl = pkgbox.split(.8)
|
|
||||||
left = spl.row(align=True)
|
|
||||||
blinfo = pkg.versions[0].bl_info
|
|
||||||
|
|
||||||
# for install/uninstall buttons
|
|
||||||
right = spl.row()
|
|
||||||
right.alignment = 'RIGHT'
|
|
||||||
right.scale_y = 1.5
|
|
||||||
|
|
||||||
# for collapse/expand button
|
|
||||||
left.operator(
|
|
||||||
WM_OT_package_toggle_expand.bl_idname,
|
|
||||||
icon='TRIA_DOWN' if pkg.expanded else 'TRIA_RIGHT',
|
|
||||||
emboss=False,
|
|
||||||
).package_name=blinfo['name']
|
|
||||||
|
|
||||||
# for metadata
|
|
||||||
leftcol = left.column(align=True)
|
|
||||||
|
|
||||||
def collapsed():
|
def collapsed():
|
||||||
|
"""Draw collapsed version of package layout"""
|
||||||
lr1 = leftcol.row()
|
lr1 = leftcol.row()
|
||||||
lr2 = leftcol.row()
|
lr2 = leftcol.row()
|
||||||
|
|
||||||
lr1.label(text=blinfo.get('name', ""))
|
if pkg.name:
|
||||||
lr2.label(text=blinfo.get('description', ""))
|
lr1.label(text=pkg.name)
|
||||||
|
if pkg.description:
|
||||||
|
lr2.label(text=pkg.description)
|
||||||
lr2.enabled = False #Give name more visual weight
|
lr2.enabled = False #Give name more visual weight
|
||||||
|
|
||||||
latest_pkg = pkg.get_latest_version()
|
|
||||||
if latest_pkg.installed:
|
|
||||||
if latest_pkg.url:
|
|
||||||
right.operator(PACKAGE_OT_uninstall.bl_idname,
|
|
||||||
text="Uninstall").package_name=latest_pkg.name
|
|
||||||
else:
|
|
||||||
right.label("Installed")
|
|
||||||
else:
|
|
||||||
if latest_pkg.url:
|
|
||||||
right.operator(PACKAGE_OT_install.bl_idname,
|
|
||||||
text="Install").package_url=pkg.versions[0].url
|
|
||||||
else:
|
|
||||||
right.label("Not installed, but no URL?")
|
|
||||||
|
|
||||||
def expanded():
|
def expanded():
|
||||||
row1 = leftcol.row()
|
"""Draw expanded version of package layout"""
|
||||||
row1.label(blinfo.get('name'), "")
|
def fmt_version(version_number: tuple) -> str:
|
||||||
|
"""Take version number as a tuple and format it as a string"""
|
||||||
def string_version(version_number) -> str:
|
|
||||||
"""Take version number as an iterable and format it as a string"""
|
|
||||||
vstr = str(version_number[0])
|
vstr = str(version_number[0])
|
||||||
for component in version_number[1:]:
|
for component in version_number[1:]:
|
||||||
vstr += "." + str(component)
|
vstr += "." + str(component)
|
||||||
return vstr
|
return vstr
|
||||||
|
|
||||||
if blinfo.get('description'):
|
row1 = leftcol.row()
|
||||||
|
row1.label(pkg.name)
|
||||||
|
|
||||||
|
if pkg.description:
|
||||||
row2 = leftcol.row()
|
row2 = leftcol.row()
|
||||||
row2.label(blinfo['description'])
|
row2.label(pkg.description)
|
||||||
# row2.scale_y = 1.2
|
# row2.scale_y = 1.2
|
||||||
|
|
||||||
if blinfo.get('version'):
|
def draw_metadatum(label: str, value: str, layout: bpy.types.UILayout):
|
||||||
spl = leftcol.row().split(.15)
|
|
||||||
spl.label("Version:")
|
|
||||||
spl.label(string_version(blinfo['version']))
|
|
||||||
|
|
||||||
def draw_metadatum(key: str, value: str, layout: bpy.types.UILayout):
|
|
||||||
"""Draw the given key value pair in a new row in given layout container"""
|
"""Draw the given key value pair in a new row in given layout container"""
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.scale_y = .8
|
row.scale_y = .8
|
||||||
spl = row.split(.15)
|
spl = row.split(.15)
|
||||||
spl.label("{}:".format(key))
|
spl.label("{}:".format(label))
|
||||||
spl.label(value)
|
spl.label(value)
|
||||||
|
|
||||||
for prop in (
|
# don't compare against None here; we don't want to display empty arrays/strings either
|
||||||
# "description",
|
if pkg.location:
|
||||||
"author",
|
draw_metadatum("Location", pkg.location, leftcol)
|
||||||
"category",
|
if pkg.version:
|
||||||
# "version",
|
draw_metadatum("Version", fmt_version(pkg.version), leftcol)
|
||||||
# "blender",
|
# if pkg.blender:
|
||||||
"location",
|
# draw_metadatum("Compatible blender version", fmt_version(pkg.blender), leftcol)
|
||||||
"warning",
|
if pkg.category:
|
||||||
"support",
|
draw_metadatum("Category", pkg.category, leftcol)
|
||||||
# "wiki_url",
|
if pkg.author:
|
||||||
# "tracker_url",
|
draw_metadatum("Author", pkg.author, leftcol)
|
||||||
):
|
if pkg.support:
|
||||||
if blinfo.get(prop):
|
draw_metadatum("Support level", pkg.support.title(), leftcol)
|
||||||
row = leftcol.row()
|
if pkg.warning:
|
||||||
row.scale_y = .8
|
draw_metadatum("Warning", pkg.warning, leftcol)
|
||||||
spl = row.split(.15)
|
|
||||||
spl.label("{}:".format(prop.title()))
|
if pkg.wiki_url or pkg.tracker_url:
|
||||||
spl.label(str(blinfo[prop]))
|
padrow = leftcol.row()
|
||||||
|
padrow.label()
|
||||||
|
padrow.scale_y = .5
|
||||||
|
urlrow = leftcol.row()
|
||||||
|
urlrow.alignment = 'LEFT'
|
||||||
|
if pkg.wiki_url:
|
||||||
|
urlrow.operator("wm.url_open", text="Documentation", icon='HELP').url=pkg.wiki_url
|
||||||
|
if pkg.tracker_url:
|
||||||
|
urlrow.operator("wm.url_open", text="Report a Bug", icon='URL').url=pkg.tracker_url
|
||||||
|
|
||||||
def draw_version(layout: bpy.types.UILayout, pkg: Package):
|
def draw_version(layout: bpy.types.UILayout, pkg: Package):
|
||||||
"""Draw version of package"""
|
"""Draw version of package"""
|
||||||
@@ -664,7 +666,7 @@ class USERPREF_PT_packages(bpy.types.Panel):
|
|||||||
right = spl.column()
|
right = spl.column()
|
||||||
right.alignment = 'RIGHT'
|
right.alignment = 'RIGHT'
|
||||||
|
|
||||||
left.label(text=string_version(pkg.version))
|
left.label(text=fmt_version(pkg.version))
|
||||||
|
|
||||||
if pkg.repository is not None:
|
if pkg.repository is not None:
|
||||||
draw_metadatum("Repository", pkg.repository, left)
|
draw_metadatum("Repository", pkg.repository, left)
|
||||||
@@ -674,16 +676,49 @@ class USERPREF_PT_packages(bpy.types.Panel):
|
|||||||
|
|
||||||
draw_metadatum("Installed to", str(pkg.installed_location), left)
|
draw_metadatum("Installed to", str(pkg.installed_location), left)
|
||||||
|
|
||||||
if len(pkg.versions) > 1:
|
if len(metapkg.versions) > 1:
|
||||||
row = pkgbox.row()
|
row = pkgbox.row()
|
||||||
row.label(text="There are multiple providers of this package:")
|
row.label(text="There are multiple providers of this package:")
|
||||||
for version in pkg.versions:
|
for version in metapkg.versions:
|
||||||
# row = pkgbox.row()
|
# row = pkgbox.row()
|
||||||
subvbox = pkgbox.box()
|
subvbox = pkgbox.box()
|
||||||
draw_version(subvbox, version)
|
draw_version(subvbox, version)
|
||||||
|
|
||||||
|
pkg = metapkg.get_latest_version()
|
||||||
|
|
||||||
if pkg.expanded:
|
pkgbox = layout.box()
|
||||||
|
spl = pkgbox.split(.8)
|
||||||
|
left = spl.row(align=True)
|
||||||
|
|
||||||
|
# for install/uninstall buttons
|
||||||
|
right = spl.row()
|
||||||
|
right.alignment = 'RIGHT'
|
||||||
|
right.scale_y = 1.5
|
||||||
|
|
||||||
|
# for collapse/expand button
|
||||||
|
left.operator(
|
||||||
|
WM_OT_package_toggle_expand.bl_idname,
|
||||||
|
icon='TRIA_DOWN' if metapkg.expanded else 'TRIA_RIGHT',
|
||||||
|
emboss=False,
|
||||||
|
).package_name=pkg.name
|
||||||
|
|
||||||
|
# for metadata
|
||||||
|
leftcol = left.column(align=True)
|
||||||
|
|
||||||
|
if pkg.installed:
|
||||||
|
if pkg.url:
|
||||||
|
right.operator(PACKAGE_OT_uninstall.bl_idname,
|
||||||
|
text="Uninstall").package_name=pkg.name
|
||||||
|
else:
|
||||||
|
right.label("Installed")
|
||||||
|
else:
|
||||||
|
if pkg.url:
|
||||||
|
right.operator(PACKAGE_OT_install.bl_idname,
|
||||||
|
text="Install").package_url=pkg.url
|
||||||
|
else:
|
||||||
|
right.label("Not installed, but no URL?")
|
||||||
|
|
||||||
|
if metapkg.expanded:
|
||||||
expanded()
|
expanded()
|
||||||
else:
|
else:
|
||||||
collapsed()# }}}
|
collapsed()# }}}
|
||||||
@@ -725,29 +760,6 @@ class USERPREF_PT_packages(bpy.types.Panel):
|
|||||||
row = pkgzone.row()
|
row = pkgzone.row()
|
||||||
draw_package(USERPREF_PT_packages.all_packages[pkgname], row)
|
draw_package(USERPREF_PT_packages.all_packages[pkgname], row)
|
||||||
|
|
||||||
class ConsolidatedPackage:
|
|
||||||
"""
|
|
||||||
Stores a grouping of different versions of the same packages,
|
|
||||||
and view-specific data used for drawing
|
|
||||||
"""
|
|
||||||
def __init__(self, pkg=None):
|
|
||||||
self.versions = []
|
|
||||||
self.expanded = False
|
|
||||||
self.installed = False
|
|
||||||
|
|
||||||
if pkg is not None:
|
|
||||||
self.add_version(pkg)
|
|
||||||
|
|
||||||
def get_latest_version(self) -> Package:
|
|
||||||
"""Get package with highest version number"""
|
|
||||||
return self.versions[0] # this is always sorted with the highest on top
|
|
||||||
|
|
||||||
def add_version(self, pkg: Package):
|
|
||||||
self.versions.append(pkg)
|
|
||||||
self.versions.sort(key=lambda v: v.version, reverse=True)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return (pkg for pkg in self.versions)
|
|
||||||
|
|
||||||
class WM_OT_package_toggle_expand(bpy.types.Operator):
|
class WM_OT_package_toggle_expand(bpy.types.Operator):
|
||||||
bl_idname = "wm.package_toggle_expand"
|
bl_idname = "wm.package_toggle_expand"
|
||||||
|
@@ -17,6 +17,7 @@ class Package:
|
|||||||
|
|
||||||
self.installed = False
|
self.installed = False
|
||||||
self.repository = None
|
self.repository = None
|
||||||
|
self.installed_location = None
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"""
|
"""
|
||||||
@@ -40,20 +41,95 @@ class Package:
|
|||||||
setattr(self, attr, package_dict[attr])
|
setattr(self, attr, package_dict[attr])
|
||||||
|
|
||||||
# bl_info convenience getters
|
# bl_info convenience getters
|
||||||
|
# required fields
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""Get name from bl_info"""
|
"""Get name from bl_info"""
|
||||||
|
try:
|
||||||
return self.bl_info['name']
|
return self.bl_info['name']
|
||||||
|
except KeyError:
|
||||||
@property
|
return None
|
||||||
def description(self) -> str:
|
|
||||||
"""Get description from bl_info"""
|
|
||||||
return self.bl_info['description']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self) -> tuple:
|
def version(self) -> tuple:
|
||||||
"""Get version from bl_info"""
|
"""Get version from bl_info"""
|
||||||
|
try:
|
||||||
return tuple(self.bl_info['version'])
|
return tuple(self.bl_info['version'])
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def blender(self) -> tuple:
|
||||||
|
"""Get blender from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['blender']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# optional fields
|
||||||
|
@property
|
||||||
|
def description(self) -> str:
|
||||||
|
"""Get description from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['description']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def author(self) -> str:
|
||||||
|
"""Get author from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['author']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def category(self) -> str:
|
||||||
|
"""Get category from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['category']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def location(self) -> str:
|
||||||
|
"""Get location from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['location']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def support(self) -> str:
|
||||||
|
"""Get support from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['support']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def warning(self) -> str:
|
||||||
|
"""Get warning from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['warning']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wiki_url(self) -> str:
|
||||||
|
"""Get wiki_url from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['wiki_url']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tracker_url(self) -> str:
|
||||||
|
"""Get tracker_url from bl_info"""
|
||||||
|
try:
|
||||||
|
return self.bl_info['tracker_url']
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
# @classmethod
|
# @classmethod
|
||||||
# def from_dict(cls, package_dict: dict):
|
# def from_dict(cls, package_dict: dict):
|
||||||
@@ -83,6 +159,7 @@ class Package:
|
|||||||
pkg = cls()
|
pkg = cls()
|
||||||
pkg.files = [filepath.name]
|
pkg.files = [filepath.name]
|
||||||
pkg.installed_location = str(filepath)
|
pkg.installed_location = str(filepath)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pkg.bl_info = module.bl_info
|
pkg.bl_info = module.bl_info
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
|
Reference in New Issue
Block a user