check links copy path

1.7.7

- feat: add copy path to `check link` ops with multiple path representation choices
gpv2
Pullusb 2021-11-18 21:14:58 +01:00
parent 204553ed47
commit 9389faed22
3 changed files with 136 additions and 23 deletions

View File

@ -1,5 +1,9 @@
# Changelog
1.7.7
- feat: add copy path to `check link` ops with multiple path representation choices
1.7.6
- ui: expose (almost) all keymap added by the addon to allow user for customize/disable as needed

View File

@ -240,6 +240,80 @@ class GPTB_OT_file_checker(bpy.types.Operator):
return {"FINISHED"}
class GPTB_OT_copy_string_to_clipboard(bpy.types.Operator):
bl_idname = "gp.copy_string_to_clipboard"
bl_label = "Copy String"
bl_description = "Copy passed string to clipboard"
bl_options = {"REGISTER"}
string : bpy.props.StringProperty(options={'SKIP_SAVE'})
def execute(self, context):
if not self.string:
# self.report({'ERROR'}, 'Nothing to copy')
return {"CANCELLED"}
bpy.context.window_manager.clipboard = self.string
self.report({'INFO'}, f'Copied: {self.string}')
return {"FINISHED"}
class GPTB_OT_copy_multipath_clipboard(bpy.types.Operator):
bl_idname = "gp.copy_multipath_clipboard"
bl_label = "Choose Path to Copy"
bl_description = "Copy Chosen Path"
bl_options = {"REGISTER"}
string : bpy.props.StringProperty(options={'SKIP_SAVE'})
def invoke(self, context, event):
if not self.string:
return {"CANCELLED"}
self.pathes = []
try:
absolute = os.path.abspath(bpy.path.abspath(self.string))
abs_parent = os.path.dirname(os.path.abspath(bpy.path.abspath(self.string)))
path_abs = str(Path(bpy.path.abspath(self.string)).resolve())
except:
# case of invalid / non-accessable path
bpy.context.window_manager.clipboard = self.string
return context.window_manager.invoke_props_dialog(self, width=800)
self.pathes.append(('Raw Path', self.string))
self.pathes.append(('Parent', os.path.dirname(self.string)))
if absolute != self.string:
self.pathes.append(('Absolute', absolute))
if absolute != self.string:
self.pathes.append(('Absolute Parent', abs_parent))
if absolute != path_abs:
self.pathes.append(('Resolved',path_abs))
self.pathes.append(('File name', os.path.basename(self.string)))
maxlen = max(len(l[1]) for l in self.pathes)
popup_width = 800
if maxlen < 50:
popup_width = 500
elif maxlen > 100:
popup_width = 1000
return context.window_manager.invoke_props_dialog(self, width=popup_width)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.separator()
col = layout.column()
for l in self.pathes:
split=col.split(factor=0.2, align=True)
split.operator('gp.copy_string_to_clipboard', text=l[0], icon='COPYDOWN').string = l[1]
split.label(text=l[1])
def execute(self, context):
return {"FINISHED"}
class GPTB_OT_links_checker(bpy.types.Operator):
bl_idname = "gp.links_checker"
@ -267,14 +341,28 @@ class GPTB_OT_links_checker(bpy.types.Operator):
layout.separator()
# layout = layout.column() # thinner linespace
for l in self.all_lnks:
if l[1] == 'LIBRARY_DATA_BROKEN':
if l[1] == 'CANCEL':
layout.label(text=l[0], icon=l[1])
else:
split=layout.split(factor=0.75)
continue
if l[1] == 'LIBRARY_DATA_BROKEN':
split=layout.split(factor=0.85)
split.label(text=l[0], icon=l[1])
split.operator('wm.path_open', text='Open folder', icon='FILE_FOLDER').filepath = Path(bpy.path.abspath(l[0])).resolve().parent.as_posix()
split.operator('wm.path_open', text='Open file', icon='FILE_TICK').filepath = Path(bpy.path.abspath(l[0])).resolve().as_posix()#os.path.abspath(bpy.path.abspath(dirname(l[0])))
# layout.label(text=l[0], icon=l[1])
else:
split=layout.split(factor=0.75, align=True)
split.label(text=l[0], icon=l[1])
## resolve() return somethin different than os.path.abspath.
# split.operator('wm.path_open', text='Open folder', icon='FILE_FOLDER').filepath = Path(bpy.path.abspath(l[0])).resolve().parent.as_posix()
# split.operator('wm.path_open', text='Open file', icon='FILE_TICK').filepath = Path(bpy.path.abspath(l[0])).resolve().as_posix()
split.operator('wm.path_open', text='Open Folder', icon='FILE_FOLDER').filepath = Path(os.path.abspath(bpy.path.abspath(l[0]))).parent.as_posix()
split.operator('wm.path_open', text='Open File', icon='FILE_TICK').filepath = Path(os.path.abspath(bpy.path.abspath(l[0]))).as_posix()
split.operator('gp.copy_multipath_clipboard', text='Copy Path', icon='COPYDOWN').string = l[0]
# split.operator('gp.copy_string_to_clipboard', text='Copy Path', icon='COPYDOWN').string = l[0] # copy blend path directly
def invoke(self, context, event):
self.all_lnks = []
@ -283,19 +371,32 @@ class GPTB_OT_links_checker(bpy.types.Operator):
abs_ct = 0
rel_ct = 0
## check for broken links
viewed = []
for current, lib in zip(bpy.utils.blend_paths(local=True), bpy.utils.blend_paths(absolute=True, local=True)):
lfp = Path(lib)
realib = Path(current)
if not lfp.exists():
self.broke_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_BROKEN') )#lfp.as_posix()
else:
if realib.as_posix().startswith('//'):
rel_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LINKED') )#lfp.as_posix()
# avoid relisting same path mutliple times
if current in viewed:
continue
# TODO find a proper way to show the number of user of this path...
viewed.append(current)
realib = Path(current) # path as-is
lfp = Path(lib) # absolute path
try: # Try because some path may fail parsing
if not lfp.exists():
self.broke_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_BROKEN') )
else:
abs_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_INDIRECT') )#lfp.as_posix()
if realib.as_posix().startswith('//'):
rel_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LINKED') )
else:
abs_ct += 1
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_INDIRECT') )
except:
self.broke_ct += 1
self.all_lnks.append( (f"{current}" , 'CANCEL') ) # error accessing file
if not self.all_lnks:
self.report({'INFO'}, 'No external links in files')
@ -316,15 +417,21 @@ class GPTB_OT_links_checker(bpy.types.Operator):
else:
print(p[0])
# Show in viewport
maxlen = max(len(x) for x in viewed)
# if broke_ct == 0:
# show_message_box(self.all_lnks, _title = self.title, _icon = 'INFO')# Links
# return {"FINISHED"}
try:
self.proj = context.preferences.addons['pipe_sync'].preferences['local_folder']
except:
self.proj = None
return context.window_manager.invoke_props_dialog(self, width=800)
popup_width = 800
if maxlen < 50:
popup_width = 500
elif maxlen > 100:
popup_width = 1000
self.proj = os.environ.get('PROJECT_ROOT')
return context.window_manager.invoke_props_dialog(self, width=popup_width)
""" OLD links checker with show_message_box
class GPTB_OT_links_checker(bpy.types.Operator):
@ -501,6 +608,8 @@ classes = (
# GPTB_OT_check_scene,
GPTB_OT_list_object_visibility,
GPTB_OT_list_modifier_visibility,
GPTB_OT_copy_string_to_clipboard,
GPTB_OT_copy_multipath_clipboard,
GPTB_OT_file_checker,
GPTB_OT_links_checker,
)

View File

@ -15,7 +15,7 @@ bl_info = {
"name": "GP toolbox",
"description": "Set of tools for Grease Pencil in animation production",
"author": "Samuel Bernou, Christophe Seux",
"version": (1, 7, 6),
"version": (1, 7, 7),
"blender": (2, 91, 0),
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
"warning": "",