Configtool: refactor printerpanel for MVC.
Move model functionality out of printerpanel.py into a new class, Printer, so we can more easily add commandline driven tests in the future and to help identify code reuse opportunities.
This commit is contained in:
parent
d3062ca1dd
commit
11bb6bb1cf
|
|
@ -0,0 +1,233 @@
|
|||
|
||||
import os
|
||||
import re
|
||||
|
||||
from sys import platform
|
||||
from configtool.data import (defineValueFormat, defineBoolFormat,
|
||||
reHelpTextStart, reHelpTextEnd,
|
||||
reDefine, reDefineBL, reDefQS, reDefQSm,
|
||||
reDefQSm2, reDefBool, reDefBoolBL)
|
||||
|
||||
class Printer:
|
||||
def __init__(self):
|
||||
self.configFile = None
|
||||
|
||||
self.cfgValues = {}
|
||||
|
||||
def hasData(self):
|
||||
return (self.configFile != None)
|
||||
|
||||
def getFileName(self):
|
||||
return self.configFile
|
||||
|
||||
def loadConfigFile(self, cfgDir, fn):
|
||||
cfgFn = os.path.join(cfgDir, "printer.generic.h")
|
||||
try:
|
||||
self.cfgBuffer = list(open(cfgFn))
|
||||
except:
|
||||
return False, cfgFn
|
||||
|
||||
try:
|
||||
self.userBuffer = list(open(fn))
|
||||
except:
|
||||
return False, fn
|
||||
|
||||
self.configFile = fn
|
||||
|
||||
gatheringHelpText = False
|
||||
helpTextString = ""
|
||||
helpKey = None
|
||||
|
||||
self.cfgValues = {}
|
||||
self.cfgNames = []
|
||||
self.helpText = {}
|
||||
|
||||
prevLines = ""
|
||||
for ln in self.cfgBuffer:
|
||||
if gatheringHelpText:
|
||||
if reHelpTextEnd.match(ln):
|
||||
gatheringHelpText = False
|
||||
helpTextString = helpTextString.strip()
|
||||
# Keep paragraphs with double-newline.
|
||||
helpTextString = helpTextString.replace("\n\n ", "\n\n")
|
||||
# Keep indented lines, typically a list.
|
||||
helpTextString = helpTextString.replace("\n\n ", "\n\n ")
|
||||
helpTextString = helpTextString.replace("\n ", "\n\n ")
|
||||
# Remove all other newlines and indents.
|
||||
helpTextString = helpTextString.replace("\n ", " ")
|
||||
hk = helpKey.split()
|
||||
for k in hk:
|
||||
self.helpText[k] = helpTextString
|
||||
helpTextString = ""
|
||||
helpKey = None
|
||||
continue
|
||||
else:
|
||||
helpTextString += ln
|
||||
continue
|
||||
|
||||
m = reHelpTextStart.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
gatheringHelpText = True
|
||||
helpKey = t[0]
|
||||
continue
|
||||
|
||||
if ln.rstrip().endswith("\\"):
|
||||
prevLines += ln.rstrip()[:-1]
|
||||
continue
|
||||
|
||||
if prevLines != "":
|
||||
ln = prevLines + ln
|
||||
prevLines = ""
|
||||
|
||||
self.parseDefineName(ln)
|
||||
self.parseDefineValue(ln)
|
||||
|
||||
# Set all boolean generic configuration items to False, so items not yet
|
||||
# existing in the user configuration default to disabled.
|
||||
for k in self.cfgValues.keys():
|
||||
if isinstance(self.cfgValues[k], bool):
|
||||
self.cfgValues[k] = False
|
||||
|
||||
# Read the user configuration. This usually overwrites all of the items
|
||||
# read above, but not those missing in the user configuration, e.g.
|
||||
# when reading an older config.
|
||||
gatheringHelpText = False
|
||||
prevLines = ""
|
||||
for ln in self.userBuffer:
|
||||
if gatheringHelpText:
|
||||
if reHelpTextEnd.match(ln):
|
||||
gatheringHelpText = False
|
||||
continue
|
||||
|
||||
if reHelpTextStart.match(ln):
|
||||
gatheringHelpText = True
|
||||
continue
|
||||
|
||||
if ln.rstrip().endswith("\\"):
|
||||
prevLines += ln.rstrip()[:-1]
|
||||
continue
|
||||
|
||||
if prevLines != "":
|
||||
ln = prevLines + ln
|
||||
prevLines = ""
|
||||
|
||||
self.parseDefineValue(ln)
|
||||
|
||||
# Parsing done. All parsed stuff is now in these array and dicts.
|
||||
# Uncomment for debugging.
|
||||
#print self.cfgValues # #defines with a value and booleans.
|
||||
#print self.cfgNames # Names found in the generic file.
|
||||
#print self.helpText
|
||||
|
||||
return True, None
|
||||
|
||||
def parseDefineName(self, ln):
|
||||
m = reDefBool.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 1:
|
||||
self.cfgNames.append(t[0])
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def parseDefineValue(self, ln):
|
||||
m = reDefQS.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2:
|
||||
m = reDefQSm.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
tt = re.findall(reDefQSm2, t[1])
|
||||
if len(tt) == 1 and (t[0] in self.cfgNames):
|
||||
self.cfgValues[t[0]] = tt[0], True
|
||||
return True
|
||||
elif len(tt) > 1 and (t[0] in self.cfgNames):
|
||||
self.cfgValues[t[0]] = tt, True
|
||||
return True
|
||||
|
||||
m = reDefine.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2 and (t[0] in self.cfgNames):
|
||||
if reDefineBL.search(ln):
|
||||
self.cfgValues[t[0]] = t[1], True
|
||||
else:
|
||||
self.cfgValues[t[0]] = t[1], False
|
||||
return True
|
||||
|
||||
m = reDefBool.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
# Accept booleans, but not those for which a value exists already.
|
||||
# Booleans already existing as values are most likely misconfigured
|
||||
# manual edits (or result of a bug).
|
||||
if len(t) == 1 and t[0] in self.cfgNames \
|
||||
and not (t[0] in self.cfgValues \
|
||||
and isinstance(self.cfgValues[t[0]], tuple)):
|
||||
if reDefBoolBL.search(ln):
|
||||
self.cfgValues[t[0]] = True
|
||||
else:
|
||||
self.cfgValues[t[0]] = False
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def saveConfigFile(self, path, values):
|
||||
fp = file(path, 'w')
|
||||
self.configFile = path
|
||||
|
||||
for ln in self.cfgBuffer:
|
||||
m = reDefine.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2 and t[0] in values.keys():
|
||||
v = values[t[0]]
|
||||
self.cfgValues[t[0]] = v
|
||||
if v[1] == False:
|
||||
fp.write("//")
|
||||
fp.write(defineValueFormat % (t[0], v[0]))
|
||||
else:
|
||||
if t[0] == 'CANNED_CYCLE':
|
||||
# Known to be absent in the GUI. Worse, this value is replaced
|
||||
# by the one in the metadata file.
|
||||
#
|
||||
# TODO: make value reading above recognize wether this value is
|
||||
# commented out or not. Reading the value its self works
|
||||
# already. Hint: it's the rule using reDefQS, reDefQSm, etc.
|
||||
#
|
||||
# TODO: add a multiline text field in the GUI to deal with this.
|
||||
#
|
||||
# TODO: write this value out properly. In /* comments */, if
|
||||
# disabled.
|
||||
#
|
||||
# TODO: currently, the lines beyond the ones with the #define are
|
||||
# treated like arbitrary comments. Having the former TODOs
|
||||
# done, this will lead to duplicates.
|
||||
fp.write(ln)
|
||||
else:
|
||||
print "Value key " + t[0] + " not found in GUI."
|
||||
|
||||
continue
|
||||
|
||||
m = reDefBoolBL.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 1 and t[0] in values.keys():
|
||||
v = values[t[0]]
|
||||
self.cfgValues[t[0]] = v
|
||||
if v == "" or v == False:
|
||||
fp.write("//")
|
||||
fp.write(defineBoolFormat % t[0])
|
||||
else:
|
||||
print "Boolean key " + t[0] + " not found in GUI."
|
||||
|
||||
continue
|
||||
|
||||
fp.write(ln)
|
||||
|
||||
fp.close()
|
||||
|
||||
return True
|
||||
|
|
@ -13,6 +13,7 @@ from configtool.mechanicalpage import MechanicalPage
|
|||
from configtool.accelerationpage import AccelerationPage
|
||||
from configtool.miscellaneouspage import MiscellaneousPage
|
||||
from configtool.protectedfiles import protectedFiles
|
||||
from configtool.printer import Printer
|
||||
|
||||
|
||||
class PrinterPanel(wx.Panel):
|
||||
|
|
@ -21,13 +22,12 @@ class PrinterPanel(wx.Panel):
|
|||
self.parent = parent
|
||||
|
||||
self.deco = Decoration()
|
||||
self.configFile = None
|
||||
self.protFileLoaded = False
|
||||
|
||||
self.settings = settings
|
||||
|
||||
self.cfgValues = {}
|
||||
self.heaters = []
|
||||
self.printer = Printer()
|
||||
|
||||
self.dir = os.path.join(self.settings.folder, "config")
|
||||
self.cfgDir = os.path.join(self.settings.folder, "configtool")
|
||||
|
||||
|
|
@ -65,9 +65,6 @@ class PrinterPanel(wx.Panel):
|
|||
self.pageValid.append(True)
|
||||
return page
|
||||
|
||||
def getFileName(self):
|
||||
return self.configFile
|
||||
|
||||
def assertModified(self, pg, flag = True):
|
||||
self.pageModified[pg] = flag
|
||||
self.modifyTab(pg)
|
||||
|
|
@ -79,7 +76,10 @@ class PrinterPanel(wx.Panel):
|
|||
return not (False in self.pageValid)
|
||||
|
||||
def hasData(self):
|
||||
return (self.configFile != None)
|
||||
return self.printer.hasData()
|
||||
|
||||
def getFileName(self):
|
||||
return self.printer.configFile
|
||||
|
||||
def assertValid(self, pg, flag = True):
|
||||
self.pageValid[pg] = flag
|
||||
|
|
@ -170,104 +170,9 @@ class PrinterPanel(wx.Panel):
|
|||
return
|
||||
|
||||
def loadConfigFile(self, fn):
|
||||
cfgFn = os.path.join(self.cfgDir, "printer.generic.h")
|
||||
try:
|
||||
self.cfgBuffer = list(open(cfgFn))
|
||||
except:
|
||||
return False, cfgFn
|
||||
|
||||
try:
|
||||
self.userBuffer = list(open(fn))
|
||||
except:
|
||||
return False, fn
|
||||
|
||||
self.configFile = fn
|
||||
|
||||
gatheringHelpText = False
|
||||
helpTextString = ""
|
||||
helpKey = None
|
||||
|
||||
self.cfgValues = {}
|
||||
self.cfgNames = []
|
||||
self.helpText = {}
|
||||
|
||||
prevLines = ""
|
||||
for ln in self.cfgBuffer:
|
||||
if gatheringHelpText:
|
||||
if reHelpTextEnd.match(ln):
|
||||
gatheringHelpText = False
|
||||
helpTextString = helpTextString.strip()
|
||||
# Keep paragraphs with double-newline.
|
||||
helpTextString = helpTextString.replace("\n\n ", "\n\n")
|
||||
# Keep indented lines, typically a list.
|
||||
helpTextString = helpTextString.replace("\n\n ", "\n\n ")
|
||||
helpTextString = helpTextString.replace("\n ", "\n\n ")
|
||||
# Remove all other newlines and indents.
|
||||
helpTextString = helpTextString.replace("\n ", " ")
|
||||
hk = helpKey.split()
|
||||
for k in hk:
|
||||
self.helpText[k] = helpTextString
|
||||
helpTextString = ""
|
||||
helpKey = None
|
||||
continue
|
||||
else:
|
||||
helpTextString += ln
|
||||
continue
|
||||
|
||||
m = reHelpTextStart.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
gatheringHelpText = True
|
||||
helpKey = t[0]
|
||||
continue
|
||||
|
||||
if ln.rstrip().endswith("\\"):
|
||||
prevLines += ln.rstrip()[:-1]
|
||||
continue
|
||||
|
||||
if prevLines != "":
|
||||
ln = prevLines + ln
|
||||
prevLines = ""
|
||||
|
||||
self.parseDefineName(ln)
|
||||
self.parseDefineValue(ln)
|
||||
|
||||
# Set all boolean generic configuration items to False, so items not yet
|
||||
# existing in the user configuration default to disabled.
|
||||
for k in self.cfgValues.keys():
|
||||
if isinstance(self.cfgValues[k], bool):
|
||||
self.cfgValues[k] = False
|
||||
|
||||
# Read the user configuration. This usually overwrites all of the items
|
||||
# read above, but not those missing in the user configuration, e.g.
|
||||
# when reading an older config.
|
||||
gatheringHelpText = False
|
||||
prevLines = ""
|
||||
for ln in self.userBuffer:
|
||||
if gatheringHelpText:
|
||||
if reHelpTextEnd.match(ln):
|
||||
gatheringHelpText = False
|
||||
continue
|
||||
|
||||
if reHelpTextStart.match(ln):
|
||||
gatheringHelpText = True
|
||||
continue
|
||||
|
||||
if ln.rstrip().endswith("\\"):
|
||||
prevLines += ln.rstrip()[:-1]
|
||||
continue
|
||||
|
||||
if prevLines != "":
|
||||
ln = prevLines + ln
|
||||
prevLines = ""
|
||||
|
||||
self.parseDefineValue(ln)
|
||||
|
||||
# Parsing done. All parsed stuff is now in these arrays and dicts.
|
||||
# Uncomment for debugging.
|
||||
#print self.cfgValues # #defines with a value and booleans.
|
||||
#print self.cfgNames # Names found in the generic file.
|
||||
#print self.helpText
|
||||
ok, file = self.printer.loadConfigFile(self.cfgDir, fn)
|
||||
if not ok:
|
||||
return ok, file
|
||||
|
||||
if os.path.basename(fn) in protectedFiles:
|
||||
self.parent.enableSavePrinter(False, True)
|
||||
|
|
@ -278,72 +183,19 @@ class PrinterPanel(wx.Panel):
|
|||
self.parent.setPrinterTabFile(os.path.basename(fn))
|
||||
|
||||
for pg in self.pages:
|
||||
pg.insertValues(self.cfgValues)
|
||||
pg.setHelpText(self.helpText)
|
||||
pg.insertValues(self.printer.cfgValues)
|
||||
pg.setHelpText(self.printer.helpText)
|
||||
|
||||
k = 'DC_EXTRUDER'
|
||||
if k in self.cfgValues.keys() and self.cfgValues[k][1] == True:
|
||||
if k in self.printer.cfgValues.keys() and self.printer.cfgValues[k][1] == True:
|
||||
self.pgMiscellaneous.setOriginalHeater(self.cfgValues[k][0])
|
||||
else:
|
||||
self.pgMiscellaneous.setOriginalHeater(None)
|
||||
|
||||
return True, None
|
||||
|
||||
def parseDefineName(self, ln):
|
||||
m = reDefBool.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 1:
|
||||
self.cfgNames.append(t[0])
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def parseDefineValue(self, ln):
|
||||
m = reDefQS.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2:
|
||||
m = reDefQSm.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
tt = re.findall(reDefQSm2, t[1])
|
||||
if len(tt) == 1 and (t[0] in self.cfgNames):
|
||||
self.cfgValues[t[0]] = tt[0], True
|
||||
return True
|
||||
elif len(tt) > 1 and (t[0] in self.cfgNames):
|
||||
self.cfgValues[t[0]] = tt, True
|
||||
return True
|
||||
|
||||
m = reDefine.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2 and (t[0] in self.cfgNames):
|
||||
if reDefineBL.search(ln):
|
||||
self.cfgValues[t[0]] = t[1], True
|
||||
else:
|
||||
self.cfgValues[t[0]] = t[1], False
|
||||
return True
|
||||
|
||||
m = reDefBool.search(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
# Accept booleans, but not those for which a value exists already.
|
||||
# Booleans already existing as values are most likely misconfigured
|
||||
# manual edits (or result of a bug).
|
||||
if len(t) == 1 and t[0] in self.cfgNames \
|
||||
and not (t[0] in self.cfgValues \
|
||||
and isinstance(self.cfgValues[t[0]], tuple)):
|
||||
if reDefBoolBL.search(ln):
|
||||
self.cfgValues[t[0]] = True
|
||||
else:
|
||||
self.cfgValues[t[0]] = False
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def onSaveConfig(self, evt):
|
||||
path = self.configFile
|
||||
path = self.getFileName()
|
||||
return self.saveConfigFile(path)
|
||||
|
||||
def onSaveConfigAs(self, evt):
|
||||
|
|
@ -386,6 +238,12 @@ class PrinterPanel(wx.Panel):
|
|||
dlg.Destroy()
|
||||
return False
|
||||
|
||||
values = {}
|
||||
for pg in self.pages:
|
||||
v1 = pg.getValues()
|
||||
for k in v1.keys():
|
||||
values[k] = v1[k]
|
||||
|
||||
ext = os.path.splitext(os.path.basename(path))[1]
|
||||
self.dir = os.path.dirname(path)
|
||||
|
||||
|
|
@ -393,7 +251,7 @@ class PrinterPanel(wx.Panel):
|
|||
path += ".h"
|
||||
|
||||
try:
|
||||
fp = file(path, 'w')
|
||||
self.printer.saveConfigFile(path, values)
|
||||
except:
|
||||
dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
|
||||
"File error", wx.OK + wx.ICON_ERROR)
|
||||
|
|
@ -401,64 +259,4 @@ class PrinterPanel(wx.Panel):
|
|||
dlg.Destroy()
|
||||
return False
|
||||
|
||||
self.configFile = path
|
||||
|
||||
values = {}
|
||||
|
||||
for pg in self.pages:
|
||||
v1 = pg.getValues()
|
||||
for k in v1.keys():
|
||||
values[k] = v1[k]
|
||||
|
||||
for ln in self.cfgBuffer:
|
||||
m = reDefine.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 2 and t[0] in values.keys():
|
||||
v = values[t[0]]
|
||||
self.cfgValues[t[0]] = v
|
||||
if v[1] == False:
|
||||
fp.write("//")
|
||||
fp.write(defineValueFormat % (t[0], v[0]))
|
||||
else:
|
||||
if t[0] == 'CANNED_CYCLE':
|
||||
# Known to be absent in the GUI. Worse, this value is replaced
|
||||
# by the one in the metadata file.
|
||||
#
|
||||
# TODO: make value reading above recognize wether this value is
|
||||
# commented out or not. Reading the value its self works
|
||||
# already. Hint: it's the rule using reDefQS, reDefQSm, etc.
|
||||
#
|
||||
# TODO: add a multiline text field in the GUI to deal with this.
|
||||
#
|
||||
# TODO: write this value out properly. In /* comments */, if
|
||||
# disabled.
|
||||
#
|
||||
# TODO: currently, the lines beyond the ones with the #define are
|
||||
# treated like arbitrary comments. Having the former TODOs
|
||||
# done, this will lead to duplicates.
|
||||
fp.write(ln)
|
||||
else:
|
||||
print "Value key " + t[0] + " not found in GUI."
|
||||
|
||||
continue
|
||||
|
||||
m = reDefBoolBL.match(ln)
|
||||
if m:
|
||||
t = m.groups()
|
||||
if len(t) == 1 and t[0] in values.keys():
|
||||
v = values[t[0]]
|
||||
self.cfgValues[t[0]] = v
|
||||
if v == "" or v == False:
|
||||
fp.write("//")
|
||||
fp.write(defineBoolFormat % t[0])
|
||||
else:
|
||||
print "Boolean key " + t[0] + " not found in GUI."
|
||||
|
||||
continue
|
||||
|
||||
fp.write(ln)
|
||||
|
||||
fp.close()
|
||||
|
||||
return True
|
||||
|
|
|
|||
Loading…
Reference in New Issue