SVN: Checkout, Multi-Repo, Optimizations & Clean-up #104
@ -18,6 +18,11 @@ from ..util import get_addon_prefs, redraw_viewport
|
||||
# TODO: Add an operator to revert all local changes to the working copy.
|
||||
|
||||
class SVN_Operator:
|
||||
@staticmethod
|
||||
def update_file_list(context):
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
repo.update_file_filter(context)
|
||||
|
||||
def execute_svn_command(self, context, command: List[str], use_cred=False) -> str:
|
||||
# Since a status update might already be being requested when an SVN operator is run,
|
||||
# we want to ignore the first update after any SVN operator.
|
||||
@ -51,6 +56,7 @@ class SVN_Operator_Single_File(SVN_Operator):
|
||||
# file.status_prediction_type = "SKIP_ONCE"
|
||||
redraw_viewport()
|
||||
|
||||
self.update_file_list(context)
|
||||
return ret
|
||||
|
||||
def _execute(self, context: Context) -> Set[str]:
|
||||
@ -227,13 +233,14 @@ class SVN_OT_download_repo_revision(SVN_Operator, Operator):
|
||||
# NOTE: This can take a long time, but providing a progress bar is
|
||||
# fundamentally impossible because SVN itself doesn't provide the command
|
||||
# line with any progress info.
|
||||
# TODO: Doing it in the background may be an option, just a hassle.
|
||||
# TODO: Should run in the background like regular `svn up`.
|
||||
output = self.execute_svn_command(
|
||||
context,
|
||||
["svn", "up", f"-r{self.revision}", "--accept", "postpone"],
|
||||
use_cred=True
|
||||
)
|
||||
self.report({"INFO"}, output.split("\n")[-2])
|
||||
self.update_file_list(context)
|
||||
return {"FINISHED"}
|
||||
|
||||
def set_predicted_file_status(self, repo, file_entry: "SVN_file"):
|
||||
|
@ -123,6 +123,16 @@ class SVN_file(PropertyGroup):
|
||||
|
||||
return 'QUESTION'
|
||||
|
||||
@property
|
||||
def has_default_status(self):
|
||||
return self.status == 'normal' and self.repos_status == 'none' and self.status_prediction_type == 'NONE'
|
||||
|
||||
show_in_filelist: BoolProperty(
|
||||
name="Show In File List",
|
||||
description="Flag indicating whether this file should be drawn in the file list. This flag is updated for every file whenever the file search string is modified. If we did this filtering during drawing time, it is painfully slow",
|
||||
default=False
|
||||
)
|
||||
|
||||
|
||||
class SVN_log(PropertyGroup):
|
||||
"""Property Group that can represent an SVN log entry."""
|
||||
@ -251,6 +261,8 @@ class SVN_repository(PropertyGroup):
|
||||
self.auth_failed = False
|
||||
if self.exists and self.is_cred_entered:
|
||||
Processes.start('Authenticate')
|
||||
# Trigger the file list filtering.
|
||||
self.file_search_filter = self.file_search_filter
|
||||
|
||||
username: StringProperty(
|
||||
name="Username",
|
||||
@ -467,18 +479,11 @@ class SVN_repository(PropertyGroup):
|
||||
return self.get_file_by_absolute_path(bpy.data.filepath)
|
||||
|
||||
### File List UIList filter properties ###
|
||||
# These are normally stored on the UIList, but then they cannot be accessed
|
||||
# from anywhere else, since template_list() does not return the UIList instance.
|
||||
# Filtering properties are normally stored on the UIList,
|
||||
# but then they cannot be accessed from anywhere else,
|
||||
# since template_list() does not return the UIList instance.
|
||||
# We need to be able to access them outside of drawing code, to be able to
|
||||
# know which entries are visible and ensure that a filtered out entry can never
|
||||
# be the active one.
|
||||
|
||||
def get_visible_indicies(self, context) -> List[int]:
|
||||
flt_flags, _flt_neworder = bpy.types.SVN_UL_file_list.cls_filter_items(
|
||||
context, self, 'external_files')
|
||||
|
||||
visible_indicies = [i for i, flag in enumerate(flt_flags) if flag != 0]
|
||||
return visible_indicies
|
||||
# ensure that a filtered out entry can never be the active one.
|
||||
|
||||
def force_good_active_index(self, context) -> bool:
|
||||
"""
|
||||
@ -486,14 +491,34 @@ class SVN_repository(PropertyGroup):
|
||||
If the active element is being filtered out, set the active element to
|
||||
something that is visible.
|
||||
"""
|
||||
visible_indicies = self.get_visible_indicies(context)
|
||||
if len(visible_indicies) == 0:
|
||||
self.external_files_active_index = 0
|
||||
elif self.external_files_active_index not in visible_indicies:
|
||||
self.external_files_active_index = visible_indicies[0]
|
||||
if not self.active_file.show_in_filelist:
|
||||
for i, file in enumerate(self.external_files):
|
||||
if file.show_in_filelist:
|
||||
self.external_files_active_index = i
|
||||
return
|
||||
|
||||
def update_file_filter(self, context):
|
||||
"""Should run when any of the SVN file list search filters are changed."""
|
||||
|
||||
UI_LIST = bpy.types.UI_UL_list
|
||||
if self.file_search_filter:
|
||||
filter_list = UI_LIST.filter_items_by_name(
|
||||
self.file_search_filter,
|
||||
1,
|
||||
self.external_files,
|
||||
"name",
|
||||
reverse=False
|
||||
)
|
||||
filter_list = [bool(val) for val in filter_list]
|
||||
self.external_files.foreach_set('show_in_filelist', filter_list)
|
||||
else:
|
||||
for file in self.external_files:
|
||||
if file == self.current_blend_file:
|
||||
file.show_in_filelist = True
|
||||
continue
|
||||
|
||||
file.show_in_filelist = not file.has_default_status
|
||||
|
||||
self.force_good_active_index(context)
|
||||
|
||||
file_search_filter: StringProperty(
|
||||
|
@ -273,6 +273,7 @@ def update_file_list(context, file_statuses: Dict[str, Tuple[str, str, int]]):
|
||||
if file_entry.svn_path not in svn_paths:
|
||||
repo.remove_file_entry(file_entry)
|
||||
|
||||
repo.update_file_filter(context)
|
||||
repo.force_good_active_index(context)
|
||||
|
||||
|
||||
|
@ -121,9 +121,9 @@ class SVN_UL_file_list(UIList):
|
||||
properties to the addon preferences) we can find a visible entry
|
||||
from other UI code, allowing us to avoid situations where the active
|
||||
element becomes hidden."""
|
||||
flt_flags = []
|
||||
flt_neworder = []
|
||||
list_items = getattr(data, propname)
|
||||
flt_flags = [file.show_in_filelist * cls.UILST_FLT_ITEM for file in list_items]
|
||||
|
||||
helper_funcs = bpy.types.UI_UL_list
|
||||
|
||||
@ -134,25 +134,6 @@ class SVN_UL_file_list(UIList):
|
||||
if not repo:
|
||||
return flt_flags, flt_neworder
|
||||
|
||||
def has_default_status(file):
|
||||
return file.status == 'normal' and file.repos_status == 'none' and file.status_prediction_type == 'NONE'
|
||||
|
||||
if repo.file_search_filter:
|
||||
flt_flags = helper_funcs.filter_items_by_name(repo.file_search_filter, cls.UILST_FLT_ITEM, list_items, "name",
|
||||
reverse=False)
|
||||
else:
|
||||
# Start with all files visible.
|
||||
flt_flags = [cls.UILST_FLT_ITEM] * len(list_items)
|
||||
|
||||
for i, item in enumerate(list_items):
|
||||
if item == repo.current_blend_file:
|
||||
# ALWAYS display the current .blend file.
|
||||
continue
|
||||
|
||||
if has_default_status(item):
|
||||
# Filter out files that have default statuses.
|
||||
flt_flags[i] = 0
|
||||
|
||||
return flt_flags, flt_neworder
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
|
@ -99,13 +99,15 @@ def is_log_useful(context):
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
if len(repo.log) == 0:
|
||||
return False
|
||||
any_visible = repo.get_visible_indicies(context)
|
||||
if not any_visible:
|
||||
return False
|
||||
active_file = repo.active_file
|
||||
if active_file.status in ['unversioned', 'added']:
|
||||
return False
|
||||
|
||||
if repo.file_search_filter:
|
||||
any_visible = any([file.show_in_filelist for file in repo.external_files])
|
||||
if not any_visible:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user