SVN: UX improvements #136
@ -445,6 +445,7 @@ class SVN_OT_cleanup(SVN_Operator, Operator):
|
||||
|
||||
Processes.restart('Status')
|
||||
Processes.restart('Log')
|
||||
Processes.restart('Redraw Viewport')
|
||||
|
||||
self.report({'INFO'}, "SVN Cleanup complete.")
|
||||
|
||||
|
@ -28,7 +28,6 @@ class SVN_OT_checkout_initiate(Operator):
|
||||
|
||||
def execute(self, context):
|
||||
prefs = get_addon_prefs(context)
|
||||
prefs.active_repo_mode = 'SELECTED_REPO'
|
||||
if self.create:
|
||||
prefs.repositories.add()
|
||||
prefs.active_repo_idx = len(prefs.repositories)-1
|
||||
|
@ -46,39 +46,29 @@ class SVN_addon_preferences(AddonPreferences):
|
||||
|
||||
repo = self.repositories.add()
|
||||
repo.initialize(root_dir, base_url)
|
||||
self.active_repo_idx = len(self.repositories)-1
|
||||
|
||||
return repo
|
||||
|
||||
def update_active_repo_idx(self, context):
|
||||
if self.idx_updating or len(self.repositories) == 0:
|
||||
if len(self.repositories) == 0:
|
||||
return
|
||||
self.idx_updating = True
|
||||
active_repo = self.active_repo
|
||||
if self.active_repo_mode == 'CURRENT_BLEND':
|
||||
scene_svn = context.scene.svn
|
||||
scene_svn_idx = self.repositories.find(scene_svn.svn_directory)
|
||||
if scene_svn_idx == -1:
|
||||
self.idx_updating = False
|
||||
return
|
||||
self.active_repo_idx = scene_svn_idx
|
||||
self.idx_updating = False
|
||||
return
|
||||
|
||||
# Authenticate when switching repos.
|
||||
if (
|
||||
active_repo and
|
||||
not active_repo.authenticated and
|
||||
not active_repo.auth_failed and
|
||||
active_repo.is_cred_entered
|
||||
):
|
||||
active_repo.authenticate(context)
|
||||
Processes.start('Redraw Viewport')
|
||||
if active_repo.authenticated:
|
||||
Processes.restart('Status')
|
||||
else:
|
||||
active_repo.authenticate(context)
|
||||
else:
|
||||
Processes.kill('Status')
|
||||
|
||||
self.idx_updating = False
|
||||
|
||||
def update_active_repo_mode(self, context):
|
||||
if self.active_repo_mode == 'CURRENT_BLEND':
|
||||
scene_svn = context.scene.svn
|
||||
scene_svn_idx = self.repositories.find(scene_svn.svn_directory)
|
||||
self.active_repo_idx = scene_svn_idx
|
||||
|
||||
checkout_mode: BoolProperty(
|
||||
name="Checkout In Progress",
|
||||
@ -86,30 +76,16 @@ class SVN_addon_preferences(AddonPreferences):
|
||||
default=False
|
||||
)
|
||||
|
||||
active_repo_mode: EnumProperty(
|
||||
name="Choose Repository",
|
||||
description="Whether the add-on should communicate with the repository of the currently opened .blend file, or the repository selected in the list below",
|
||||
items=[
|
||||
('CURRENT_BLEND', "Current Blend", "Check if the current .blend file is in an SVN repository, and communicate with that if that is the case. The file list will display only the files of the repository of the current .blend file. If the current .blend is not in a repository, do nothing"),
|
||||
('SELECTED_REPO', "Selected Repo",
|
||||
"Communicate with the selected repository")
|
||||
],
|
||||
default='CURRENT_BLEND',
|
||||
update=update_active_repo_mode
|
||||
)
|
||||
|
||||
active_repo_idx: IntProperty(
|
||||
name="SVN Repositories",
|
||||
options=set(),
|
||||
update=update_active_repo_idx
|
||||
)
|
||||
idx_updating: BoolProperty(
|
||||
name="Index is Updating",
|
||||
description="Helper flag to avoid infinite looping update callbacks",
|
||||
)
|
||||
|
||||
@property
|
||||
def active_repo(self) -> SVN_repository:
|
||||
def active_repo(self) -> Optional[SVN_repository]:
|
||||
if not self.is_svn_installed:
|
||||
return
|
||||
if 0 <= self.active_repo_idx <= len(self.repositories)-1:
|
||||
return self.repositories[self.active_repo_idx]
|
||||
|
||||
|
@ -28,33 +28,10 @@ class SVN_scene_properties(PropertyGroup):
|
||||
)
|
||||
|
||||
def get_repo(self, context) -> Optional['SVN_repository']:
|
||||
"""Return the current repository.
|
||||
Depending on preferences, this is either the repo the current .blend file is in,
|
||||
or whatever repo is selected in the preferences UI.
|
||||
"""
|
||||
"""Return the active repository."""
|
||||
prefs = get_addon_prefs(context)
|
||||
if not prefs.is_svn_installed:
|
||||
return
|
||||
return prefs.active_repo
|
||||
|
||||
if prefs.active_repo_mode == 'CURRENT_BLEND':
|
||||
return self.get_scene_repo(context)
|
||||
else:
|
||||
return prefs.active_repo
|
||||
|
||||
def get_scene_repo(self, context) -> Optional['SVN_repository']:
|
||||
"""Return the repository of the current file, even if the add-on is
|
||||
configured to another repository.
|
||||
"""
|
||||
prefs = get_addon_prefs(context)
|
||||
if not prefs.is_svn_installed:
|
||||
return
|
||||
|
||||
if not self.svn_url or not self.svn_directory:
|
||||
return
|
||||
|
||||
for repo in prefs.repositories:
|
||||
if (repo.url == self.svn_url) and (Path(repo.directory) == Path(self.svn_directory)):
|
||||
return repo
|
||||
|
||||
registry = [
|
||||
SVN_scene_properties,
|
||||
|
@ -305,9 +305,9 @@ class SVN_repository(PropertyGroup):
|
||||
)
|
||||
|
||||
@property
|
||||
def is_cred_entered(self):
|
||||
def is_cred_entered(self) -> bool:
|
||||
"""Check if there's a username and password entered at all."""
|
||||
return self.username and self.password
|
||||
return bool(self.username and self.password)
|
||||
|
||||
authenticated: BoolProperty(
|
||||
name="Authenticated",
|
||||
|
@ -44,7 +44,7 @@ class BackgroundProcess:
|
||||
# Displayed in the tooltip on mouse-hover in the error message when an error occurs.
|
||||
error_description = "SVN Error:"
|
||||
|
||||
debug = True
|
||||
debug = False
|
||||
|
||||
def debug_print(self, msg: str):
|
||||
if self.debug:
|
||||
@ -82,7 +82,7 @@ class BackgroundProcess:
|
||||
def handle_error(self, context, error):
|
||||
self.output = ""
|
||||
self.error = error.stderr.decode()
|
||||
self.is_running = False
|
||||
self.stop()
|
||||
|
||||
def process_output(self, context, prefs):
|
||||
"""
|
||||
@ -113,7 +113,7 @@ class BackgroundProcess:
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
if not repo:
|
||||
self.debug_print("Shutdown: Not in repo.")
|
||||
self.is_running = False
|
||||
self.stop()
|
||||
return
|
||||
|
||||
prefs = get_addon_prefs(context)
|
||||
@ -127,7 +127,7 @@ class BackgroundProcess:
|
||||
|
||||
if self.needs_authentication and not repo.authenticated:
|
||||
self.debug_print("Shutdown: Authentication needed.")
|
||||
self.is_running = False
|
||||
self.stop()
|
||||
return
|
||||
|
||||
if not self.thread or not self.thread.is_alive() and not self.output and not self.error:
|
||||
@ -146,15 +146,14 @@ class BackgroundProcess:
|
||||
self.output = ""
|
||||
redraw_viewport()
|
||||
if self.repeat_delay == 0:
|
||||
self.debug_print(
|
||||
"Shutdown: Output was processed, repeat_delay==0.")
|
||||
self.is_running = False
|
||||
self.debug_print("Shutdown: Output was processed, repeat_delay==0.")
|
||||
self.stop()
|
||||
return
|
||||
self.debug_print(f"Processed output. Waiting {self.repeat_delay}")
|
||||
return self.repeat_delay
|
||||
elif not self.thread and not self.thread.is_alive() and self.repeat_delay == 0:
|
||||
self.debug_print("Shutdown: Finished.\n")
|
||||
self.is_running = False
|
||||
self.stop()
|
||||
return
|
||||
|
||||
self.debug_print(f"Tick delay: {self.tick_delay}")
|
||||
@ -188,6 +187,7 @@ class BackgroundProcess:
|
||||
|
||||
def stop(self):
|
||||
"""Stop the process if it isn't running, by unregistering its timer function"""
|
||||
self.debug_print("stop() function was called.")
|
||||
self.is_running = False
|
||||
if bpy.app.timers.is_registered(self.timer_function):
|
||||
# This won't work if the timer has returned None at any point, as that
|
||||
|
@ -7,6 +7,7 @@ class BGP_SVN_Redraw_Viewport(BackgroundProcess):
|
||||
repeat_delay = 1
|
||||
debug = False
|
||||
tick_delay = 1
|
||||
needs_authentication = False
|
||||
|
||||
def tick(self, context, prefs):
|
||||
redraw_viewport()
|
||||
|
@ -56,13 +56,12 @@ class SVN_OT_explain_status(Operator):
|
||||
|
||||
@bpy.app.handlers.persistent
|
||||
def ensure_svn_of_current_file(_scene=None):
|
||||
"""When opening or saving a .blend file, it's possible that the new .blend
|
||||
"""When opening or saving a .blend file, it's possible that the new .blend
|
||||
is part of an SVN repository. If this is the case, do the following:
|
||||
- Initialize SVN Scene info
|
||||
- Initialize Repository
|
||||
- Try to authenticate
|
||||
- Check if this file's repository is already in our database
|
||||
- If not, create it
|
||||
- Switch to that repo
|
||||
"""
|
||||
|
||||
context = bpy.context
|
||||
prefs = get_addon_prefs(context)
|
||||
prefs.is_svn_installed = check_svn_installed()
|
||||
@ -71,52 +70,42 @@ def ensure_svn_of_current_file(_scene=None):
|
||||
|
||||
scene_svn = context.scene.svn
|
||||
|
||||
# If we have any repository entries, make sure at least one is active.
|
||||
prefs.sync_repo_info_file()
|
||||
|
||||
if prefs.active_repo_idx == -1 and len(prefs.repositories) > 0:
|
||||
prefs.active_repo_idx = 0
|
||||
elif prefs.active_repo_idx > len(prefs.repositories)-1:
|
||||
prefs.active_repo_idx = 0
|
||||
else:
|
||||
prefs.active_repo_idx = prefs.active_repo_idx
|
||||
|
||||
repo = prefs.active_repo
|
||||
if repo and repo.is_cred_entered and repo.authenticated:
|
||||
status = Processes.get('Status')
|
||||
if status and time.time() - status.timestamp_last_update < status.repeat_delay + 5:
|
||||
# If the SVN Status background process has recently processed data,
|
||||
# there is no need to re-initialize everything.
|
||||
# This happens when a file that was already saved is saved again,
|
||||
# or a file from the same repository as the previous one is loaded.
|
||||
Processes.restart('Status')
|
||||
return
|
||||
# If the file is unsaved, nothing more to do.
|
||||
if not bpy.data.filepath:
|
||||
scene_svn.svn_url = ""
|
||||
return
|
||||
|
||||
# If file is not in a repo, nothing more to do.
|
||||
is_in_repo = set_scene_svn_info(context)
|
||||
if not is_in_repo:
|
||||
return
|
||||
|
||||
# If we switched repos, reset auth flags and authenticate the new repo.
|
||||
for repo in prefs.repositories:
|
||||
# This would ideally only run when opening Blender for the first
|
||||
# time, but there is no app handler for that, sadly.
|
||||
repo.authenticated = False
|
||||
repo.auth_failed = False
|
||||
|
||||
if prefs.active_repo_mode == 'CURRENT_BLEND':
|
||||
if not bpy.data.filepath:
|
||||
scene_svn.svn_url = ""
|
||||
return
|
||||
|
||||
is_in_repo = set_scene_svn_info(context)
|
||||
if not is_in_repo:
|
||||
return
|
||||
|
||||
repo = scene_svn.get_scene_repo(context)
|
||||
if not repo:
|
||||
repo = prefs.init_repo(context, scene_svn.svn_directory)
|
||||
|
||||
for i, other_repo in enumerate(prefs.repositories):
|
||||
if other_repo == repo:
|
||||
prefs.active_repo_idx = i
|
||||
|
||||
# If file is in an existing repo, we should switch over to that repo.
|
||||
for i, existing_repo in enumerate(prefs.repositories):
|
||||
if ( existing_repo.url == scene_svn.svn_url and
|
||||
existing_repo.directory == scene_svn.svn_directory
|
||||
):
|
||||
prefs.active_repo_idx = i
|
||||
break
|
||||
else:
|
||||
repo = prefs.active_repo
|
||||
if not repo:
|
||||
return
|
||||
|
||||
if repo.is_cred_entered:
|
||||
repo.authenticate(context)
|
||||
# If file is in a non-existing repo, initialize that repo.
|
||||
repo = prefs.init_repo(context, scene_svn.svn_directory)
|
||||
|
||||
|
||||
def set_scene_svn_info(context) -> bool:
|
||||
|
@ -18,9 +18,6 @@ class SVN_UL_repositories(UIList):
|
||||
repo = item
|
||||
row = layout.row()
|
||||
|
||||
prefs = get_addon_prefs(context)
|
||||
if prefs.active_repo_mode == 'CURRENT_BLEND' and repo != context.scene.svn.get_repo(context):
|
||||
row.enabled = False
|
||||
row.label(text=repo.display_name)
|
||||
|
||||
if not repo.dir_exists:
|
||||
@ -198,10 +195,6 @@ def draw_prefs_checkout(self, context):
|
||||
def draw_prefs_repos(self, context) -> None:
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.use_property_split = True
|
||||
row.prop(self, 'active_repo_mode', expand=True)
|
||||
|
||||
auth_in_progress = False
|
||||
auth_error = False
|
||||
auth_proc = Processes.get('Authenticate')
|
||||
@ -209,12 +202,6 @@ def draw_prefs_repos(self, context) -> None:
|
||||
auth_in_progress = auth_proc.is_running
|
||||
auth_error = auth_proc.error
|
||||
|
||||
if self.active_repo_mode == 'CURRENT_BLEND' and not context.scene.svn.get_repo(context):
|
||||
split = layout.split(factor=0.4)
|
||||
split.row()
|
||||
split.row().label(text="Current file is not in a repository.")
|
||||
return
|
||||
|
||||
repo_col = layout.column()
|
||||
split = repo_col.row().split()
|
||||
split.row().label(text="SVN Repositories:")
|
||||
|
@ -16,12 +16,7 @@ class VIEW3D_PT_svn_credentials(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
prefs = get_addon_prefs(context)
|
||||
if prefs.active_repo_mode == 'CURRENT_BLEND':
|
||||
repo = context.scene.svn.get_scene_repo(context)
|
||||
else:
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
return repo and not repo.authenticated
|
||||
|
||||
def draw(self, context):
|
||||
|
Loading…
Reference in New Issue
Block a user