Skip to content

Commit

Permalink
Loads and saves files to/from QLC! Can move functions across!
Browse files Browse the repository at this point in the history
This might actually work.
  • Loading branch information
danthedeckie authored Apr 5, 2019
1 parent 510b67b commit 779e43a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 20 deletions.
60 changes: 54 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,58 @@
# QLC-File-Ferret
A Utility for cleaning up QLC+ files, and moving functions between files.
QLC+ File Ferret
================

WORK IN PROGRESS!!
**WARNING! VERY EARLY PROTOTYPE! NOT READY FOR PRODUCTION USE!!!**

This is not even beginning to be Alpha yet.
We use QLC+ a lot.

It probably wont' even run at this point.
We tend to have a single 'base' file, and then make specialised files per
event.

I'm just prototyping at the moment.
We have a few problems:

- Our 'base' file tends to get quite messy
- There's no easy way to move functions from a specialised file back into
the base, or if one operator makes a cool sequence for a specific dance
in one file, to move it to another.

This utility will try to help.

So far:
-------

Can move functions (scenes, chasers, collections, sequences, shows) from one
file to another.

**WARNING!**

It doesn't yet have any concept of moving fixtures around - so if you have
different fixtures in your different files, I have no clue what will happen.

Next:
-----

1) It has the capacity to see which functions are 'orphans' - not used by any
other function, or attached to anything in the Virtual Console. There should
be a way to display that, and clean it up.

2) We need a TON of tests to confirm that it's not gonna screw up our files.
This has only been made as a quick few-hours-between-shows hacky prototype.

3) Searching / Filtering / Sorting of functions by name,
and by orphan-parent status.

4) Creating / Moving / Renaming Functions, with some semblance of automation,
to allow (say) moving all functions used ONLY by a chaser into a folder of
the same name, or renaming them all to helpful things...

5) Fixture aware! So checking files are compatible (have compatible fixtures)
or at least figuring out what to do when there are differences.

6) Make it prettier. Icons, statusbar, etc.

To use:
-------

python3 gui.py

And you can probably figure it out.
14 changes: 8 additions & 6 deletions gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
]

# Global State: (oh noes)
CLIPBOARD = []
CLIPBOARD = set()

class QLCFileBox(ttk.Frame):
'''
Expand Down Expand Up @@ -155,12 +155,12 @@ def copySelected(self):
func = self.qfile.function_by_id(iid)
if not func: continue

if not func in CLIPBOARD:
CLIPBOARD.append(func)
CLIPBOARD.add(func)

for func in self.qfile.subfunction_ids(func, recurse=True):
if not func in CLIPBOARD:
CLIPBOARD.append(func)
for subfunc in self.qfile.subfunction_ids(func, recurse=True):
CLIPBOARD.add(subfunc)

print('%i items in clipboard' % len(CLIPBOARD))


def pasteToHere(self):
Expand All @@ -174,6 +174,7 @@ class Application(ttk.Frame):
'''
def __init__(self, master=None):
tk.Frame.__init__(self, master)

self.pack()
self.create_widgets()

Expand Down Expand Up @@ -217,6 +218,7 @@ def load_file(self, filename=None):

if __name__ == '__main__':
app = Application()

app.master.title('QLC+ Multi-file Helper Utility')

for f in (sys.argv[1:]):
Expand Down
35 changes: 27 additions & 8 deletions reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def write(self, filename, *vargs, **kwargs):
with open(filename, 'w') as f:
# apparently etree cannot write doctypes :-(
# oh well. we can.
f.write('<?xml version "1.0" encoding="UTF-8"?>\n<!DOCTYPE Workspace>\n')
f.write('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE Workspace>\n')
new_file.write(f, encoding="unicode", xml_declaration=False, *vargs, **kwargs)

def list_functions(self):
Expand Down Expand Up @@ -95,23 +95,37 @@ def function_by_id(self, fid):
def subfunction_ids(self, func, recurse=False):

if func.attrib['Type'] == 'Show':
for f in func.findall("*//qlc:ShowFunction", NS):
for f in func.findall(".//qlc:ShowFunction", NS):
subfunc = self.function_by_id(f.attrib["ID"])
yield subfunc
if recurse:
yield from self.subfunction_ids(subfunc)
elif func.attrib['Type'] == 'Sequence':
yield func.attrib['BoundScene']
elif func.attrib['Type'] in ('Collection', 'Chaser'):
for f in func.findall("*//qlc:Step", NS):
print(ET.tostring(func))
for f in func.findall(".//qlc:Step", NS):
print('step!')
print(ET.tostring(f))
subfunc = self.function_by_id(f.text)
yield subfunc
if recurse:
yield from self.subfunction_ids(subfunc)
else:
print("No Subfunctions!")


def subfunction_id_replace(self, func, old_id, new_id):
if func.attrib['Type'] == 'Show':
for f in func.findall(".//qlc:ShowFunction", NS):
if f.attrib["ID"] == old_id:
f.attrib["ID"] = new_id
elif func.attrib['Type'] == 'Sequence':
if func.attrib['BoundScene'] == old_id:
func.attrib['BoundScene'] = new_id
elif func.attrib['Type'] in ('Collection', 'Chaser'):
for f in func.findall(".//qlc:Step", NS):
if f.text == old_id:
f.text = new_id


def paste_functions_here(self, clipboard):

Expand All @@ -132,14 +146,19 @@ def paste_functions_here(self, clipboard):
# TODO: Look for Duplicate Functions - and don't copy them automatically,
# but instead ask the user what to do.

replace_tables = {}

for f in new_functions:
if f.attrib['ID'] in current_ids:
fresh_id += 1

# Fix any references to this function_id in other functions:
for ff in new_functions:
self.subfunction_id_replace(ff, f.attrib['ID'], str(fresh_id))

# And update this function itself...
f.attrib['ID'] = str(fresh_id)
current_ids.add(f.attrib['ID'])
# TODO:
# - go through all other functions looking for any uses of the old
# function id, and replace it with the new one.

enginenode = self.root.find('qlc:Engine', NS)

Expand Down

0 comments on commit 779e43a

Please sign in to comment.