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.
|
# TODO: Add an operator to revert all local changes to the working copy.
|
||||||
|
|
||||||
class SVN_Operator:
|
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:
|
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,
|
# 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.
|
# 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"
|
# file.status_prediction_type = "SKIP_ONCE"
|
||||||
redraw_viewport()
|
redraw_viewport()
|
||||||
|
|
||||||
|
self.update_file_list(context)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _execute(self, context: Context) -> Set[str]:
|
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
|
# NOTE: This can take a long time, but providing a progress bar is
|
||||||
# fundamentally impossible because SVN itself doesn't provide the command
|
# fundamentally impossible because SVN itself doesn't provide the command
|
||||||
# line with any progress info.
|
# 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(
|
output = self.execute_svn_command(
|
||||||
context,
|
context,
|
||||||
["svn", "up", f"-r{self.revision}", "--accept", "postpone"],
|
["svn", "up", f"-r{self.revision}", "--accept", "postpone"],
|
||||||
use_cred=True
|
use_cred=True
|
||||||
)
|
)
|
||||||
self.report({"INFO"}, output.split("\n")[-2])
|
self.report({"INFO"}, output.split("\n")[-2])
|
||||||
|
self.update_file_list(context)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def set_predicted_file_status(self, repo, file_entry: "SVN_file"):
|
def set_predicted_file_status(self, repo, file_entry: "SVN_file"):
|
||||||
|
@ -123,6 +123,16 @@ class SVN_file(PropertyGroup):
|
|||||||
|
|
||||||
return 'QUESTION'
|
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):
|
class SVN_log(PropertyGroup):
|
||||||
"""Property Group that can represent an SVN log entry."""
|
"""Property Group that can represent an SVN log entry."""
|
||||||
@ -251,6 +261,8 @@ class SVN_repository(PropertyGroup):
|
|||||||
self.auth_failed = False
|
self.auth_failed = False
|
||||||
if self.exists and self.is_cred_entered:
|
if self.exists and self.is_cred_entered:
|
||||||
Processes.start('Authenticate')
|
Processes.start('Authenticate')
|
||||||
|
# Trigger the file list filtering.
|
||||||
|
self.file_search_filter = self.file_search_filter
|
||||||
|
|
||||||
username: StringProperty(
|
username: StringProperty(
|
||||||
name="Username",
|
name="Username",
|
||||||
@ -467,18 +479,11 @@ class SVN_repository(PropertyGroup):
|
|||||||
return self.get_file_by_absolute_path(bpy.data.filepath)
|
return self.get_file_by_absolute_path(bpy.data.filepath)
|
||||||
|
|
||||||
### File List UIList filter properties ###
|
### File List UIList filter properties ###
|
||||||
# These are normally stored on the UIList, but then they cannot be accessed
|
# Filtering properties are normally stored on the UIList,
|
||||||
# from anywhere else, since template_list() does not return the UIList instance.
|
# 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
|
# 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
|
# ensure that a filtered out entry can never be the active one.
|
||||||
# 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
|
|
||||||
|
|
||||||
def force_good_active_index(self, context) -> bool:
|
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
|
If the active element is being filtered out, set the active element to
|
||||||
something that is visible.
|
something that is visible.
|
||||||
"""
|
"""
|
||||||
visible_indicies = self.get_visible_indicies(context)
|
if not self.active_file.show_in_filelist:
|
||||||
if len(visible_indicies) == 0:
|
for i, file in enumerate(self.external_files):
|
||||||
self.external_files_active_index = 0
|
if file.show_in_filelist:
|
||||||
elif self.external_files_active_index not in visible_indicies:
|
self.external_files_active_index = i
|
||||||
self.external_files_active_index = visible_indicies[0]
|
return
|
||||||
|
|
||||||
def update_file_filter(self, context):
|
def update_file_filter(self, context):
|
||||||
"""Should run when any of the SVN file list search filters are changed."""
|
"""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)
|
self.force_good_active_index(context)
|
||||||
|
|
||||||
file_search_filter: StringProperty(
|
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:
|
if file_entry.svn_path not in svn_paths:
|
||||||
repo.remove_file_entry(file_entry)
|
repo.remove_file_entry(file_entry)
|
||||||
|
|
||||||
|
repo.update_file_filter(context)
|
||||||
repo.force_good_active_index(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
|
properties to the addon preferences) we can find a visible entry
|
||||||
from other UI code, allowing us to avoid situations where the active
|
from other UI code, allowing us to avoid situations where the active
|
||||||
element becomes hidden."""
|
element becomes hidden."""
|
||||||
flt_flags = []
|
|
||||||
flt_neworder = []
|
flt_neworder = []
|
||||||
list_items = getattr(data, propname)
|
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
|
helper_funcs = bpy.types.UI_UL_list
|
||||||
|
|
||||||
@ -134,25 +134,6 @@ class SVN_UL_file_list(UIList):
|
|||||||
if not repo:
|
if not repo:
|
||||||
return flt_flags, flt_neworder
|
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
|
return flt_flags, flt_neworder
|
||||||
|
|
||||||
def filter_items(self, context, data, propname):
|
def filter_items(self, context, data, propname):
|
||||||
|
@ -99,13 +99,15 @@ def is_log_useful(context):
|
|||||||
repo = context.scene.svn.get_repo(context)
|
repo = context.scene.svn.get_repo(context)
|
||||||
if len(repo.log) == 0:
|
if len(repo.log) == 0:
|
||||||
return False
|
return False
|
||||||
any_visible = repo.get_visible_indicies(context)
|
|
||||||
if not any_visible:
|
|
||||||
return False
|
|
||||||
active_file = repo.active_file
|
active_file = repo.active_file
|
||||||
if active_file.status in ['unversioned', 'added']:
|
if active_file.status in ['unversioned', 'added']:
|
||||||
return False
|
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
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user