Blender SVN: New Features #273
@ -545,13 +545,12 @@ class SVN_OT_cleanup(SVN_Operator, Operator):
|
||||
class SVN_OT_cancel_running_operation(Operator):
|
||||
bl_idname = "svn.cancel"
|
||||
bl_label = "SVN Cancel Operation"
|
||||
bl_description = "Cancel the running operation"
|
||||
bl_description = "Cancel ongoing commit/update operation"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
def execute(self, context):
|
||||
Processes.kill('Commit')
|
||||
Processes.kill('Update')
|
||||
Processes.kill('List')
|
||||
return {'FINISHED'}
|
||||
|
||||
registry = [
|
||||
|
@ -168,16 +168,21 @@ class SVN_file(PropertyGroup):
|
||||
|
||||
### File size - Update a string representation one time when file_size_KiB is set. ###
|
||||
### We want to avoid re-calculating that string on every re-draw for optimization. ###
|
||||
def get_file_size(self):
|
||||
def get_file_size_ui_str(self):
|
||||
num = self.file_size_KiB
|
||||
for unit in ("KiB", "MiB", "GiB", "TiB", "PiB", "EiB"):
|
||||
if num < 1024:
|
||||
return f"{num:3.1f} {unit}"
|
||||
num_digits = len(str(num).split(".")[0])
|
||||
file_size = f"{num:0.{max(0, 3-num_digits)}f} {unit}"
|
||||
if "." not in file_size:
|
||||
file_size = file_size.replace(" ", " ")
|
||||
return file_size
|
||||
num /= 1024.0
|
||||
return f"{num:.1f} YiB"
|
||||
|
||||
return "Really Big"
|
||||
|
||||
def update_file_size(self, _context):
|
||||
self.file_size = self.get_file_size()
|
||||
self.file_size = self.get_file_size_ui_str()
|
||||
|
||||
file_size_KiB: FloatProperty(description="One KibiByte (KiB) is 1024 bytes", update=update_file_size)
|
||||
file_size: StringProperty(description="File size for displaying in the UI")
|
||||
@ -531,6 +536,30 @@ class SVN_repository(PropertyGroup):
|
||||
for log_entry in self.log]
|
||||
)
|
||||
|
||||
def get_root_subdirs(self):
|
||||
for f in self.external_files:
|
||||
if not self.get_parent_file(f):
|
||||
yield f
|
||||
|
||||
def find_dir_children(self, dir: SVN_file):
|
||||
for f in self.external_files:
|
||||
if self.get_parent_file(f) == dir:
|
||||
yield f
|
||||
|
||||
def calculate_folder_sizes(self):
|
||||
for root_subdir in self.get_root_subdirs():
|
||||
self.calculate_folder_size_recursive(root_subdir)
|
||||
|
||||
def calculate_folder_size_recursive(self, dir: SVN_file):
|
||||
size = 0
|
||||
for child in self.find_dir_children(dir):
|
||||
if child.is_dir:
|
||||
self.calculate_folder_size_recursive(child)
|
||||
size += child.file_size_KiB
|
||||
|
||||
dir.file_size_KiB = size
|
||||
return size
|
||||
|
||||
prev_external_files_active_index: IntProperty(
|
||||
name="Previous Active Index",
|
||||
description="Internal value to avoid triggering the update callback unnecessarily",
|
||||
@ -645,6 +674,11 @@ class SVN_repository(PropertyGroup):
|
||||
update=refresh_ui_lists
|
||||
)
|
||||
|
||||
show_file_size: BoolProperty(
|
||||
name="Show Size On Disk",
|
||||
description="Show size of each file and aggregate size of folders",
|
||||
default=False
|
||||
)
|
||||
show_file_paths: BoolProperty(
|
||||
name="Show File Paths",
|
||||
description="Show file paths relative to the SVN root, instead of just the file name"
|
||||
@ -659,8 +693,8 @@ class SVN_repository(PropertyGroup):
|
||||
name="File Display Mode",
|
||||
description="Whether the full file tree sould be drawn instead of just modified files as a flat list",
|
||||
items=[
|
||||
('FLAT', "Modifications", "Display only modified files as a flat list", 'PRESET', 0),
|
||||
('TREE', "Tree View", "Display the full tree of the entire repository", 'OUTLINER', 1),
|
||||
('FLAT', "Changes", "Display only modified files as a flat list", 'PRESET', 0),
|
||||
('TREE', "File Tree", "Display the full tree of the entire repository", 'OUTLINER', 1),
|
||||
],
|
||||
update=update_tree_display
|
||||
)
|
||||
|
@ -179,7 +179,7 @@ class BGP_SVN_List(BackgroundProcess):
|
||||
def acquire_output(self, context, prefs):
|
||||
self.output = execute_svn_command(
|
||||
context,
|
||||
["svn", "list", "--recursive", "--xml"],
|
||||
["svn", "list", "--recursive", "--xml", "-r", "HEAD"],
|
||||
use_cred=True,
|
||||
)
|
||||
|
||||
@ -296,6 +296,8 @@ def update_file_list_svn_status(context, file_statuses: Dict[str, Tuple[str, str
|
||||
"\nUpdating log...\n",
|
||||
)
|
||||
Processes.start('Log')
|
||||
|
||||
if any([not f.is_dir and not f.file_size_KiB for f in repo.external_files]):
|
||||
Processes.start('List')
|
||||
|
||||
# Remove file entries who no longer seem to have an SVN status.
|
||||
@ -372,6 +374,9 @@ def update_file_list_svn_list(context, svn_list_str: str) -> Dict:
|
||||
if kind == 'file':
|
||||
file_entry.file_size_KiB = float(file_info['size']) / 1024.0
|
||||
|
||||
# Calculate size of folders.
|
||||
repo.calculate_folder_sizes()
|
||||
|
||||
|
||||
@bpy.app.handlers.persistent
|
||||
def mark_current_file_as_modified(_dummy1=None, _dummy2=None):
|
||||
|
@ -5,12 +5,28 @@ import time
|
||||
|
||||
import bpy
|
||||
from bpy.types import UIList
|
||||
from bpy.props import BoolProperty
|
||||
|
||||
from .. import constants
|
||||
from ..util import get_addon_prefs, dots
|
||||
from ..threaded.background_process import Processes
|
||||
|
||||
def file_list_ui_split(layout, context):
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
main_split = layout.split(factor=0.9)
|
||||
left_side = main_split.row()
|
||||
|
||||
filepath_ui = left_side.row()
|
||||
if repo.show_file_size:
|
||||
filesize_ui = layout.row()
|
||||
filesize_ui.alignment='RIGHT'
|
||||
else:
|
||||
filesize_ui = None
|
||||
status_ui = layout.row(align=True)
|
||||
status_ui.alignment='RIGHT'
|
||||
ops_ui = layout.row(align=True)
|
||||
|
||||
return filepath_ui, filesize_ui, status_ui, ops_ui
|
||||
|
||||
|
||||
class SVN_UL_file_list(UIList):
|
||||
# Value that indicates that this item has passed the filter process successfully. See rna_ui.c.
|
||||
@ -26,20 +42,13 @@ class SVN_UL_file_list(UIList):
|
||||
file_entry = item
|
||||
prefs = get_addon_prefs(context)
|
||||
|
||||
main_row = layout.row()
|
||||
split = main_row.split(factor=0.6)
|
||||
filepath_ui = split.row()
|
||||
split = split.split(factor=0.4)
|
||||
status_ui = split.row(align=True)
|
||||
|
||||
ops_ui = split.row(align=True)
|
||||
ops_ui.alignment = 'RIGHT'
|
||||
filepath_ui, filesize_ui, status_ui, ops_ui = file_list_ui_split(layout, context)
|
||||
|
||||
ops_ui.enabled = file_entry.status_prediction_type == 'NONE' and not prefs.is_busy
|
||||
|
||||
if repo.display_mode == 'TREE':
|
||||
split = filepath_ui.split(factor=0.05 * file_entry.tree_depth + 0.00001)
|
||||
split.row()
|
||||
split.label()
|
||||
row = split.row(align=True)
|
||||
filepath_ui = row.row(align=True)
|
||||
if file_entry.has_children:
|
||||
@ -53,6 +62,29 @@ class SVN_UL_file_list(UIList):
|
||||
else:
|
||||
filepath_ui.label(text=file_entry.file_name, icon=file_entry.file_icon)
|
||||
|
||||
if repo.show_file_size:
|
||||
icon_map = {
|
||||
'KiB' : 'DECORATE',
|
||||
'MiB' : 'RADIOBUT_ON',
|
||||
'GiB' : 'SHADING_SOLID',
|
||||
'TiB' : 'SHADING_SOLID',
|
||||
'PiB' : 'SHADING_SOLID',
|
||||
'EiB' : 'SHADING_SOLID',
|
||||
}
|
||||
icon = 'BLANK1 '
|
||||
if file_entry.file_size_KiB == 0:
|
||||
icon = 'BLANK1'
|
||||
text=" "
|
||||
else:
|
||||
icon = icon_map[file_entry.file_size[-3:]]
|
||||
text=file_entry.file_size
|
||||
width = get_sidebar_width(context)
|
||||
if width < 800:
|
||||
text = text.replace("iB", "")
|
||||
filesize_ui.label(text=text)
|
||||
else:
|
||||
filesize_ui.label(text=text, icon=icon)
|
||||
|
||||
statuses = [file_entry.status]
|
||||
# SVN operations
|
||||
ops = []
|
||||
@ -114,10 +146,16 @@ class SVN_UL_file_list(UIList):
|
||||
op.popup=True
|
||||
ops.append(op)
|
||||
|
||||
for i in range(max(0, 2-len(ops))):
|
||||
ops_ui.label(text="", icon='BLANK1')
|
||||
|
||||
for op in ops:
|
||||
if hasattr(op, 'file_rel_path'):
|
||||
op.file_rel_path = file_entry.svn_path
|
||||
|
||||
for i in range(max(0, 2-len(statuses))):
|
||||
status_ui.label(text="", icon='BLANK1')
|
||||
|
||||
# Populate the status icons.
|
||||
for status in statuses:
|
||||
icon = constants.SVN_STATUS_DATA[status][0]
|
||||
@ -167,8 +205,6 @@ class SVN_UL_file_list(UIList):
|
||||
|
||||
def draw_process_info(context, layout):
|
||||
prefs = get_addon_prefs(context)
|
||||
process_message = ""
|
||||
any_error = False
|
||||
col = layout.column()
|
||||
for process in Processes.processes.values():
|
||||
if process.name in {'Redraw Viewport', 'Activate File'}:
|
||||
@ -180,17 +216,14 @@ def draw_process_info(context, layout):
|
||||
warning = row.operator(
|
||||
'svn.clear_error', text=f"SVN {process.name}: Error Occurred. Hover to view", icon='ERROR')
|
||||
warning.process_id = process.name
|
||||
any_error = True
|
||||
break
|
||||
continue
|
||||
|
||||
if process.is_running:
|
||||
message = process.get_ui_message(context)
|
||||
if message:
|
||||
message = message.replace("...", dots())
|
||||
process_message = f"SVN: {message}"
|
||||
col.label(text=message)
|
||||
|
||||
if not any_error and process_message:
|
||||
col.label(text=process_message)
|
||||
if prefs.debug_mode:
|
||||
col.label(text="Processes: " +
|
||||
", ".join([p.name for p in Processes.running_processes]))
|
||||
@ -204,24 +237,24 @@ class SVN_PT_filelist_options(bpy.types.Panel):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
prefs = get_addon_prefs(context)
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
|
||||
layout.label(text="Display Mode:")
|
||||
layout.prop(repo, 'display_mode', text=" ", expand=True)
|
||||
|
||||
layout.use_property_split=True
|
||||
layout.use_property_decorate=False
|
||||
layout.ui_units_x = 17.0
|
||||
|
||||
repo = context.scene.svn.get_repo(context)
|
||||
|
||||
layout.prop(repo, 'display_mode', text="Display Mode", expand=True)
|
||||
|
||||
file_paths = layout.row()
|
||||
file_paths.enabled = repo.display_mode == 'FLAT'
|
||||
file_paths.prop(repo, 'show_file_paths')
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.prop(prefs, 'do_auto_updates', icon='TEMP')
|
||||
layout.row().prop(repo, 'show_file_size')
|
||||
|
||||
def get_sidebar_width(context) -> float:
|
||||
for region in context.area.regions:
|
||||
if region.type == 'UI':
|
||||
return region.width
|
||||
|
||||
def draw_file_list(context, layout):
|
||||
prefs = get_addon_prefs(context)
|
||||
@ -235,20 +268,25 @@ def draw_file_list(context, layout):
|
||||
row.label(text="Repository is not authenticated.", icon='ERROR')
|
||||
return
|
||||
|
||||
main_col = layout.column()
|
||||
main_row = main_col.row()
|
||||
split = main_row.split(factor=0.6)
|
||||
filepath_row = split.row()
|
||||
filepath_row.label(text=" Filepath")
|
||||
width = get_sidebar_width(context)
|
||||
layout.label(text=str(width))
|
||||
|
||||
status_row = split.row()
|
||||
status_row.label(text=" Status")
|
||||
top_row = layout.row()
|
||||
box = top_row.box().row()
|
||||
filepath_ui, filesize_ui, status_ui, ops_ui = file_list_ui_split(box, context)
|
||||
filepath_ui.alignment='CENTER'
|
||||
filepath_ui.label(text="File")
|
||||
|
||||
ops_row = main_row.row()
|
||||
ops_row.alignment = 'RIGHT'
|
||||
ops_row.label(text="Operations")
|
||||
if repo.show_file_size:
|
||||
filesize_ui.label(text="Size")
|
||||
status_ui.label(text="Status")
|
||||
|
||||
row = main_col.row()
|
||||
ops_ui.alignment = 'RIGHT'
|
||||
ops_ui.label(text="Actions")
|
||||
|
||||
top_row.column().prop(prefs, 'do_auto_updates', text="", icon='TEMP')
|
||||
|
||||
row = layout.row()
|
||||
row.template_list(
|
||||
"SVN_UL_file_list",
|
||||
"svn_file_list",
|
||||
|
@ -53,8 +53,8 @@ class VIEW3D_PT_svn_files(Panel):
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
draw_process_info(context, layout)
|
||||
draw_file_list(context, layout)
|
||||
draw_process_info(context, layout)
|
||||
|
||||
|
||||
registry = [
|
||||
|
Loading…
Reference in New Issue
Block a user