SVN: UX improvements #136
@ -20,7 +20,7 @@ class SVN_Operator:
|
||||
@staticmethod
|
||||
def update_file_list(context):
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
repo.update_file_filter(context)
|
||||
repo.refresh_ui_lists(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,
|
||||
@ -51,7 +51,6 @@ class SVN_Operator_Single_File(SVN_Operator):
|
||||
ret = self._execute(context)
|
||||
|
||||
file = self.get_file(context)
|
||||
if file:
|
||||
Processes.start('Status')
|
||||
redraw_viewport()
|
||||
|
||||
@ -107,7 +106,7 @@ class May_Modifiy_Current_Blend(SVN_Operator_Single_File, Warning_Operator):
|
||||
return current_blend and current_blend.svn_path == self.file_rel_path
|
||||
|
||||
reload_file: BoolProperty(
|
||||
name="Reload File",
|
||||
name="Reload File (Keep UI)",
|
||||
description="Reload the file after the operation is completed. The UI layout will be preserved",
|
||||
default=False,
|
||||
)
|
||||
@ -305,6 +304,7 @@ class SVN_OT_trash_file(SVN_Operator_Single_File, Warning_Operator, Operator):
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
file_rel_path: StringProperty()
|
||||
missing_file_allowed = False
|
||||
|
||||
def get_warning_text(self, context):
|
||||
return "Are you sure you want to move this file to the recycle bin?\n " + self.file_rel_path
|
||||
|
@ -444,15 +444,15 @@ class SVN_repository(PropertyGroup):
|
||||
"""When user clicks on a different file, the latest log entry of that file
|
||||
should become the active log entry."""
|
||||
|
||||
latest_idx = self.get_latest_revision_of_file(
|
||||
latest_rev = self.get_latest_revision_of_file(
|
||||
self.active_file.svn_path)
|
||||
# SVN Revisions are not 0-indexed, so we need to subtract 1.
|
||||
self.log_active_index = latest_idx-1
|
||||
self.log_active_index = latest_rev-1
|
||||
|
||||
space = context.space_data
|
||||
if space and space.type == 'FILE_BROWSER':
|
||||
# Set the active file in the file browser to whatever was selected in the SVN Files panel.
|
||||
self.log_active_index_filebrowser = latest_idx-1
|
||||
self.log_active_index_filebrowser = latest_rev-1
|
||||
|
||||
space.params.directory = self.active_file.absolute_path.parent.as_posix().encode()
|
||||
space.params.filename = self.active_file.name.encode()
|
||||
@ -462,7 +462,7 @@ class SVN_repository(PropertyGroup):
|
||||
relative_path=self.active_file.name)
|
||||
Processes.start('Activate File')
|
||||
|
||||
# Filter out log entries that did not affect the selected file.
|
||||
# Set the filter flag of the log entries based on whether they affect the active file or not.
|
||||
self.log.foreach_set(
|
||||
'affects_active_file',
|
||||
[log_entry.changes_file(self.active_file)
|
||||
@ -513,28 +513,10 @@ class SVN_repository(PropertyGroup):
|
||||
return self.get_file_by_absolute_path(bpy.data.filepath)
|
||||
|
||||
### File List UIList filter properties ###
|
||||
# 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
|
||||
# ensure that a filtered out entry can never be the active one.
|
||||
|
||||
def force_good_active_index(self, context) -> bool:
|
||||
"""
|
||||
We want to avoid having the active file entry be invisible due to filtering.
|
||||
If the active element is being filtered out, set the active element to
|
||||
something that is visible.
|
||||
"""
|
||||
if len(self.external_files) == 0:
|
||||
return
|
||||
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."""
|
||||
def refresh_ui_lists(self, context):
|
||||
"""Refresh the file UI list based on filter settings.
|
||||
Also triggers a refresh of the SVN UIList, through the update callback of
|
||||
external_files_active_index."""
|
||||
|
||||
UI_LIST = bpy.types.UI_UL_list
|
||||
if self.file_search_filter:
|
||||
@ -555,12 +537,24 @@ class SVN_repository(PropertyGroup):
|
||||
|
||||
file.show_in_filelist = not file.has_default_status
|
||||
|
||||
self.force_good_active_index(context)
|
||||
if len(self.external_files) == 0:
|
||||
return
|
||||
if self.active_file.show_in_filelist:
|
||||
# Trigger the update callback, because that refreshes the SVN Log UI.
|
||||
self.external_files_active_index = self.external_files_active_index
|
||||
return
|
||||
|
||||
# Make sure the active file isn't now being filtered out.
|
||||
# If it is, change the active file to the first visible one.
|
||||
for i, file in enumerate(self.external_files):
|
||||
if file.show_in_filelist:
|
||||
self.external_files_active_index = i
|
||||
return
|
||||
|
||||
file_search_filter: StringProperty(
|
||||
name="Search Filter",
|
||||
description="Only show entries that contain this string",
|
||||
update=update_file_filter
|
||||
update=refresh_ui_lists
|
||||
)
|
||||
|
||||
|
||||
|
@ -277,8 +277,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)
|
||||
repo.refresh_ui_lists(context)
|
||||
|
||||
|
||||
def get_repo_file_statuses(svn_status_str: str) -> Dict[str, Tuple[str, str, int]]:
|
||||
|
@ -3,26 +3,10 @@
|
||||
|
||||
import bpy
|
||||
from bpy.types import Context, UIList, Operator
|
||||
from bpy.props import StringProperty
|
||||
from bpy.props import StringProperty, BoolProperty
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class SVN_OT_open_blend_file(Operator):
|
||||
# This is needed because drawing a button for wm.open_mainfile in the UI
|
||||
# directly simply does not work; Blender just opens a full-screen filebrowser,
|
||||
# instead of opening the .blend file. Probably a bug.
|
||||
bl_idname = "svn.open_blend_file"
|
||||
bl_label = "Open Blend File"
|
||||
bl_description = "Open Blend File"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
filepath: StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.wm.open_mainfile(filepath=self.filepath, load_ui=False)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def check_context_match(context: Context, uilayout_type: str, bl_idname: str) -> bool:
|
||||
"""For example, when right-clicking on a UIList, the uilayout_type will
|
||||
be `ui_list` and the bl_idname is that of the UIList being right-clicked.
|
||||
@ -39,8 +23,17 @@ def svn_file_list_context_menu(self: UIList, context: Context) -> None:
|
||||
layout.separator()
|
||||
active_file = context.scene.svn.get_repo(context).active_file
|
||||
if active_file.name.endswith("blend"):
|
||||
layout.operator("svn.open_blend_file",
|
||||
text=f"Open {active_file.name}").filepath = active_file.absolute_path
|
||||
op = layout.operator("wm.open_mainfile",
|
||||
text=f"Open {active_file.name}")
|
||||
op.filepath = active_file.absolute_path
|
||||
op.display_file_selector = False
|
||||
op.load_ui = True
|
||||
op = layout.operator("wm.open_mainfile",
|
||||
text=f"Open {active_file.name} (Keep UI)")
|
||||
op.filepath = active_file.absolute_path
|
||||
op.display_file_selector = False
|
||||
op.load_ui = False
|
||||
|
||||
else:
|
||||
layout.operator("wm.path_open",
|
||||
text=f"Open {active_file.name}").filepath = str(Path(active_file.absolute_path))
|
||||
@ -73,5 +66,3 @@ def unregister():
|
||||
bpy.types.UI_MT_list_item_context_menu.remove(svn_file_list_context_menu)
|
||||
bpy.types.UI_MT_list_item_context_menu.remove(svn_log_list_context_menu)
|
||||
|
||||
|
||||
registry = [SVN_OT_open_blend_file]
|
||||
|
@ -34,8 +34,8 @@ def draw_outdated_file_warning(self, context):
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.VIEW3D_HT_header.prepend(draw_outdated_file_warning)
|
||||
bpy.types.TOPBAR_MT_editor_menus.append(draw_outdated_file_warning)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.VIEW3D_HT_header.remove(draw_outdated_file_warning)
|
||||
bpy.types.TOPBAR_MT_editor_menus.remove(draw_outdated_file_warning)
|
||||
|
Loading…
Reference in New Issue
Block a user