Better sorting of search results

This commit is contained in:
Ellwood Zwovic
2017-07-18 17:30:42 -07:00
parent 6193437636
commit 19c1f3a8ac

View File

@@ -402,8 +402,17 @@ class USERPREF_PT_packages(bpy.types.Panel):
return (userpref.active_section == 'PACKAGES')
def draw(self, context):
layout = self.layout
wm = context.window_manager
# try:
# wm['package_last_used_filters']
# except KeyError:
# wm['package_last_used_filters'] = {}
# try:
# wm['package_displayed_packages']
# except KeyError:
# wm['package_displayed_packages'] = []
main = layout.row()
spl = main.split(.12)
@@ -411,42 +420,66 @@ class USERPREF_PT_packages(bpy.types.Panel):
pkgzone = spl.column()
sidebar.label(text="Category")
sidebar.prop(context.window_manager, "addon_filter", text="")
sidebar.prop(wm, "addon_filter", text="")
top = pkgzone.row()
spl = top.split(.6)
spl.prop(context.window_manager, "package_search", text="", icon='VIEWZOOM')
spl.prop(wm, "package_search", text="", icon='VIEWZOOM')
spl_r = spl.row()
spl_r.prop(context.window_manager, "package_install_filter", expand=True)
spl_r.prop(wm, "package_install_filter", expand=True)
#TODO: more advanced filter/sorting; sort matches which match the filter string from the start higher
#Also some caching of this would be nice, this only needs to be re-run when any of the filters change.
def filter_package(package):# {{{
"""Returns true if the given package matches all filters"""
filterstr = bpy.context.window_manager.package_search
category = bpy.context.window_manager.addon_filter
blinfo = package['bl_info']
#TODO: if filters are only added to, we can filter on existing filtered list rather than redoing whole list
# def filters_changed(filters: dict) -> bool:
# if filters['search'] != wm['package_last_used_filters'].get('search'):
# return True
# if filters['category'] != wm['package_last_used_filters'].get('category'):
# return True
# return False
def match_search() -> bool:
if len(filterstr) == 0:
return True
if blinfo['name'].lower().__contains__(filterstr.lower()):
def filtered(filters: dict, packages: list) -> list:
"""Returns filtered and sorted list of packages which match filters defined in dict"""
#TODO: using lower() for case-insensitive comparison doesn't work in some languages
def match_contains(blinfo) -> bool:
if blinfo['name'].lower().__contains__(filters['search'].lower()):
return True
return False
def match_category() -> bool:
if category.upper() == 'ALL':
def match_startswith(blinfo) -> bool:
if blinfo['name'].lower().startswith(filters['search'].lower()):
return True
return False
def match_category(blinfo) -> bool:
if filters['category'].lower() == 'all':
return True
if 'category' not in blinfo:
return True
if blinfo['category'].upper() == category.upper():
return False
if blinfo['category'].lower() == filters['category'].lower():
return True
return False
if match_search() and match_category():
return True
return False# }}}
# use two lists as a simple way of putting matches from the start on top
contains = []
startswith = []
for pkg in packages:
blinfo = pkg['bl_info']
if match_category(blinfo):
if len(filters['search']) == 0:
startswith.append(pkg)
continue
if match_startswith(blinfo):
startswith.append(pkg)
continue
if match_contains(blinfo):
contains.append(pkg)
continue
return startswith + contains
def draw_package(pkg, layout):# {{{
"""Draws the given package"""
@@ -533,7 +566,7 @@ class USERPREF_PT_packages(bpy.types.Panel):
#TODO either store repos in windowmanager and reload from disk every time, or store them in the .blend. Not both
repo = context.user_preferences.addons[__package__].preferences['repo']
except KeyError:
center_message("Loading Repositories...")
center_message(pkgzone, "Loading Repositories...")
import pathlib
# TODO: read repository synchronously for now; can't run an operator to do async monitoring from draw code
@@ -544,14 +577,25 @@ class USERPREF_PT_packages(bpy.types.Panel):
return
if repo is None:
center_message("No repository found. Add one in the addon preferences.")
center_message(pkgzone, "No repository found. Add one in the addon preferences.")
return
for pkg in repo['packages']:
if filter_package(pkg):
row = pkgzone.row()
draw_package(pkg, row)
filters = {
'category': bpy.context.window_manager.addon_filter,
'search': bpy.context.window_manager.package_search,
}
# if filters_changed(filters):
# self.log.debug("Re-executing filters")
# wm['package_displayed_packages'] = filtered(filters, repo['packages'])
filtered_packages = filtered(filters, repo['packages'])
# for key, item in filters.items():
# wm['package_last_used_filters'][key] = item
for pkg in filtered_packages:
row = pkgzone.row()
draw_package(pkg, row)
class WM_OT_package_toggle_expand(bpy.types.Operator):
@@ -623,6 +667,8 @@ def register():
name="Install filter",
default='AVAILABLE',
)
# bpy.types.WindowManager.package_last_used_filters = dict()
# bpy.types.WindowManager.package_displayed_packages = []
bpy.utils.register_class(PackageManagerPreferences)
@@ -635,4 +681,6 @@ def unregister():
bpy.utils.unregister_class(WM_OT_package_toggle_expand)
del bpy.types.WindowManager.package_search
del bpy.types.WindowManager.package_install_filter
# del bpy.types.WindowManager.package_displayed_packages
# del bpy.types.WindowManager.package_last_used_filters
bpy.utils.unregister_class(PackageManagerPreferences)