Files
blender-portable-repo/scripts/addons/blender_svn/ui/ui_log.py
T
2026-03-17 14:58:51 -06:00

280 lines
8.8 KiB
Python

# SPDX-FileCopyrightText: 2023 Blender Studio Tools Authors
#
# SPDX-License-Identifier: GPL-3.0-or-later
from bpy.props import IntProperty, BoolProperty
from bpy.types import UIList, Panel, Operator
from ..util import get_addon_prefs
class SVN_UL_log(UIList):
show_all_logs: BoolProperty(
name='Show All Logs',
description='Show the complete SVN Log, instead of only entries that affected the currently selected file',
default=False
)
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if self.layout_type != 'DEFAULT':
raise NotImplemented
svn = data
log_entry = item
num, auth, date, msg = layout_log_split(layout.row())
active_file = svn.active_file
num.label(text=str(log_entry.revision_number))
if item.revision_number == active_file.revision:
num.operator('svn.tooltip_log', text="", icon='LAYER_ACTIVE',
emboss=False).log_rev = log_entry.revision_number
elif log_entry.changes_file(active_file):
get_older = num.operator(
'svn.download_file_revision', text="", icon='IMPORT', emboss=False)
get_older.revision = log_entry.revision_number
get_older.file_rel_path = active_file.svn_path
auth.label(text=log_entry.revision_author)
date.label(text=log_entry.revision_date_simple)
commit_msg = log_entry.commit_message
commit_msg = commit_msg.split(
"\n")[0] if "\n" in commit_msg else commit_msg
commit_msg = commit_msg[:50] + \
"..." if len(commit_msg) > 52 else commit_msg
msg.alignment = 'LEFT'
msg.operator("svn.display_commit_message", text=commit_msg,
emboss=False).log_rev = log_entry.revision_number
def filter_items(self, context, data, propname):
"""Custom filtering functionality:
- Always sort by descending revision number
- Allow searching for various criteria
"""
svn = data
log_entries = getattr(data, propname)
# Start off with all entries flagged as visible.
flt_flags = [self.bitflag_filter_item] * len(log_entries)
# Always sort by descending revision number
flt_neworder = sorted(range(len(log_entries)),
key=lambda i: log_entries[i].revision_number)
flt_neworder.reverse()
if not self.show_all_logs:
flt_flags = [
log_entry.affects_active_file * self.bitflag_filter_item
for log_entry in log_entries
]
if self.filter_name:
# Filtering: Allow comma-separated keywords.
# ALL keywords must be found somewhere in the log entry for it to show up.
filter_words = [word.strip().lower()
for word in self.filter_name.split(",")]
for idx, log_entry in enumerate(log_entries):
for filter_word in filter_words:
if filter_word not in log_entry.text_to_search:
flt_flags[idx] = 0
break
return flt_flags, flt_neworder
def draw_filter(self, context, layout):
"""Custom filtering UI.
"""
main_row = layout.row()
main_row.prop(self, 'filter_name', text="")
main_row.prop(self, 'show_all_logs', text="",
toggle=True, icon='ALIGN_JUSTIFY')
def is_log_useful(context) -> bool:
"""Return whether the log has any useful info to display."""
prefs = get_addon_prefs(context)
repo = prefs.active_repo
if not repo or not repo.authenticated:
return False
if len(repo.log) == 0 or len(repo.external_files) == 0:
return False
active_file = repo.active_file
if active_file.status in ['unversioned', 'added']:
return False
any_visible = any([file.show_in_filelist for file in repo.external_files])
if not any_visible:
return False
return True
class VIEW3D_PT_svn_log(Panel):
"""Display the revision history of the selected file."""
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'SVN'
bl_label = 'Revision History'
bl_parent_id = "VIEW3D_PT_svn_files"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return is_log_useful(context)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
draw_svn_log(context, layout)
def layout_log_split(layout):
main = layout.split(factor=0.4)
num_and_auth = main.row()
date_and_msg = main.row()
num_and_auth_split = num_and_auth.split(factor=0.5)
num = num_and_auth_split.row()
auth = num_and_auth_split.row()
date_and_msg_split = date_and_msg.split(factor=0.3)
date = date_and_msg_split.row()
msg = date_and_msg_split.row()
return num, auth, date, msg
def draw_svn_log(context, layout):
num, auth, date, msg = layout_log_split(layout.row())
num.label(text="Rev. #")
auth.label(text="Author")
date.label(text="Date")
msg.label(text="Message")
prefs = get_addon_prefs(context)
repo = prefs.active_repo
layout.template_list(
"SVN_UL_log",
"svn_log",
repo,
"log",
repo,
"log_active_index",
)
active_log = repo.active_log
if not active_log:
return
layout.label(text="Revision Date: " + active_log.revision_date)
layout.label(
text=f"Files changed in revision `r{active_log.revision_number}`:")
col = layout.column(align=True)
row = col.row()
split = row.split(factor=0.80)
split.label(text=" Filepath")
row = split.row()
row.alignment = 'RIGHT'
row.label(text="Action")
for f in active_log.changed_files:
row = col.row()
split = row.split(factor=0.90)
split.prop(f, 'name', emboss=False, text="", icon=f.file_icon)
row = split.row()
row.alignment = 'RIGHT'
row.operator('svn.explain_status', text="",
icon=f.status_icon, emboss=False).status = f.status
def execute_tooltip_log(self, context):
"""Set the index on click, to act as if this operator button was
click-through in the UIList."""
repo = context.scene.svn.get_repo(context)
tup = repo.get_log_by_revision(self.log_rev)
if tup:
repo.log_active_index = tup[0]
return {'FINISHED'}
class SVN_OT_log_tooltip(Operator):
bl_idname = "svn.tooltip_log"
bl_label = "" # Don't want the first line of the tooltip on mouse hover.
# bl_description = "An operator to be drawn in the log list, that can display a dynamic tooltip"
bl_options = {'INTERNAL'}
log_rev: IntProperty(
description="Revision number of the log entry to show in the tooltip"
)
@classmethod
def description(cls, context, properties):
return "This is the currently checked out version of the file"
execute = execute_tooltip_log
class SVN_OT_log_show_commit_msg(Operator):
bl_idname = "svn.display_commit_message"
bl_label = "" # Don't want the first line of the tooltip on mouse hover.
# bl_description = "Show the currently active commit, using a dynamic tooltip"
bl_options = {'INTERNAL'}
log_rev: IntProperty(
description="Revision number of the log entry to show in the tooltip"
)
@classmethod
def description(cls, context, properties):
log_entry = context.scene.svn.get_repo(context).get_log_by_revision(properties.log_rev)[
1]
commit_msg = log_entry.commit_message
# Prettify the tooltips.
pretty_msg = ""
for line in commit_msg.split("\n"):
# Remove leading/trailing whitespace
line = line.strip()
# Add punctuation mark
if not (line.endswith(".") or line.endswith("!") or line.endswith("?")):
line = line + "."
# Split long lines into several
limit = 300
if len(line) > limit:
words = line.split(" ")
sub_lines = []
new_line = ""
for word in words:
if len(new_line) + len(word) < limit:
new_line += " "+word
else:
sub_lines.append(new_line)
new_line = word
else:
sub_lines.append(new_line)
line = "\n".join(sub_lines)
pretty_msg += "\n"+line
# Remove last period because Blender adds it.
if pretty_msg.endswith("."):
pretty_msg = pretty_msg[:-1]
return pretty_msg
execute = execute_tooltip_log
registry = [
VIEW3D_PT_svn_log,
SVN_UL_log,
SVN_OT_log_tooltip,
SVN_OT_log_show_commit_msg
]