コード例 #1
0
    def __init__(self, font):
        self.modified = False
        self.valid = True
        self.fieldValid = {}
        self.textControls = {}
        self.checkBoxes = {}
        self.radioButtons = {}
        self.radioButtonBoxes = {}
        self.choices = {}
        self.deco = Decoration()
        self.font = font

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
コード例 #2
0
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Teacup Configtool", size=(880, 550))
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.Bind(wx.EVT_SIZE, self.onResize)

        self.deco = Decoration()

        panel = wx.Panel(self, -1)
        panel.SetBackgroundColour(self.deco.getBackgroundColour())
        panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

        self.settings = Settings(self, cmd_folder)
        self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS,
                                     wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
        self.settings.folder = cmd_folder

        self.heaters = []
        self.savePrtEna = False
        self.saveBrdEna = False
        self.protPrtFile = False
        self.protBrdFile = False

        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(panel,
                              wx.ID_ANY,
                              size=(880, 550),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.printerFileName = None
        self.printerTabDecor = ""
        self.printerBaseText = "Printer"
        self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgPrinter, self.printerBaseText)

        self.boardFileName = None
        self.boardTabDecor = ""
        self.boardBaseText = "Board"
        self.pgBoard = BoardPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgBoard, self.boardBaseText)

        panel.Fit()
        self.panel = panel

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
        self.SetSizer(sz)
        self.makeMenu()
コード例 #3
0
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent

    self.deco = Decoration()
    self.configFile = None
    self.protFileLoaded = False

    self.settings = settings

    self.cfgValues = {}
    self.heaters = []
    self.dir = os.path.join(self.settings.folder, "config")
    self.cfgDir = os.path.join(self.settings.folder, "configtool")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgMech = MechanicalPage(self, self.nb, len(self.pages),
                                 self.settings.font)
    text = "Mechanical"
    self.nb.AddPage(self.pgMech, text)
    self.pages.append(self.pgMech)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgAcc = AccelerationPage(self, self.nb, len(self.pages),
                                  self.settings.font)
    text = "Acceleration"
    self.nb.AddPage(self.pgAcc, text)
    self.pages.append(self.pgAcc)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgMiscellaneous = MiscellaneousPage(self, self.nb, len(self.pages),
                                             self.settings.font)
    text = "Miscellaneous"
    self.nb.AddPage(self.pgMiscellaneous, text)
    self.pages.append(self.pgMiscellaneous)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()
コード例 #4
0
ファイル: boardpanel.py プロジェクト: pezr/Teacup_Firmware
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent
        self.settings = settings
        self.protFileLoaded = False

        self.deco = Decoration()
        self.configFile = None

        self.cfgValues = {}
        self.heaters = []
        self.sensors = []
        self.candHeatPins = []
        self.candThermPins = []
        self.dir = os.path.join(self.settings.folder, "config")
        self.cfgDir = os.path.join(self.settings.folder, "configtool")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgCpu = self.registerPage(CpuPage, "CPU")
        self.pgPins = self.registerPage(PinoutsPage, "Pinouts")
        self.pgDisplay = self.registerPage(DisplayPage, "Display")
        self.pgHeaters = self.registerPage(HeatersPage, "Heaters")
        self.pgSensors = self.registerPage(SensorsPage,
                                           "Temperature Sensors",
                                           heatersPage=self.pgHeaters)
        self.pgCommunications = self.registerPage(CommunicationsPage,
                                                  "Communications")

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()
コード例 #5
0
ファイル: printerpanel.py プロジェクト: pezr/Teacup_Firmware
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent

        self.deco = Decoration()
        self.configFile = None
        self.protFileLoaded = False

        self.settings = settings

        self.cfgValues = {}
        self.heaters = []
        self.dir = os.path.join(self.settings.folder, "config")
        self.cfgDir = os.path.join(self.settings.folder, "configtool")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgMech = self.registerPage(MechanicalPage, "Mechanical")
        self.pgAcc = self.registerPage(AccelerationPage, "Acceleration")
        self.pgMiscellaneous = self.registerPage(MiscellaneousPage,
                                                 "Miscellaneous")

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()
コード例 #6
0
ファイル: page.py プロジェクト: DEMI1/Teacup_Firmware
  def __init__(self, font):
    self.modified = False
    self.valid = True
    self.fieldValid = {}
    self.textControls = {}
    self.checkBoxes = {}
    self.radioButtons = {}
    self.radioButtonBoxes = {}
    self.choices = {}
    self.deco = Decoration()
    self.font = font

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
コード例 #7
0
  def __init__(self):
    wx.Frame.__init__(self, None, -1, "Teacup Configtool", size = (880, 550))
    self.Bind(wx.EVT_CLOSE, self.onClose)
    self.Bind(wx.EVT_SIZE, self.onResize)

    self.deco = Decoration()

    panel = wx.Panel(self, -1)
    panel.SetBackgroundColour(self.deco.getBackgroundColour())
    panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

    self.settings = Settings(self, cmd_folder)
    self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
                                 wx.FONTWEIGHT_BOLD)
    self.settings.folder = cmd_folder

    self.heaters = []
    self.savePrtEna = False
    self.saveBrdEna = False
    self.protPrtFile = False
    self.protBrdFile = False

    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(panel, wx.ID_ANY, size = (880, 550),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.printerFileName = None
    self.printerTabDecor = ""
    self.printerBaseText = "Printer"
    self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgPrinter, self.printerBaseText)

    self.boardFileName = None
    self.boardTabDecor = ""
    self.boardBaseText = "Board"
    self.pgBoard = BoardPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgBoard, self.boardBaseText)

    panel.Fit()
    self.panel = panel

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
    self.SetSizer(sz)
    self.makeMenu()
コード例 #8
0
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent
    self.settings = settings
    self.protFileLoaded = False

    self.deco = Decoration()
    self.configFile = None

    self.cfgValues = {}
    self.heaters = []
    self.sensors = []
    self.candHeatPins = []
    self.candThermPins = []
    self.dir = os.path.join(self.settings.folder, "config")
    self.cfgDir = os.path.join(self.settings.folder, "configtool")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgCpu = self.registerPage(CpuPage, "CPU")
    self.pgPins = self.registerPage(PinoutsPage, "Pinouts")
    self.pgDisplay = self.registerPage(DisplayPage, "Display")
    self.pgHeaters = self.registerPage(HeatersPage, "Heaters")
    self.pgSensors = self.registerPage(SensorsPage, "Temperature Sensors",
                                       heatersPage = self.pgHeaters)
    self.pgCommunications = self.registerPage(CommunicationsPage,
                                              "Communications")

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()
コード例 #9
0
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent

    self.deco = Decoration()
    self.protFileLoaded = False

    self.settings = settings

    self.printer = Printer(self.settings)

    self.dir = os.path.join(self.settings.folder, "config")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgMech = self.registerPage(MechanicalPage, "Mechanical")
    self.pgAcc = self.registerPage(AccelerationPage, "Acceleration")
    self.pgMiscellaneous = self.registerPage(MiscellaneousPage,
                                             "Miscellaneous")

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()
コード例 #10
0
ファイル: boardpanel.py プロジェクト: benj919/Teacup_Firmware
class BoardPanel(wx.Panel):
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent
    self.settings = settings
    self.protFileLoaded = False

    self.deco = Decoration()
    self.configFile = None

    self.cfgValues = {}
    self.heaters = []
    self.sensors = []
    self.candHeatPins = []
    self.candThermPins = []
    self.dir = os.path.join(self.settings.folder, "config")
    self.cfgDir = os.path.join(self.settings.folder, "configtool")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgCpu = CpuPage(self, self.nb, len(self.pages), self.settings.font)
    text = "CPU"
    self.nb.AddPage(self.pgCpu, text)
    self.pages.append(self.pgCpu)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgPins = PinoutsPage(self, self.nb, len(self.pages),
                              self.settings.font)
    text = "Pinouts"
    self.nb.AddPage(self.pgPins, text)
    self.pages.append(self.pgPins)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgHeaters = HeatersPage(self, self.nb, len(self.pages),
                                 self.settings.font)
    text = "Heaters"
    self.nb.AddPage(self.pgHeaters, text)
    self.pages.append(self.pgHeaters)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgSensors = SensorsPage(self, self.nb, len(self.pages), self.pgHeaters,
                                 self.settings.font)
    text = "Temperature Sensors"
    self.nb.AddPage(self.pgSensors, text)
    self.pages.append(self.pgSensors)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgCommunications = CommunicationsPage(self, self.nb, len(self.pages),
                                               self.settings.font)
    text = "Communications"
    self.nb.AddPage(self.pgCommunications, text)
    self.pages.append(self.pgCommunications)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()

  def getCPUInfo(self):
    vF_CPU = None
    if 'F_CPU' in self.cfgValues.keys():
      vF_CPU = self.cfgValues['F_CPU'][0]

    vCPU = None
    if 'CPU' in self.cfgValues.keys():
      vCPU = self.cfgValues['CPU'][0]

    return vF_CPU, vCPU

  def assertModified(self, pg, flag = True):
    self.pageModified[pg] = flag
    self.modifyTab(pg)

  def isModified(self):
    return (True in self.pageModified)

  def isValid(self):
    return not (False in self.pageValid)

  def hasData(self):
    return (self.configFile != None)

  def getFileName(self):
    return self.configFile

  def assertValid(self, pg, flag = True):
    self.pageValid[pg] = flag
    self.modifyTab(pg)

    if False in self.pageValid:
      self.parent.enableSaveBoard(False, False)
    else:
      self.parent.enableSaveBoard(not self.protFileLoaded, True)

  def modifyTab(self, pg):
    if self.pageModified[pg] and not self.pageValid[pg]:
      pfx = "?* "
    elif self.pageModified[pg]:
      pfx = "* "
    elif not self.pageValid[pg]:
      pfx = "? "
    else:
      pfx = ""

    self.nb.SetPageText(pg, pfx + self.titles[pg])
    if True in self.pageModified and False in self.pageValid:
      pfx = "?* "
    elif True in self.pageModified:
      pfx = "* "
    elif False in self.pageValid:
      pfx = "? "
    else:
      pfx = ""
    self.parent.setBoardTabDecor(pfx)

  def setHeaters(self, ht):
    self.parent.setHeaters(ht)

  def onClose(self, evt):
    if not self.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def confirmLoseChanges(self, msg):
    if True not in self.pageModified:
      return True

    dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
                                 "There are changes to your board "
                                 "configuration that will be lost.",
                           "Changes pending",
                           wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
    rc = dlg.ShowModal()
    dlg.Destroy()

    if rc != wx.ID_YES:
      return False

    return True

  def onLoadConfig(self, evt):
    if not self.confirmLoseChanges("load a new board configuration"):
      return

    if platform == "darwin":
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Board configuration (board.*.h)|*.h"
    else:
      wildcard = "Board configuration (board.*.h)|board.*.h"

    dlg = wx.FileDialog(self, message = "Choose a board config file",
                        defaultDir = self.dir, defaultFile = "",
                        wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)

    path = None
    if dlg.ShowModal() == wx.ID_OK:
      path = dlg.GetPath()

    dlg.Destroy()
    if path is None:
      return

    self.dir = os.path.dirname(path)
    rc, efn = self.loadConfigFile(path)

    if not rc:
      dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

  def loadConfigFile(self, fn):
    cfgFn = os.path.join(self.cfgDir, "board.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

    self.processors = []
    self.sensors = []
    self.heaters = []
    self.candHeatPins = []
    self.candThermPins = []
    self.candProcessors = []
    self.candClocks = []
    self.tempTables = {}
    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 = ""

      if self.parseCandidateValues(ln):
        continue

      if self.parseDefineName(ln):
        continue

    # Ignore candidates in the metadata file.
    self.candHeatPins = []
    self.candThermPins = []
    self.candProcessors = []
    self.candClocks = []
    self.tempTables = {}
    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 = ""

      if self.parseCandidateValues(ln):
        continue

      elif self.parseDefineValue(ln):
        continue

      else:
        m = reDefTS.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            s = self.parseSensor(t[0])
            if s:
              self.sensors.append(s)
              continue

        m = reDefHT.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            s = self.parseHeater(t[0])
            if s:
              self.heaters.append(s)
              continue

    for k in range(len(self.sensors)):
      tn = self.sensors[k][0].upper()
      if tn in self.tempTables.keys():
        self.sensors[k][3] = self.tempTables[tn]
      else:
        self.sensors[k][3] = None

    if os.path.basename(fn) in protectedFiles:
      self.parent.enableSaveBoard(False, True)
      self.protFileLoaded = True
    else:
      self.protFileLoaded = False
      self.parent.enableSaveBoard(True, True)
    self.parent.setBoardTabFile(os.path.basename(fn))
    self.pgHeaters.setCandidatePins(self.candHeatPins)
    self.pgSensors.setCandidatePins(self.candThermPins)
    self.pgCpu.setCandidateProcessors(self.candProcessors)
    self.pgCpu.setCandidateClocks(self.candClocks)

    for pg in self.pages:
      pg.insertValues(self.cfgValues)
      pg.setHelpText(self.helpText)

    self.pgSensors.setSensors(self.sensors)
    self.pgHeaters.setHeaters(self.heaters)

    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 = reDefBoolBL.search(ln)
    if m:
      t = m.groups()
      if len(t) == 1 and (t[0] in self.cfgNames):
        self.cfgValues[t[0]] = True
        return True

    return False

  def parseCandidateValues(self, ln):
    m = reCandThermPins.match(ln)
    if m:
      t = m.groups()
      if len(t) == 1:
        self.candThermPins.append(t[0])
      return True

    m = reCandHeatPins.match(ln)
    if m:
      t = m.groups()
      if len(t) == 1:
        self.candHeatPins.append(t[0])
      return True

    m = reCandProcessors.match(ln)
    if m:
      t = m.groups()
      if len(t) == 1:
        self.candProcessors.append(t[0])
      return True

    m = reCandCPUClocks.match(ln)
    if m:
      t = m.groups()
      if len(t) == 1:
        self.candClocks.append(t[0])
      return True

    m = reDefTT.match(ln)
    if m:
      t = m.groups()
      if len(t) == 2:
        s = self.parseTempTable(t[1])
        if s:
          self.tempTables[t[0]] = s
      return True

    return False

  def parseSensor(self, s):
    m = reSensor.search(s)
    if m:
      t = m.groups()
      if len(t) == 4:
        return list(t)
    return None

  def parseHeater(self, s):
    m = reHeater.search(s)
    if m:
      t = m.groups()
      if len(t) == 3:
        return list(t)
    return None

  def parseTempTable(self, s):
    m = reTempTable4.search(s)
    if m:
      t = m.groups()
      if len(t) == 4:
        return list(t)
    m = reTempTable7.search(s)
    if m:
      t = m.groups()
      if len(t) == 7:
        return list(t)
    return None

  def onSaveConfig(self, evt):
    path = self.configFile
    return self.saveConfigFile(path)

  def onSaveConfigAs(self, evt):
    wildcard = "Board configuration (board.*.h)|board.*.h"

    dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
                        defaultFile = "", wildcard = wildcard,
                        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

    val = dlg.ShowModal()

    if val != wx.ID_OK:
      dlg.Destroy()
      return

    path = dlg.GetPath()
    dlg.Destroy()

    rc = self.saveConfigFile(path)
    if rc:
      self.parent.setBoardTabFile(os.path.basename(path))
      self.protFileLoaded = False
      self.parent.enableSaveBoard(True, True)
    return rc

  def saveConfigFile(self, path):
    if os.path.basename(path) in protectedFiles:
      dlg = wx.MessageDialog(self, "It's not allowed to overwrite files "
                             "distributed by Teacup. Choose another name.",
                             "Protected file error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    if not os.path.basename(path).startswith("board."):
      dlg = wx.MessageDialog(self, "Illegal file name: %s.\n"
                                   "File name must begin with \"board.\"" % path,
                             "Illegal file name", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    ext = os.path.splitext(os.path.basename(path))[1]
    self.dir = os.path.dirname(path)

    if ext == "":
      path += ".h"

    try:
      fp = file(path, 'w')
    except:
      dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      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]

    skipToSensorEnd = False
    skipToHeaterEnd = False
    tempTables = {}
    candThermPinsWritten = False
    candHeatPinsWritten = False
    candProcessorsWritten = False
    candCPUClocksWritten = False
    for ln in self.cfgBuffer:
      m = reStartSensors.match(ln)
      if m:
        fp.write(ln)
        fp.write("//                 name      type           pin    "
                 "additional\n");
        ttString = "\n"
        ttString += "// Beta algorithm      r0      beta  r2    vadc\n"
        ttString += "// Steinhart-Hart      rp      t0    r0      t1    "
        ttString += "r1      t2    r2\n"
        for s in self.sensors:
          sstr = "%-10s%-15s%-7s" % ((s[0] + ","), (s[1] + ","), (s[2] + ","))
          if s[3] is None:
            sstr += "0"
          else:
            sstr += "THERMISTOR_%s" % s[0].upper()
            tt = s[3]
            if len(tt) == 4:
              ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-6s%s)\n" % \
                          (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                           (tt[2] + ","), tt[3])
            else:
              ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-8s%-6s%-8s%-6s%s)\n" % \
                          (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                           (tt[2] + ","), (tt[3] + ","), (tt[4] + ","),
                           (tt[5] + ","), tt[6])
          fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr)
        fp.write(ttString)
        skipToSensorEnd = True
        continue

      if skipToSensorEnd:
        m = reEndSensors.match(ln)
        if m:
          fp.write(ln)
          skipToSensorEnd = False
        continue

      m = reStartHeaters.match(ln)
      if m:
        fp.write(ln)
        fp.write("//            name      port   pwm\n")
        for s in self.heaters:
          sstr = "%-10s%-7s%s" % ((s[0] + ","), (s[1] + ","), s[2])
          fp.write("DEFINE_HEATER(%s)\n" % sstr)
        fp.write("\n")
        for s in self.heaters:
          fp.write(defineHeaterFormat % (s[0].upper(), s[0]))
        skipToHeaterEnd = True
        continue

      if skipToHeaterEnd:
        m = reEndHeaters.match(ln)
        if m:
          fp.write(ln)
          skipToHeaterEnd = False
        continue

      if reCandThermPins.match(ln):
        if not candThermPinsWritten:
          for pin in self.candThermPins:
            fp.write("//#define TEMP_SENSOR_PIN " + pin + "\n")
          candThermPinsWritten = True
        continue

      if reCandHeatPins.match(ln):
        if not candHeatPinsWritten:
          for pin in self.candHeatPins:
            fp.write("//#define HEATER_PIN " + pin + "\n")
          candHeatPinsWritten = True
        continue

      if reCandProcessors.match(ln):
        if not candProcessorsWritten:
          for pin in self.candProcessors:
            fp.write("//#define CPU_TYPE " + pin + "\n")
          candProcessorsWritten = True
        continue

      if reCandCPUClocks.match(ln):
        if not candCPUClocksWritten:
          for pin in self.candClocks:
            fp.write("//#define F_CPU_OPT " + pin + "\n")
          candCPUClocksWritten = True
        continue

      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] == 'TX_ENABLE_PIN' or t[0] == 'RX_ENABLE_PIN':
                # Known to be absent in the GUI, probably won't be added anytime soon.
                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:
          if t[0] == 'MOTHERBOARD':
            # Known to be absent in the GUI, also won't be added anytime soon.
            fp.write(ln)
          else:
            print "Boolean key " + t[0] + " not found in GUI."

        continue

      fp.write(ln)

    fp.close()
    return self.generateTempTables()

  def generateTempTables(self):
    if not generateTempTables(self.sensors, self.settings):
      dlg = wx.MessageDialog(self, "Error writing to file thermistortable.h.",
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    return True
コード例 #11
0
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent
    self.settings = settings
    self.protFileLoaded = False

    self.deco = Decoration()
    self.configFile = None

    self.cfgValues = {}
    self.heaters = []
    self.sensors = []
    self.candHeatPins = []
    self.candThermPins = []
    self.dir = os.path.join(self.settings.folder, "config")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgCpu = CpuPage(self, self.nb, len(self.pages), self.settings.font)
    text = "CPU"
    self.nb.AddPage(self.pgCpu, text)
    self.pages.append(self.pgCpu)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgPins = PinoutsPage(self, self.nb, len(self.pages),
                              self.settings.font)
    text = "Pinouts"
    self.nb.AddPage(self.pgPins, text)
    self.pages.append(self.pgPins)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgHeaters = HeatersPage(self, self.nb, len(self.pages),
                                 self.settings.font)
    text = "Heaters"
    self.nb.AddPage(self.pgHeaters, text)
    self.pages.append(self.pgHeaters)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgSensors = SensorsPage(self, self.nb, len(self.pages), self.pgHeaters,
                                 self.settings.font)
    text = "Temperature Sensors"
    self.nb.AddPage(self.pgSensors, text)
    self.pages.append(self.pgSensors)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgCommunications = CommunicationsPage(self, self.nb, len(self.pages),
                                               self.settings.font)
    text = "Communications"
    self.nb.AddPage(self.pgCommunications, text)
    self.pages.append(self.pgCommunications)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()
コード例 #12
0
class ConfigFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Teacup Configtool", size=(880, 550))
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.Bind(wx.EVT_SIZE, self.onResize)

        self.deco = Decoration()

        panel = wx.Panel(self, -1)
        panel.SetBackgroundColour(self.deco.getBackgroundColour())
        panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

        self.settings = Settings(self, cmd_folder)
        self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS,
                                     wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
        self.settings.folder = cmd_folder

        self.heaters = []
        self.savePrtEna = False
        self.saveBrdEna = False
        self.protPrtFile = False
        self.protBrdFile = False

        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(panel,
                              wx.ID_ANY,
                              size=(880, 550),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.printerFileName = None
        self.printerTabDecor = ""
        self.printerBaseText = "Printer"
        self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgPrinter, self.printerBaseText)

        self.boardFileName = None
        self.boardTabDecor = ""
        self.boardBaseText = "Board"
        self.pgBoard = BoardPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgBoard, self.boardBaseText)

        panel.Fit()
        self.panel = panel

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
        self.SetSizer(sz)
        self.makeMenu()

    def onClose(self, evt):
        if not self.pgPrinter.confirmLoseChanges("exit"):
            return

        if not self.pgBoard.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def onResize(self, evt):
        self.panel.SetSize(self.GetClientSize())
        self.Refresh()
        evt.Skip()

    def setPrinterTabFile(self, fn):
        self.printerFileName = fn
        self.updatePrinterTab()

    def setPrinterTabDecor(self, prefix):
        self.printerTabDecor = prefix
        self.updatePrinterTab()

    def updatePrinterTab(self):
        txt = self.printerTabDecor + self.printerBaseText
        if self.printerFileName:
            txt += " <%s>" % self.printerFileName
        self.nb.SetPageText(0, txt)

    def setBoardTabFile(self, fn):
        self.boardFileName = fn
        self.updateBoardTab()

    def setBoardTabDecor(self, prefix):
        self.boardTabDecor = prefix
        self.updateBoardTab()

    def updateBoardTab(self):
        txt = self.boardTabDecor + self.boardBaseText
        if self.boardFileName:
            txt += " <%s>" % self.boardFileName
        self.nb.SetPageText(1, txt)

    def setHeaters(self, ht):
        self.heaters = ht
        self.pgPrinter.setHeaters(ht)

    def makeMenu(self):
        file_menu = wx.Menu()

        file_menu.Append(
            ID_LOAD_CONFIG, "Load config.h",
            "Load config.h and its named printer and board files.")
        self.Bind(wx.EVT_MENU, self.onLoadConfig, id=ID_LOAD_CONFIG)
        file_menu.Enable(ID_LOAD_CONFIG, False)

        file_menu.Append(ID_SAVE_CONFIG, "Save config.h",
                         "Save config.h file.")
        self.Bind(wx.EVT_MENU, self.onSaveConfig, id=ID_SAVE_CONFIG)
        file_menu.Enable(ID_SAVE_CONFIG, False)

        file_menu.AppendSeparator()

        file_menu.Append(ID_LOAD_PRINTER, "Load printer",
                         "Load a printer configuration file.")
        self.Bind(wx.EVT_MENU, self.pgPrinter.onLoadConfig, id=ID_LOAD_PRINTER)

        file_menu.Append(ID_SAVE_PRINTER, "Save printer",
                         "Save printer configuration.")
        self.Bind(wx.EVT_MENU, self.onSavePrinterConfig, id=ID_SAVE_PRINTER)
        file_menu.Enable(ID_SAVE_PRINTER, False)

        file_menu.Append(ID_SAVE_PRINTER_AS, "Save printer as...",
                         "Save printer configuration to a new file.")
        self.Bind(wx.EVT_MENU,
                  self.onSavePrinterConfigAs,
                  id=ID_SAVE_PRINTER_AS)
        file_menu.Enable(ID_SAVE_PRINTER_AS, False)

        file_menu.AppendSeparator()

        file_menu.Append(ID_LOAD_BOARD, "Load board",
                         "Load a board configuration file.")
        self.Bind(wx.EVT_MENU, self.pgBoard.onLoadConfig, id=ID_LOAD_BOARD)

        file_menu.Append(ID_SAVE_BOARD, "Save board",
                         "Save board configuration.")
        self.Bind(wx.EVT_MENU, self.onSaveBoardConfig, id=ID_SAVE_BOARD)
        file_menu.Enable(ID_SAVE_BOARD, False)

        file_menu.Append(ID_SAVE_BOARD_AS, "Save board as...",
                         "Save board configuration to a new file.")
        self.Bind(wx.EVT_MENU, self.onSaveBoardConfigAs, id=ID_SAVE_BOARD_AS)
        file_menu.Enable(ID_SAVE_BOARD_AS, False)

        file_menu.AppendSeparator()

        file_menu.Append(wx.ID_EXIT, "E&xit", "Exit the application.")
        self.Bind(wx.EVT_MENU, self.onClose, id=wx.ID_EXIT)

        self.fileMenu = file_menu

        menu_bar = wx.MenuBar()

        menu_bar.Append(file_menu, "&File")

        edit_menu = wx.Menu()

        edit_menu.Append(ID_SETTINGS, "Settings", "Change settings.")
        self.Bind(wx.EVT_MENU, self.onEditSettings, id=ID_SETTINGS)

        self.editMenu = edit_menu

        menu_bar.Append(edit_menu, "&Edit")

        build_menu = wx.Menu()

        build_menu.Append(ID_BUILD, "Build", "Build the executable.")
        self.Bind(wx.EVT_MENU, self.onBuild, id=ID_BUILD)

        build_menu.Append(ID_UPLOAD, "Upload", "Upload the executable.")
        self.Bind(wx.EVT_MENU, self.onUpload, id=ID_UPLOAD)

        self.buildMenu = build_menu

        menu_bar.Append(build_menu, "&Build")

        help_menu = wx.Menu()

        help_menu.Append(ID_HELP, "Help", "Find help.")
        self.Bind(wx.EVT_MENU, self.onHelp, id=ID_HELP)

        help_menu.Append(ID_REPORT, "Report problem",
                         "Report a problem to Teacup maintainers.")
        self.Bind(wx.EVT_MENU, self.onReportProblem, id=ID_REPORT)

        help_menu.AppendSeparator()

        help_menu.Append(ID_ABOUT, "About Teacup")
        self.Bind(wx.EVT_MENU, self.onAbout, id=ID_ABOUT)

        self.helpMenu = help_menu

        menu_bar.Append(help_menu, "&Help")

        self.SetMenuBar(menu_bar)
        loadFlag = self.checkEnableLoadConfig()
        self.checkEnableUpload()
        if loadFlag:
            self.loadConfigFile("config.h")

    def onSaveBoardConfig(self, evt):
        rc = self.pgBoard.onSaveConfig(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSaveBoardConfigAs(self, evt):
        rc = self.pgBoard.onSaveConfigAs(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSavePrinterConfig(self, evt):
        rc = self.pgPrinter.onSaveConfig(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSavePrinterConfigAs(self, evt):
        rc = self.pgPrinter.onSaveConfigAs(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def checkEnableLoadConfig(self):
        fn = os.path.join(cmd_folder, "config.h")
        if os.path.isfile(fn):
            self.fileMenu.Enable(ID_LOAD_CONFIG, True)
            self.buildMenu.Enable(ID_BUILD, True)
            return True
        else:
            self.fileMenu.Enable(ID_LOAD_CONFIG, False)
            self.buildMenu.Enable(ID_BUILD, False)
            return False

    def checkEnableUpload(self):
        fn = os.path.join(cmd_folder, "teacup.hex")
        if os.path.isfile(fn):
            self.buildMenu.Enable(ID_UPLOAD, True)
        else:
            self.buildMenu.Enable(ID_UPLOAD, False)

    def enableSavePrinter(self, saveFlag, saveAsFlag):
        self.fileMenu.Enable(ID_SAVE_PRINTER, saveFlag)
        self.fileMenu.Enable(ID_SAVE_PRINTER_AS, saveAsFlag)
        self.savePrtEna = saveAsFlag
        self.protPrtFile = not saveFlag
        if self.savePrtEna and self.saveBrdEna:
            self.enableSaveConfig(True)
        else:
            self.enableSaveConfig(False)

    def enableSaveBoard(self, saveFlag, saveAsFlag):
        self.fileMenu.Enable(ID_SAVE_BOARD, saveFlag)
        self.fileMenu.Enable(ID_SAVE_BOARD_AS, saveAsFlag)
        self.saveBrdEna = saveAsFlag
        self.protBrdFile = not saveFlag
        if self.savePrtEna and self.saveBrdEna:
            self.enableSaveConfig(True)
        else:
            self.enableSaveConfig(False)

    def enableSaveConfig(self, flag):
        self.fileMenu.Enable(ID_SAVE_CONFIG, flag)

    def onLoadConfig(self, evt):
        self.loadConfigFile("config.h")

    def loadConfigFile(self, fn):
        if not self.pgPrinter.confirmLoseChanges("load config"):
            return False

        if not self.pgBoard.confirmLoseChanges("load config"):
            return False

        pfile, bfile = self.getConfigFileNames(fn)

        if not pfile:
            self.message(
                "Config file did not contain a printer file "
                "include statement.", "Config error")
            return False
        else:
            if not self.pgPrinter.loadConfigFile(pfile):
                self.message(
                    "There was a problem loading the printer config file:\n%s"
                    % pfile, "Config error")
                return False

        if not bfile:
            self.message(
                "Config file did not contain a board file "
                "include statement.", "Config error")
            return False
        else:
            if not self.pgBoard.loadConfigFile(bfile):
                self.message(
                    "There was a problem loading the board config file:\n%s" %
                    bfile, "Config error")
                return False

        return True

    def getConfigFileNames(self, fn):
        pfile = None
        bfile = None
        path = os.path.join(cmd_folder, fn)
        try:
            cfgBuffer = list(open(path))
        except:
            self.message("Unable to process config file %s." % fn,
                         "File error")
            return None, None

        for ln in cfgBuffer:
            if not ln.lstrip().startswith("#include"):
                continue

            m = reInclude.search(ln)
            if m:
                t = m.groups()
                if len(t) == 1:
                    if "printer." in t[0]:
                        if pfile:
                            self.message(
                                "Multiple printer file include statements.\n"
                                "Ignoring %s." % ln, "Config error",
                                wx.OK + wx.ICON_WARNING)
                        else:
                            pfile = os.path.join(cmd_folder, t[0])
                    elif "board." in t[0]:
                        if bfile:
                            self.message(
                                "Multiple board file include statements.\n"
                                "Ignoring %s." % ln, "Config error",
                                wx.OK + wx.ICON_WARNING)
                        else:
                            bfile = os.path.join(cmd_folder, t[0])
                    else:
                        self.message(
                            "Unable to parse include statement:\n%s" % ln,
                            "Config error")

        return pfile, bfile

    def onSaveConfig(self, evt):
        fn = os.path.join(cmd_folder, "config.h")
        try:
            fp = open(fn, 'w')
        except:
            self.message("Unable to open config.h for output.", "File error")
            return False

        bfn = self.pgBoard.getFileName()
        if self.pgBoard.isModified() and self.pgBoard.isValid():
            if not self.pgBoard.saveConfigFile(bfn):
                return False
        else:
            self.pgBoard.generateTempTables()

        pfn = self.pgPrinter.getFileName()
        if self.pgPrinter.isModified() and self.pgPrinter.isValid():
            if not self.pgPrinter.saveConfigFile(pfn):
                return False

        prefix = cmd_folder + os.path.sep
        lpfx = len(prefix)

        if bfn.startswith(prefix):
            rbfn = bfn[lpfx:]
        else:
            rbfn = bfn

        if pfn.startswith(prefix):
            rpfn = pfn[lpfx:]
        else:
            rpfn = pfn

        fp.write("\n")
        fp.write("// Configuration for controller board.\n")
        fp.write("#include \"%s\"\n" % rbfn)
        fp.write("\n")
        fp.write("// Configuration for printer board.\n")
        fp.write("#include \"%s\"\n" % rpfn)

        fp.close()

        self.checkEnableLoadConfig()
        return True

    def onBuild(self, evt):
        self.onBuildorUpload(True)

    def onUpload(self, evt):
        self.onBuildorUpload(False)

    def onBuildorUpload(self, buildFlag):
        if not (self.pgPrinter.hasData() or self.pgBoard.hasData()):
            dlg = wx.MessageDialog(
                self, "Data needs to be loaded. "
                "Click Yes to load config.h.", "Data missing",
                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
            rc = dlg.ShowModal()
            dlg.Destroy()
            if rc != wx.ID_YES:
                return

            self.loadConfigFile("config.h")
        else:
            if self.pgPrinter.isModified():
                dlg = wx.MessageDialog(
                    self, "Printer data needs to be saved. Click "
                    "Yes to save printer configuration.", "Changes pending",
                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
                rc = dlg.ShowModal()
                dlg.Destroy()
                if rc != wx.ID_YES:
                    return

                if self.protPrtFile:
                    rc = self.onSavePrinterConfigAs(None)
                else:
                    rc = self.onSavePrinterConfig(None)
                if not rc:
                    return

            if self.pgBoard.isModified():
                dlg = wx.MessageDialog(
                    self, "Board data needs to be saved. Click "
                    "Yes to save board configuration.", "Changes pending",
                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
                rc = dlg.ShowModal()
                dlg.Destroy()
                if rc != wx.ID_YES:
                    return

                if self.protBrdFile:
                    rc = self.onSaveBoardConfigAs(None)
                else:
                    rc = self.onSaveBoardConfig(None)
                if not rc:
                    return

        if not self.verifyConfigLoaded():
            dlg = wx.MessageDialog(
                self, "Loaded configuration does not match the "
                "config.h file. Click Yes to save config.h.",
                "Configuration changed",
                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
            rc = dlg.ShowModal()
            dlg.Destroy()
            if rc != wx.ID_YES:
                return

            if not self.onSaveConfig(None):
                return

        f_cpu, cpu = self.pgBoard.getCPUInfo()
        if not cpu:
            dlg = wx.MessageDialog(self, "Unable to determine CPU type.",
                                   "CPU type error", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        if not f_cpu:
            dlg = wx.MessageDialog(self, "Unable to determine CPU clock rate.",
                                   "CPU clock rate error",
                                   wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        if buildFlag:
            dlg = Build(self, self.settings, f_cpu, cpu)
            dlg.ShowModal()
            dlg.Destroy()
            self.checkEnableUpload()
        else:
            dlg = Upload(self, self.settings, f_cpu, cpu)
            dlg.ShowModal()
            dlg.Destroy()

    def verifyConfigLoaded(self):
        pfile, bfile = self.getConfigFileNames("config.h")
        lpfile = self.pgPrinter.getFileName()
        lbfile = self.pgBoard.getFileName()

        return ((pfile == lpfile) and (bfile == lbfile))

    def onEditSettings(self, evt):
        dlg = SettingsDlg(self, self.settings)
        rc = dlg.ShowModal()
        dlg.Destroy()

    def onHelp(self, evt):
        self.message(
            "Find help by hovering slowly over the buttons and text "
            "fields. Tooltip should appear, explaining things.",
            "Find help",
            style=wx.OK)

    def onReportProblem(self, evt):
        import urllib
        import webbrowser
        import subprocess
        from sys import platform

        # Testing allowed URLs up to 32 kB in size. Longer URLs are simply chopped.
        mailRecipients ="reply+0004dc756da9f0641af0a3834c580ad5be469f4f6b" \
                        "5d4cfc92cf00000001118c958a92a169ce051faa8c@" \
                        "reply.github.com,[email protected]"
        mailSubject = "Teacup problem report"
        mailBody = "Please answer these questions before hitting \"send\":\n\n" \
                   "What did you try to do?\n\n\n" \
                   "What did you expect to happen?\n\n\n" \
                   "What happened instead?\n\n\n\n" \
                   "To allow developers to help, configuration files are " \
                   "attached, with help comments stripped:\n"

        for f in self.pgBoard.getFileName(), self.pgPrinter.getFileName():
            if not f:
                mailBody += "\n(no file loaded)\n"
                continue

            mailBody += "\n" + os.path.basename(f) + ":\n"
            mailBody += "----------------------------------------------\n"
            try:
                fc = open(f).read()
                fc = reHelpText.sub("", fc)
                mailBody += fc
            except:
                mailBody += "(could not read this file)\n"
            mailBody += "----------------------------------------------\n"

        url = "mailto:" + urllib.quote(mailRecipients) + \
              "?subject=" + urllib.quote(mailSubject) + \
              "&body=" + urllib.quote(mailBody)

        # This is a work around a bug in gvfs-open coming with (at least) Ubuntu
        # 15.04. gvfs-open would open mailto:///[email protected] instead of
        # the requested mailto:[email protected].
        if platform.startswith("linux"):
            try:
                subprocess.check_output(["gvfs-open", "--help"])

                # Broken gvfs-open exists, so it might be used.
                # Try to open the URL directly.
                for urlOpener in "thunderbird", "evolution", "firefox", "mozilla", \
                                 "epiphany", "konqueror", "chromium-browser", \
                                 "google-chrome":
                    try:
                        subprocess.check_output([urlOpener, url],
                                                stderr=subprocess.STDOUT)
                        return
                    except:
                        pass
            except:
                pass

        webbrowser.open_new(url)

    def onAbout(self, evt):
        # Get the contributors' top 10 with something like this:
        #   export B=experimental
        #   git log $B | grep "Author:" | sort | uniq | while \
        #     read A; do N=$(git log $B | grep "$A" | wc -l); echo "$N $A"; done | \
        #     sort -rn
        self.message(
            "Teacup Firmware is a 3D Printer and CNC machine controlling "
            "firmware with emphasis on performance, efficiency and "
            "outstanding quality. What Teacup does, shall it do very well."
            "\n\n\n"
            "Lots of people hard at work! Top 10 contributors:\n\n"
            "    Markus Hitter (542 commits)\n"
            "    Michael Moon (322 commits)\n"
            "    Phil Hord (55 commits)\n"
            "    Jeff Bernardis (51 commits)\n"
            "    Markus Amsler (47 commits)\n"
            "    David Forrest (27 commits)\n"
            "    Jim McGee (15 commits)\n"
            "    Ben Jackson (12 commits)\n"
            "    Bas Laarhoven (10 commits)\n"
            "    Stephan Walter (9 commits)\n"
            "    Roland Brochard (3 commits)\n"
            "    Jens Ch. Restemeier (3 commits)\n",
            "About Teacup",
            style=wx.OK)

    def message(self, text, title, style=wx.OK + wx.ICON_ERROR):
        dlg = wx.MessageDialog(self, text, title, style)
        dlg.ShowModal()
        dlg.Destroy()
コード例 #13
0
class PrinterPanel(wx.Panel):
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent

        self.deco = Decoration()
        self.protFileLoaded = False

        self.settings = settings

        self.printer = Printer(self.settings)

        self.dir = os.path.join(self.settings.folder, "config")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgMech = self.registerPage(MechanicalPage, "Mechanical")
        self.pgAcc = self.registerPage(AccelerationPage, "Acceleration")
        self.pgMiscellaneous = self.registerPage(MiscellaneousPage,
                                                 "Miscellaneous")

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()

    def registerPage(self, klass, label, *args, **kwargs):
        page = klass(self,
                     self.nb,
                     len(self.pages),
                     *args,
                     font=self.settings.font,
                     **kwargs)
        self.nb.AddPage(page, label)
        self.pages.append(page)
        self.titles.append(label)
        self.pageModified.append(False)
        self.pageValid.append(True)
        return page

    def assertModified(self, pg, flag=True):
        self.pageModified[pg] = flag
        self.modifyTab(pg)

    def isModified(self):
        return (True in self.pageModified)

    def isValid(self):
        return not (False in self.pageValid)

    def hasData(self):
        return self.printer.hasData()

    def getFileName(self):
        return self.printer.configFile

    def assertValid(self, pg, flag=True):
        self.pageValid[pg] = flag
        self.modifyTab(pg)

        if False in self.pageValid:
            self.parent.enableSavePrinter(False, False)
        else:
            self.parent.enableSavePrinter(not self.protFileLoaded, True)

    def modifyTab(self, pg):
        if self.pageModified[pg] and not self.pageValid[pg]:
            pfx = "?* "
        elif self.pageModified[pg]:
            pfx = "* "
        elif not self.pageValid[pg]:
            pfx = "? "
        else:
            pfx = ""

        self.nb.SetPageText(pg, pfx + self.titles[pg])
        if True in self.pageModified and False in self.pageValid:
            pfx = "?* "
        elif True in self.pageModified:
            pfx = "* "
        elif False in self.pageValid:
            pfx = "? "
        else:
            pfx = ""
        self.parent.setPrinterTabDecor(pfx)

    def setHeaters(self, ht):
        return self.pgMiscellaneous.setHeaters(ht)

    def onClose(self, evt):
        if not self.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def confirmLoseChanges(self, msg):
        if True not in self.pageModified:
            return True

        dlg = wx.MessageDialog(
            self, "Are you sure you want to " + msg + "?\n"
            "There are changes to your printer "
            "configuration that will be lost.", "Changes pending",
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()

        if rc != wx.ID_YES:
            return False

        return True

    def onLoadConfig(self, evt):
        if not self.confirmLoseChanges("load a new printer configuration"):
            return

        if platform.startswith("darwin"):
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Printer configuration (printer.*.h)|*.h"
        else:
            wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Choose a printer config file",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.OPEN | wx.CHANGE_DIR)

        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

        dlg.Destroy()
        if path is None:
            return

        self.dir = os.path.dirname(path)
        rc, efn = self.loadConfigFile(path)

        if not rc:
            dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

    def loadConfigFile(self, fn):
        ok, file = self.printer.loadConfigFile(fn)
        if not ok:
            return ok, file

        if os.path.basename(fn) in protectedFiles:
            self.parent.enableSavePrinter(False, True)
            self.protFileLoaded = True
        else:
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        self.parent.setPrinterTabFile(os.path.basename(fn))

        for pg in self.pages:
            pg.insertValues(self.printer.cfgValues)
            pg.setHelpText(self.printer.helpText)

        k = 'DC_EXTRUDER'
        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 onSaveConfig(self, evt):
        path = self.getFileName()
        return self.saveConfigFile(path)

    def onSaveConfigAs(self, evt):
        if platform.startswith("darwin"):
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Printer configuration (printer.*.h)|*.h"
        else:
            wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Save as ...",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        val = dlg.ShowModal()

        if val != wx.ID_OK:
            dlg.Destroy()
            return

        path = dlg.GetPath()
        dlg.Destroy()

        rc = self.saveConfigFile(path)
        if rc:
            self.parent.setPrinterTabFile(os.path.basename(path))
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        return rc

    def saveConfigFile(self, path):
        if os.path.basename(path) in protectedFiles:
            dlg = wx.MessageDialog(
                self, "It's not allowed to overwrite files "
                "distributed by Teacup. Choose another name.",
                "Protected file error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        if not os.path.basename(path).startswith("printer."):
            dlg = wx.MessageDialog(
                self, "Illegal file name: %s.\n"
                "File name must begin with \"printer.\"" % path,
                "Illegal file name", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            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)

        if ext == "":
            path += ".h"

        try:
            self.printer.saveConfigFile(path, values)
        except:
            dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        return True
コード例 #14
0
class Page:
    def __init__(self, font):
        self.modified = False
        self.valid = True
        self.fieldValid = {}
        self.textControls = {}
        self.textControlsOriginal = {}
        self.checkBoxes = {}
        self.radioButtons = {}
        self.radioButtonBoxes = {}
        self.choices = {}
        self.choicesOriginal = {}
        self.boolChoices = {}
        self.deco = Decoration()
        self.font = font

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

    def enableAll(self, flag=True):
        for c in self.textControls.keys():
            self.textControls[c].Enable(flag)
        for c in self.checkBoxes.keys():
            self.checkBoxes[c].Enable(flag)
        for c in self.radioButtons.keys():
            self.radioButtons[c].Enable(flag)
        for c in self.choices.keys():
            self.choices[c].Enable(flag)

    def addTextCtrl(self, name, labelWidth, validator):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(
            self,
            wx.ID_ANY,
            self.labels[name] + " ",
            size=(labelWidth, -1),
            style=wx.ALIGN_RIGHT,
        )
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetTcLabel)

        tc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_RIGHT, name=name)
        tc.SetFont(self.font)
        self.fieldValid[name] = True
        tc.Bind(wx.EVT_TEXT, validator)
        self.textControls[name] = tc
        lsz.Add(tc)

        return lsz

    def addCheckBox(self, name, validator):
        if name in self.labels.keys():
            lbl = self.labels[name]
        else:
            lbl = name
        cb = wx.CheckBox(self, wx.ID_ANY, lbl)
        cb.SetFont(self.font)
        cb.Bind(wx.EVT_CHECKBOX, validator)
        self.checkBoxes[name] = cb

        return cb

    def addRadioButton(self, name, style, validator, sbox=None):
        rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style=style)
        rb.SetFont(self.font)
        self.Bind(wx.EVT_RADIOBUTTON, validator, rb)
        self.radioButtons[name] = rb
        if sbox is not None:
            self.radioButtonBoxes[name] = sbox

        return rb

    def addChoice(self,
                  name,
                  choices,
                  selection,
                  labelWidth,
                  validator,
                  size=(-1, -1)):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(
            self,
            wx.ID_ANY,
            self.labels[name],
            size=(labelWidth, -1),
            style=wx.ALIGN_RIGHT,
        )
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetChLabel)

        ch = wx.Choice(self, wx.ID_ANY, choices=choices, size=size, name=name)
        ch.SetBackgroundColour(self.deco.getBackgroundColour())
        ch.SetFont(self.font)
        ch.Bind(wx.EVT_CHOICE, validator)
        ch.SetSelection(selection)
        lsz.Add(ch)
        self.choices[name] = ch

        return lsz

    def addPinChoice(self, name, labelWidth):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(
            self,
            wx.ID_ANY,
            self.labels[name],
            size=(labelWidth, -1),
            style=wx.ALIGN_RIGHT,
        )
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetChLabel)

        ch = wx.Choice(self, wx.ID_ANY, name=name, style=wx.CB_SORT)
        ch.SetBackgroundColour(self.deco.getBackgroundColour())
        ch.SetFont(self.font)
        ch.AppendItems(["-"] + pinNames)
        ch.Bind(wx.EVT_CHOICE, self.onChoice)
        self.choices[name] = ch
        lsz.Add(ch)

        return lsz

    # addChoice handles #defines with value, this handles choices for
    # sets of boolean #defines.
    def addBoolChoice(self,
                      name,
                      allowBlank,
                      labelWidth,
                      validator,
                      size=(-1, -1)):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(
            self,
            wx.ID_ANY,
            self.labels[name],
            size=(labelWidth, -1),
            style=wx.ALIGN_RIGHT,
        )
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetChLabel)

        ch = wx.Choice(self, wx.ID_ANY, size=size, name=name)
        ch.SetBackgroundColour(self.deco.getBackgroundColour())
        ch.SetFont(self.font)
        ch.Bind(wx.EVT_CHOICE, validator)

        if allowBlank:
            ch.Append("(none)")
            ch.SetSelection(0)

        lsz.Add(ch)
        self.boolChoices[name] = ch

        return lsz

    def setChoice(self, name, cfgValues, default):
        if name in cfgValues.keys() and cfgValues[name][1] == True:
            bv = cfgValues[name][0]
        else:
            bv = default

        s = self.choices[name].FindString(bv)
        if s < 0:
            s = self.choices[name].FindString(default)
            if s < 0:
                s = 0

        self.choices[name].SetSelection(s)

    def onTextCtrlInteger(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        name = tc.GetName()
        w = tc.GetValue().strip()
        if w == "":
            valid = True
        else:
            m = reInteger.match(w)
            if m:
                valid = True
            else:
                valid = False

        self.setFieldValidity(name, valid)

        if valid:
            tc.SetBackgroundColour(
                wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
        else:
            tc.SetBackgroundColour("pink")
        tc.Refresh()
        evt.Skip()

    def onTextCtrlFloat(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        name = tc.GetName()
        w = tc.GetValue().strip()
        if w == "":
            valid = True
        else:
            m = reFloat.match(w)
            if m:
                valid = True
            else:
                valid = False

        self.setFieldValidity(name, valid)

        if valid:
            tc.SetBackgroundColour(
                wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
        else:
            tc.SetBackgroundColour("pink")
        tc.Refresh()
        evt.Skip()

    def onTextCtrlPin(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        self.validatePin(tc)
        evt.Skip()

    def onTextCtrl(self, evt):
        self.assertModified(True)
        evt.Skip()

    def onChoice(self, evt):
        self.assertModified(True)
        evt.Skip()

    def onCheckBox(self, evt):
        self.assertModified(True)
        evt.Skip()

    def setHelpText(self, ht):
        for k in self.textControls.keys():
            if k in ht.keys():
                self.textControls[k].SetToolTip(ht[k])

        for k in self.checkBoxes.keys():
            if k in ht.keys():
                self.checkBoxes[k].SetToolTip(ht[k])

        for k in self.radioButtons.keys():
            if k in ht.keys():
                self.radioButtons[k].SetToolTip(ht[k])
                if k in self.radioButtonBoxes.keys():
                    self.radioButtonBoxes[k].SetToolTip(ht[k])

        for k in self.choices.keys():
            if k in ht.keys():
                self.choices[k].SetToolTip(ht[k])

        for k in self.boolChoices.keys():
            for candidate in ht.keys():
                if candidate.startswith(k):
                    self.boolChoices[k].SetToolTip(ht[candidate])
                    break

    def insertValues(self, cfgValues):
        self.assertValid(True)
        self.enableAll(True)
        for k in self.fieldValid.keys():
            self.fieldValid[k] = True

        for k in self.checkBoxes.keys():
            if k in cfgValues.keys() and cfgValues[k]:
                self.checkBoxes[k].SetValue(True)
            else:
                self.checkBoxes[k].SetValue(False)

        for k in self.textControls.keys():
            if k in cfgValues.keys():
                self.textControlsOriginal[k] = cfgValues[k]
                if cfgValues[k][1] == True:
                    self.textControls[k].SetValue(str(cfgValues[k][0]))
                else:
                    self.textControls[k].SetValue("")
            else:
                print("Key " + k + " not found in config data.")

        for k in self.choices.keys():
            if k in cfgValues.keys():
                self.choicesOriginal[k] = cfgValues[k]
                self.setChoice(k, cfgValues, "-")
            else:
                print("Key " + k + " not found in config data.")

        for k in self.boolChoices.keys():
            choice = self.boolChoices[k]

            # Remove items left behind from the previous configuration.
            while choice.GetCount(
            ) and not choice.GetString(choice.GetCount() - 1).startswith("("):
                choice.Delete(choice.GetCount() - 1)

            # Add items found in this configuration.
            for cfg in cfgValues.keys():
                if cfg.startswith(k):
                    if cfg in self.labels.keys():
                        choice.Append(self.labels[cfg])
                    else:
                        choice.Append(cfg)

                    # As we want to write the configuration name later, not the user
                    # friendly string, we store the configuration name as client data.
                    n = choice.GetCount() - 1
                    choice.SetClientData(n, cfg)

                    if cfgValues[cfg]:
                        choice.SetSelection(n)

        self.assertModified(False)

    def getValues(self):
        self.assertModified(False)
        result = {}

        for k in self.checkBoxes.keys():
            cb = self.checkBoxes[k]
            result[k] = cb.IsChecked()

        for k in self.textControls.keys():
            v = self.textControls[k].GetValue()
            if v == "":
                if k in self.textControlsOriginal.keys():
                    result[k] = self.textControlsOriginal[k][0], False
                else:
                    result[k] = "", False
            else:
                result[k] = v, True

        for k in self.radioButtons.keys():
            result[k] = self.radioButtons[k].GetValue(), True

        for k in self.choices.keys():
            v = self.choices[k].GetSelection()
            s = self.choices[k].GetString(v)
            if s == "-":
                if k in self.choicesOriginal.keys():
                    result[k] = self.choicesOriginal[k][0], False
                else:
                    result[k] = "", False
            else:
                result[k] = s, True

        for k in self.boolChoices.keys():
            choice = self.boolChoices[k]
            for i in range(choice.GetCount()):
                s = choice.GetClientData(i)
                if s:
                    result[s] = i == choice.GetSelection()

        return result

    def assertModified(self, flag):
        if flag != self.modified:
            self.parent.assertModified(self.id, flag)
            self.modified = flag

    def setFieldValidity(self, name, flag):
        self.fieldValid[name] = flag

        pgValid = True
        for k in self.fieldValid.keys():
            if not self.fieldValid[k]:
                pgValid = False
                break

        self.assertValid(pgValid)

    def assertValid(self, flag):
        if flag != self.valid:
            self.parent.assertValid(self.id, flag)
            self.valid = flag
コード例 #15
0
class ConfigFrame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, None, -1, "Teacup Configtool", size = (880, 550))
    self.Bind(wx.EVT_CLOSE, self.onClose)
    self.Bind(wx.EVT_SIZE, self.onResize)

    self.deco = Decoration()

    panel = wx.Panel(self, -1)
    panel.SetBackgroundColour(self.deco.getBackgroundColour())
    panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

    self.settings = Settings(self, cmd_folder)
    self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
                                 wx.FONTWEIGHT_BOLD)
    self.settings.folder = cmd_folder

    self.heaters = []
    self.savePrtEna = False
    self.saveBrdEna = False
    self.protPrtFile = False
    self.protBrdFile = False

    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(panel, wx.ID_ANY, size = (880, 550),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.printerFileName = None
    self.printerTabDecor = ""
    self.printerBaseText = "Printer"
    self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgPrinter, self.printerBaseText)

    self.boardFileName = None
    self.boardTabDecor = ""
    self.boardBaseText = "Board"
    self.pgBoard = BoardPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgBoard, self.boardBaseText)

    panel.Fit()
    self.panel = panel

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
    self.SetSizer(sz)
    self.makeMenu()

  def onClose(self, evt):
    if not self.pgPrinter.confirmLoseChanges("exit"):
      return

    if not self.pgBoard.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def onResize(self, evt):
    self.panel.SetSize(self.GetClientSize())
    self.Refresh()
    evt.Skip();

  def setPrinterTabFile(self, fn):
    self.printerFileName = fn
    self.updatePrinterTab()

  def setPrinterTabDecor(self, prefix):
    self.printerTabDecor = prefix
    self.updatePrinterTab()

  def updatePrinterTab(self):
    txt = self.printerTabDecor + self.printerBaseText
    if self.printerFileName:
      txt += " <%s>" % self.printerFileName
    self.nb.SetPageText(0, txt)

  def setBoardTabFile(self, fn):
    self.boardFileName = fn
    self.updateBoardTab()

  def setBoardTabDecor(self, prefix):
    self.boardTabDecor = prefix
    self.updateBoardTab()

  def updateBoardTab(self):
    txt = self.boardTabDecor + self.boardBaseText
    if self.boardFileName:
      txt += " <%s>" % self.boardFileName
    self.nb.SetPageText(1, txt)

  def setHeaters(self, ht):
    self.heaters = ht
    self.pgPrinter.setHeaters(ht)

  def makeMenu(self):
    file_menu = wx.Menu()

    file_menu.Append(ID_LOAD_CONFIG, "Load config.h",
                     "Load config.h and its named printer and board files.")
    self.Bind(wx.EVT_MENU, self.onLoadConfig, id = ID_LOAD_CONFIG)
    file_menu.Enable(ID_LOAD_CONFIG, False)

    file_menu.Append(ID_SAVE_CONFIG, "Save config.h", "Save config.h file.")
    self.Bind(wx.EVT_MENU, self.onSaveConfig, id = ID_SAVE_CONFIG)
    file_menu.Enable(ID_SAVE_CONFIG, False)

    file_menu.AppendSeparator()

    file_menu.Append(ID_LOAD_PRINTER, "Load printer",
                     "Load a printer configuration file.")
    self.Bind(wx.EVT_MENU, self.pgPrinter.onLoadConfig, id = ID_LOAD_PRINTER)

    file_menu.Append(ID_SAVE_PRINTER, "Save printer",
                     "Save printer configuration.")
    self.Bind(wx.EVT_MENU, self.onSavePrinterConfig, id = ID_SAVE_PRINTER)
    file_menu.Enable(ID_SAVE_PRINTER, False)

    file_menu.Append(ID_SAVE_PRINTER_AS, "Save printer as...",
                     "Save printer configuration to a new file.")
    self.Bind(wx.EVT_MENU, self.onSavePrinterConfigAs, id = ID_SAVE_PRINTER_AS)
    file_menu.Enable(ID_SAVE_PRINTER_AS, False)

    file_menu.AppendSeparator()

    file_menu.Append(ID_LOAD_BOARD, "Load board",
                     "Load a board configuration file.")
    self.Bind(wx.EVT_MENU, self.pgBoard.onLoadConfig, id = ID_LOAD_BOARD)

    file_menu.Append(ID_SAVE_BOARD, "Save board", "Save board configuration.")
    self.Bind(wx.EVT_MENU, self.onSaveBoardConfig, id = ID_SAVE_BOARD)
    file_menu.Enable(ID_SAVE_BOARD, False)

    file_menu.Append(ID_SAVE_BOARD_AS, "Save board as...",
                     "Save board configuration to a new file.")
    self.Bind(wx.EVT_MENU, self.onSaveBoardConfigAs, id = ID_SAVE_BOARD_AS)
    file_menu.Enable(ID_SAVE_BOARD_AS, False)

    file_menu.AppendSeparator()

    file_menu.Append(wx.ID_EXIT, "E&xit", "Exit the application.")
    self.Bind(wx.EVT_MENU, self.onClose, id = wx.ID_EXIT)

    self.fileMenu = file_menu

    menu_bar = wx.MenuBar()

    menu_bar.Append(file_menu, "&File")

    edit_menu = wx.Menu()

    edit_menu.Append(ID_SETTINGS, "Settings", "Change settings.")
    self.Bind(wx.EVT_MENU, self.onEditSettings, id = ID_SETTINGS)

    self.editMenu = edit_menu

    menu_bar.Append(edit_menu, "&Edit")

    build_menu = wx.Menu()

    build_menu.Append(ID_BUILD, "Build", "Build the executable.")
    self.Bind(wx.EVT_MENU, self.onBuild, id = ID_BUILD)

    build_menu.Append(ID_UPLOAD, "Upload", "Upload the executable.")
    self.Bind(wx.EVT_MENU, self.onUpload, id = ID_UPLOAD)

    self.buildMenu = build_menu

    menu_bar.Append(build_menu, "&Build")

    help_menu = wx.Menu()

    help_menu.Append(ID_HELP, "Help", "Find help.")
    self.Bind(wx.EVT_MENU, self.onHelp, id = ID_HELP)

    help_menu.Append(ID_REPORT, "Report problem",
                     "Report a problem to Teacup maintainers.")
    self.Bind(wx.EVT_MENU, self.onReportProblem, id = ID_REPORT)

    help_menu.AppendSeparator()

    help_menu.Append(ID_ABOUT, "About Teacup")
    self.Bind(wx.EVT_MENU, self.onAbout, id = ID_ABOUT)

    self.helpMenu = help_menu

    menu_bar.Append(help_menu, "&Help")

    self.SetMenuBar(menu_bar)
    loadFlag = self.checkEnableLoadConfig()
    self.checkEnableUpload()
    if loadFlag:
      self.loadConfigFile("config.h")

  def onSaveBoardConfig(self, evt):
    rc = self.pgBoard.onSaveConfig(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSaveBoardConfigAs(self, evt):
    rc = self.pgBoard.onSaveConfigAs(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSavePrinterConfig(self, evt):
    rc = self.pgPrinter.onSaveConfig(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSavePrinterConfigAs(self, evt):
    rc = self.pgPrinter.onSaveConfigAs(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def checkEnableLoadConfig(self):
    fn = os.path.join(cmd_folder, "config.h")
    if os.path.isfile(fn):
      self.fileMenu.Enable(ID_LOAD_CONFIG, True)
      self.buildMenu.Enable(ID_BUILD, True)
      return True
    else:
      self.fileMenu.Enable(ID_LOAD_CONFIG, False)
      self.buildMenu.Enable(ID_BUILD, False)
      return False

  def checkEnableUpload(self):
    fn = os.path.join(cmd_folder, "teacup.hex")
    if os.path.isfile(fn):
      self.buildMenu.Enable(ID_UPLOAD, True)
    else:
      self.buildMenu.Enable(ID_UPLOAD, False)

  def enableSavePrinter(self, saveFlag, saveAsFlag):
    self.fileMenu.Enable(ID_SAVE_PRINTER, saveFlag)
    self.fileMenu.Enable(ID_SAVE_PRINTER_AS, saveAsFlag)
    self.savePrtEna = saveAsFlag
    self.protPrtFile = not saveFlag
    if self.savePrtEna and self.saveBrdEna:
      self.enableSaveConfig(True)
    else:
      self.enableSaveConfig(False)

  def enableSaveBoard(self, saveFlag, saveAsFlag):
    self.fileMenu.Enable(ID_SAVE_BOARD, saveFlag)
    self.fileMenu.Enable(ID_SAVE_BOARD_AS, saveAsFlag)
    self.saveBrdEna = saveAsFlag
    self.protBrdFile = not saveFlag
    if self.savePrtEna and self.saveBrdEna:
      self.enableSaveConfig(True)
    else:
      self.enableSaveConfig(False)

  def enableSaveConfig(self, flag):
    self.fileMenu.Enable(ID_SAVE_CONFIG, flag)

  def onLoadConfig(self, evt):
    self.loadConfigFile("config.h")

  def loadConfigFile(self, fn):
    if not self.pgPrinter.confirmLoseChanges("load config"):
      return False

    if not self.pgBoard.confirmLoseChanges("load config"):
      return False

    pfile, bfile = self.getConfigFileNames(fn)

    if not pfile:
      self.message("Config file did not contain a printer file "
                   "include statement.", "Config error")
      return False
    else:
      if not self.pgPrinter.loadConfigFile(pfile):
        self.message("There was a problem loading the printer config file:\n%s"
                     % pfile, "Config error")
        return False

    if not bfile:
      self.message("Config file did not contain a board file "
                   "include statement.", "Config error")
      return False
    else:
      if not self.pgBoard.loadConfigFile(bfile):
        self.message("There was a problem loading the board config file:\n%s"
                     % bfile, "Config error")
        return False

    return True

  def getConfigFileNames(self, fn):
    pfile = None
    bfile = None
    path = os.path.join(cmd_folder, fn)
    try:
      cfgBuffer = list(open(path))
    except:
      self.message("Unable to process config file %s." % fn, "File error")
      return None, None

    for ln in cfgBuffer:
      if not ln.lstrip().startswith("#include"):
        continue

      m = reInclude.search(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if "printer." in t[0]:
            if pfile:
              self.message("Multiple printer file include statements.\n"
                           "Ignoring %s." % ln, "Config error",
                           wx.OK + wx.ICON_WARNING)
            else:
              pfile = os.path.join(cmd_folder, t[0])
          elif "board." in t[0]:
            if bfile:
              self.message("Multiple board file include statements.\n"
                           "Ignoring %s." % ln, "Config error",
                           wx.OK + wx.ICON_WARNING)
            else:
              bfile = os.path.join(cmd_folder, t[0])
          else:
            self.message("Unable to parse include statement:\n%s" % ln,
                         "Config error")

    return pfile, bfile

  def onSaveConfig(self, evt):
    fn = os.path.join(cmd_folder, "config.h")
    try:
      fp = open(fn, 'w')
    except:
      self.message("Unable to open config.h for output.", "File error")
      return False

    bfn = self.pgBoard.getFileName()
    if self.pgBoard.isModified() and self.pgBoard.isValid():
      if not self.pgBoard.saveConfigFile(bfn):
        return False
    else:
      self.pgBoard.generateTempTables()

    pfn = self.pgPrinter.getFileName()
    if self.pgPrinter.isModified() and self.pgPrinter.isValid():
      if not self.pgPrinter.saveConfigFile(pfn):
        return False

    prefix = cmd_folder + os.path.sep
    lpfx = len(prefix)

    if bfn.startswith(prefix):
      rbfn = bfn[lpfx:]
    else:
      rbfn = bfn

    if pfn.startswith(prefix):
      rpfn = pfn[lpfx:]
    else:
      rpfn = pfn

    fp.write("\n")
    fp.write("// Configuration for controller board.\n")
    fp.write("#include \"%s\"\n" % rbfn)
    fp.write("\n")
    fp.write("// Configuration for printer board.\n")
    fp.write("#include \"%s\"\n" % rpfn)

    fp.close()

    self.checkEnableLoadConfig()
    return True

  def onBuild(self, evt):
    self.onBuildorUpload(True)

  def onUpload(self, evt):
    self.onBuildorUpload(False)

  def onBuildorUpload(self, buildFlag):
    if not (self.pgPrinter.hasData() or self.pgBoard.hasData()):
      dlg = wx.MessageDialog(self, "Data needs to be loaded. "
                                   "Click Yes to load config.h.",
                             "Data missing",
                             wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
      rc = dlg.ShowModal()
      dlg.Destroy()
      if rc != wx.ID_YES:
        return

      self.loadConfigFile("config.h")
    else:
      if self.pgPrinter.isModified():
        dlg = wx.MessageDialog(self, "Printer data needs to be saved. Click "
                                     "Yes to save printer configuration.",
                               "Changes pending",
                               wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()
        if rc != wx.ID_YES:
          return

        if self.protPrtFile:
          rc = self.onSavePrinterConfigAs(None)
        else:
          rc = self.onSavePrinterConfig(None)
        if not rc:
          return

      if self.pgBoard.isModified():
        dlg = wx.MessageDialog(self, "Board data needs to be saved. Click "
                                     "Yes to save board configuration.",
                               "Changes pending",
                               wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()
        if rc != wx.ID_YES:
          return

        if self.protBrdFile:
          rc = self.onSaveBoardConfigAs(None)
        else:
          rc = self.onSaveBoardConfig(None)
        if not rc:
          return

    if not self.verifyConfigLoaded():
      dlg = wx.MessageDialog(self, "Loaded configuration does not match the "
                                   "config.h file. Click Yes to save config.h.",
                             "Configuration changed",
                             wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
      rc = dlg.ShowModal()
      dlg.Destroy()
      if rc != wx.ID_YES:
        return

      if not self.onSaveConfig(None):
        return

    f_cpu, cpu = self.pgBoard.getCPUInfo()
    if not cpu:
      dlg = wx.MessageDialog(self, "Unable to determine CPU type.",
                             "CPU type error", wx.OK | wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

    if not f_cpu:
      dlg = wx.MessageDialog(self, "Unable to determine CPU clock rate.",
                             "CPU clock rate error", wx.OK | wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

    if buildFlag:
      dlg = Build(self, self.settings, f_cpu, cpu)
      dlg.ShowModal()
      dlg.Destroy()
      self.checkEnableUpload()
    else:
      dlg = Upload(self, self.settings, f_cpu, cpu)
      dlg.ShowModal()
      dlg.Destroy()

  def verifyConfigLoaded(self):
    pfile, bfile = self.getConfigFileNames("config.h")
    lpfile = self.pgPrinter.getFileName()
    lbfile = self.pgBoard.getFileName()

    return ((pfile == lpfile) and (bfile == lbfile))

  def onEditSettings(self, evt):
    dlg = SettingsDlg(self, self.settings)
    rc = dlg.ShowModal()
    dlg.Destroy()

  def onHelp(self, evt):
    self.message("Find help by hovering slowly over the buttons and text "
                 "fields. Tooltip should appear, explaining things.",
                 "Find help", style = wx.OK)

  def onReportProblem(self, evt):
    import urllib
    import webbrowser
    import subprocess
    from sys import platform

    # Testing allowed URLs up to 32 kB in size. Longer URLs are simply chopped.
    mailRecipients ="reply+0004dc756da9f0641af0a3834c580ad5be469f4f6b" \
                    "5d4cfc92cf00000001118c958a92a169ce051faa8c@" \
                    "reply.github.com,[email protected]"
    mailSubject = "Teacup problem report"
    mailBody = "Please answer these questions before hitting \"send\":\n\n" \
               "What did you try to do?\n\n\n" \
               "What did you expect to happen?\n\n\n" \
               "What happened instead?\n\n\n\n" \
               "To allow developers to help, configuration files are " \
               "attached, with help comments stripped:\n"

    for f in self.pgBoard.getFileName(), self.pgPrinter.getFileName():
      if not f:
        mailBody += "\n(no file loaded)\n"
        continue

      mailBody += "\n" + os.path.basename(f) + ":\n"
      mailBody += "----------------------------------------------\n"
      try:
        fc = open(f).read()
        fc = reHelpText.sub("", fc)
        mailBody += fc
      except:
        mailBody += "(could not read this file)\n"
      mailBody += "----------------------------------------------\n"

    url = "mailto:" + urllib.quote(mailRecipients) + \
          "?subject=" + urllib.quote(mailSubject) + \
          "&body=" + urllib.quote(mailBody)

    # This is a work around a bug in gvfs-open coming with (at least) Ubuntu
    # 15.04. gvfs-open would open mailto:///[email protected] instead of
    # the requested mailto:[email protected].
    if platform.startswith("linux"):
      try:
        subprocess.check_output(["gvfs-open", "--help"])

        # Broken gvfs-open exists, so it might be used.
        # Try to open the URL directly.
        for urlOpener in "thunderbird", "evolution", "firefox", "mozilla", \
                         "epiphany", "konqueror", "chromium-browser", \
                         "google-chrome":
          try:
            subprocess.check_output([urlOpener, url], stderr=subprocess.STDOUT)
            return
          except:
            pass
      except:
        pass

    webbrowser.open_new(url)

  def onAbout(self, evt):
    # Get the contributors' top 10 with something like this:
    #   export B=experimental
    #   git log $B | grep "Author:" | sort | uniq | while \
    #     read A; do N=$(git log $B | grep "$A" | wc -l); echo "$N $A"; done | \
    #     sort -rn
    self.message("Teacup Firmware is a 3D Printer and CNC machine controlling "
                 "firmware with emphasis on performance, efficiency and "
                 "outstanding quality. What Teacup does, shall it do very well."
                 "\n\n\n"
                 "Lots of people hard at work! Top 10 contributors:\n\n"
                 "    Markus Hitter (542 commits)\n"
                 "    Michael Moon (322 commits)\n"
                 "    Phil Hord (55 commits)\n"
                 "    Jeff Bernardis (51 commits)\n"
                 "    Markus Amsler (47 commits)\n"
                 "    David Forrest (27 commits)\n"
                 "    Jim McGee (15 commits)\n"
                 "    Ben Jackson (12 commits)\n"
                 "    Bas Laarhoven (10 commits)\n"
                 "    Stephan Walter (9 commits)\n"
                 "    Roland Brochard (3 commits)\n"
                 "    Jens Ch. Restemeier (3 commits)\n",
                 "About Teacup", style = wx.OK)

  def message(self, text, title, style = wx.OK + wx.ICON_ERROR):
    dlg = wx.MessageDialog(self, text, title, style)
    dlg.ShowModal()
    dlg.Destroy()
コード例 #16
0
ファイル: configtool.py プロジェクト: mandrav/Teacup_Firmware
class ConfigFrame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, None, -1, "Teacup Configtool", size = (880, 550))
    self.Bind(wx.EVT_CLOSE, self.onClose)
    self.Bind(wx.EVT_SIZE, self.onResize)

    self.deco = Decoration()

    panel = wx.Panel(self, -1)
    panel.SetBackgroundColour(self.deco.getBackgroundColour())
    panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

    self.settings = Settings(self, cmd_folder)
    self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL,
                                 wx.FONTWEIGHT_BOLD)
    self.settings.folder = cmd_folder

    self.heaters = []
    self.savePrtEna = False
    self.saveBrdEna = False
    self.protPrtFile = False
    self.protBrdFile = False

    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(panel, wx.ID_ANY, size = (880, 550),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.printerFileName = None
    self.printerTabDecor = ""
    self.printerBaseText = "Printer"
    self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgPrinter, self.printerBaseText)

    self.boardFileName = None
    self.boardTabDecor = ""
    self.boardBaseText = "Board"
    self.pgBoard = BoardPanel(self, self.nb, self.settings)
    self.nb.AddPage(self.pgBoard, self.boardBaseText)

    panel.Fit()
    self.panel = panel

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
    self.SetSizer(sz)
    self.makeMenu()

  def onClose(self, evt):
    if not self.pgPrinter.confirmLoseChanges("exit"):
      return

    if not self.pgBoard.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def onResize(self, evt):
    self.panel.SetSize(self.GetClientSize())
    self.Refresh()
    evt.Skip();

  def setPrinterTabFile(self, fn):
    self.printerFileName = fn
    self.updatePrinterTab()

  def setPrinterTabDecor(self, prefix):
    self.printerTabDecor = prefix
    self.updatePrinterTab()

  def updatePrinterTab(self):
    txt = self.printerTabDecor + self.printerBaseText
    if self.printerFileName:
      txt += " <%s>" % self.printerFileName
    self.nb.SetPageText(0, txt)

  def setBoardTabFile(self, fn):
    self.boardFileName = fn
    self.updateBoardTab()

  def setBoardTabDecor(self, prefix):
    self.boardTabDecor = prefix
    self.updateBoardTab()

  def updateBoardTab(self):
    txt = self.boardTabDecor + self.boardBaseText
    if self.boardFileName:
      txt += " <%s>" % self.boardFileName
    self.nb.SetPageText(1, txt)

  def setHeaters(self, ht):
    self.heaters = ht
    self.pgPrinter.setHeaters(ht)

  def makeMenu(self):
    file_menu = wx.Menu()

    file_menu.Append(ID_LOAD_CONFIG, "Load config.h",
                     "Load config.h and its named printer and board files.")
    self.Bind(wx.EVT_MENU, self.onLoadConfig, id = ID_LOAD_CONFIG)
    file_menu.Enable(ID_LOAD_CONFIG, False)

    file_menu.Append(ID_SAVE_CONFIG, "Save config.h", "Save config.h file.")
    self.Bind(wx.EVT_MENU, self.onSaveConfig, id = ID_SAVE_CONFIG)
    file_menu.Enable(ID_SAVE_CONFIG, False)

    file_menu.AppendSeparator()

    file_menu.Append(ID_LOAD_PRINTER, "Load printer",
                     "Load a printer configuration file.")
    self.Bind(wx.EVT_MENU, self.pgPrinter.onLoadConfig, id = ID_LOAD_PRINTER)

    file_menu.Append(ID_SAVE_PRINTER, "Save printer",
                     "Save printer configuration.")
    self.Bind(wx.EVT_MENU, self.onSavePrinterConfig, id = ID_SAVE_PRINTER)
    file_menu.Enable(ID_SAVE_PRINTER, False)

    file_menu.Append(ID_SAVE_PRINTER_AS, "Save printer as...",
                     "Save printer configuration to a new file.")
    self.Bind(wx.EVT_MENU, self.onSavePrinterConfigAs, id = ID_SAVE_PRINTER_AS)
    file_menu.Enable(ID_SAVE_PRINTER_AS, False)

    file_menu.AppendSeparator()

    file_menu.Append(ID_LOAD_BOARD, "Load board",
                     "Load a board configuration file.")
    self.Bind(wx.EVT_MENU, self.pgBoard.onLoadConfig, id = ID_LOAD_BOARD)

    file_menu.Append(ID_SAVE_BOARD, "Save board", "Save board configuration.")
    self.Bind(wx.EVT_MENU, self.onSaveBoardConfig, id = ID_SAVE_BOARD)
    file_menu.Enable(ID_SAVE_BOARD, False)

    file_menu.Append(ID_SAVE_BOARD_AS, "Save board as...",
                     "Save board configuration to a new file.")
    self.Bind(wx.EVT_MENU, self.onSaveBoardConfigAs, id = ID_SAVE_BOARD_AS)
    file_menu.Enable(ID_SAVE_BOARD_AS, False)

    file_menu.AppendSeparator()

    file_menu.Append(wx.ID_EXIT, "E&xit", "Exit the application.")
    self.Bind(wx.EVT_MENU, self.onClose, id = wx.ID_EXIT)

    self.fileMenu = file_menu

    menu_bar = wx.MenuBar()

    menu_bar.Append(file_menu, "&File")

    edit_menu = wx.Menu()

    edit_menu.Append(ID_SETTINGS, "Settings", "Change settings.")
    self.Bind(wx.EVT_MENU, self.onEditSettings, id = ID_SETTINGS)

    self.editMenu = edit_menu

    menu_bar.Append(edit_menu, "&Edit")

    build_menu = wx.Menu()

    build_menu.Append(ID_BUILD, "Build", "Build the executable.")
    self.Bind(wx.EVT_MENU, self.onBuild, id = ID_BUILD)

    build_menu.Append(ID_UPLOAD, "Upload", "Upload the executable.")
    self.Bind(wx.EVT_MENU, self.onUpload, id = ID_UPLOAD)

    self.buildMenu = build_menu

    menu_bar.Append(build_menu, "&Build")

    self.SetMenuBar(menu_bar)
    loadFlag = self.checkEnableLoadConfig()
    self.checkEnableUpload()
    if loadFlag:
      self.loadConfigFile("config.h")

  def onSaveBoardConfig(self, evt):
    rc = self.pgBoard.onSaveConfig(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSaveBoardConfigAs(self, evt):
    rc = self.pgBoard.onSaveConfigAs(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSavePrinterConfig(self, evt):
    rc = self.pgPrinter.onSaveConfig(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def onSavePrinterConfigAs(self, evt):
    rc = self.pgPrinter.onSaveConfigAs(evt)
    if rc:
      self.checkEnableLoadConfig()
    return rc

  def checkEnableLoadConfig(self):
    fn = os.path.join(cmd_folder, "config.h")
    if os.path.isfile(fn):
      self.fileMenu.Enable(ID_LOAD_CONFIG, True)
      self.buildMenu.Enable(ID_BUILD, True)
      return True
    else:
      self.fileMenu.Enable(ID_LOAD_CONFIG, False)
      self.buildMenu.Enable(ID_BUILD, False)
      return False

  def checkEnableUpload(self):
    fn = os.path.join(cmd_folder, "teacup.hex")
    if os.path.isfile(fn):
      self.buildMenu.Enable(ID_UPLOAD, True)
    else:
      self.buildMenu.Enable(ID_UPLOAD, False)

  def enableSavePrinter(self, saveFlag, saveAsFlag):
    self.fileMenu.Enable(ID_SAVE_PRINTER, saveFlag)
    self.fileMenu.Enable(ID_SAVE_PRINTER_AS, saveAsFlag)
    self.savePrtEna = saveAsFlag
    self.protPrtFile = not saveFlag
    if self.savePrtEna and self.saveBrdEna:
      self.enableSaveConfig(True)
    else:
      self.enableSaveConfig(False)

  def enableSaveBoard(self, saveFlag, saveAsFlag):
    self.fileMenu.Enable(ID_SAVE_BOARD, saveFlag)
    self.fileMenu.Enable(ID_SAVE_BOARD_AS, saveAsFlag)
    self.saveBrdEna = saveAsFlag
    self.protBrdFile = not saveFlag
    if self.savePrtEna and self.saveBrdEna:
      self.enableSaveConfig(True)
    else:
      self.enableSaveConfig(False)

  def enableSaveConfig(self, flag):
    self.fileMenu.Enable(ID_SAVE_CONFIG, flag)

  def onLoadConfig(self, evt):
    self.loadConfigFile("config.h")

  def loadConfigFile(self, fn):
    if not self.pgPrinter.confirmLoseChanges("load config"):
      return False

    if not self.pgBoard.confirmLoseChanges("load config"):
      return False

    pfile, bfile = self.getConfigFileNames(fn)

    if not pfile:
      self.message("Config file did not contain a printer file "
                   "include statement.", "Config error")
      return False
    else:
      if not self.pgPrinter.loadConfigFile(pfile):
        self.message("There was a problem loading the printer config file:\n%s"
                     % pfile, "Config error")
        return False

    if not bfile:
      self.message("Config file did not contain a board file "
                   "include statement.", "Config error")
      return False
    else:
      if not self.pgBoard.loadConfigFile(bfile):
        self.message("There was a problem loading the board config file:\n%s"
                     % bfile, "Config error")
        return False

    return True

  def getConfigFileNames(self, fn):
    pfile = None
    bfile = None
    path = os.path.join(cmd_folder, fn)
    try:
      cfgBuffer = list(open(path))
    except:
      self.message("Unable to process config file %s." % fn, "File error")
      return None, None

    for ln in cfgBuffer:
      if not ln.lstrip().startswith("#include"):
        continue

      m = reInclude.search(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if "printer." in t[0]:
            if pfile:
              self.message("Multiple printer file include statements.\n"
                           "Ignoring %s." % ln, "Config error",
                           wx.OK + wx.ICON_WARNING)
            else:
              pfile = os.path.join(cmd_folder, t[0])
          elif "board." in t[0]:
            if bfile:
              self.message("Multiple board file include statements.\n"
                           "Ignoring %s." % ln, "Config error",
                           wx.OK + wx.ICON_WARNING)
            else:
              bfile = os.path.join(cmd_folder, t[0])
          else:
            self.message("Unable to parse include statement:\n%s" % ln,
                         "Config error")

    return pfile, bfile

  def onSaveConfig(self, evt):
    fn = os.path.join(cmd_folder, "config.h")
    try:
      fp = open(fn, 'w')
    except:
      self.message("Unable to open config.h for output.", "File error")
      return False

    bfn = self.pgBoard.getFileName()
    if self.pgBoard.isModified() and self.pgBoard.isValid():
      if not self.pgBoard.saveConfigFile(bfn):
        return False
    else:
      self.pgBoard.generateTempTables()

    pfn = self.pgPrinter.getFileName()
    if self.pgPrinter.isModified() and self.pgPrinter.isValid():
      if not self.pgPrinter.saveConfigFile(pfn):
        return False

    prefix = cmd_folder + os.path.sep
    lpfx = len(prefix)

    if bfn.startswith(prefix):
      rbfn = bfn[lpfx:]
    else:
      rbfn = bfn

    if pfn.startswith(prefix):
      rpfn = pfn[lpfx:]
    else:
      rpfn = pfn

    fp.write("\n")
    fp.write("// Configuration for controller board.\n")
    fp.write("#include \"%s\"\n" % rbfn)
    fp.write("\n")
    fp.write("// Configuration for printer board.\n")
    fp.write("#include \"%s\"\n" % rpfn)

    fp.close()

    self.checkEnableLoadConfig()
    return True

  def onBuild(self, evt):
    self.onBuildorUpload(True)

  def onUpload(self, evt):
    self.onBuildorUpload(False)

  def onBuildorUpload(self, buildFlag):
    if not (self.pgPrinter.hasData() or self.pgBoard.hasData()):
      dlg = wx.MessageDialog(self, "Data needs to be loaded. "
                                   "Click Yes to load config.h.",
                             "Data missing",
                             wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
      rc = dlg.ShowModal()
      dlg.Destroy()
      if rc != wx.ID_YES:
        return

      self.loadConfigFile("config.h")
    else:
      if self.pgPrinter.isModified():
        dlg = wx.MessageDialog(self, "Printer data needs to be saved. Click "
                                     "Yes to save printer configuration.",
                               "Changes pending",
                               wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()
        if rc != wx.ID_YES:
          return

        if self.protPrtFile:
          rc = self.onSavePrinterConfigAs(None)
        else:
          rc = self.onSavePrinterConfig(None)
        if not rc:
          return

      if self.pgBoard.isModified():
        dlg = wx.MessageDialog(self, "Board data needs to be saved. Click "
                                     "Yes to save board configuration.",
                               "Changes pending",
                               wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()
        if rc != wx.ID_YES:
          return

        if self.protBrdFile:
          rc = self.onSaveBoardConfigAs(None)
        else:
          rc = self.onSaveBoardConfig(None)
        if not rc:
          return

    if not self.verifyConfigLoaded():
      dlg = wx.MessageDialog(self, "Loaded configuration does not match the "
                                   "config.h file. Click Yes to save config.h.",
                             "Configuration changed",
                             wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
      rc = dlg.ShowModal()
      dlg.Destroy()
      if rc != wx.ID_YES:
        return

      if not self.onSaveConfig(None):
        return

    f_cpu, cpu = self.pgBoard.getCPUInfo()
    if not cpu:
      dlg = wx.MessageDialog(self, "Unable to determine CPU type.",
                             "CPU type error", wx.OK | wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

    if not f_cpu:
      dlg = wx.MessageDialog(self, "Unable to determine CPU clock rate.",
                             "CPU clock rate error", wx.OK | wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

    if buildFlag:
      dlg = Build(self, self.settings, f_cpu, cpu)
      dlg.ShowModal()
      dlg.Destroy()
      self.checkEnableUpload()
    else:
      dlg = Upload(self, self.settings, f_cpu, cpu)
      dlg.ShowModal()
      dlg.Destroy()

  def verifyConfigLoaded(self):
    pfile, bfile = self.getConfigFileNames("config.h")
    lpfile = self.pgPrinter.getFileName()
    lbfile = self.pgBoard.getFileName()

    return ((pfile == lpfile) and (bfile == lbfile))

  def onEditSettings(self, evt):
    dlg = SettingsDlg(self, self.settings)
    rc = dlg.ShowModal()
    dlg.Destroy()

  def message(self, text, title, style = wx.OK + wx.ICON_ERROR):
    dlg = wx.MessageDialog(self, text, title, style)
    dlg.ShowModal()
    dlg.Destroy()
コード例 #17
0
class BoardPanel(wx.Panel):
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent

        self.deco = Decoration()
        self.protFileLoaded = False

        self.settings = settings

        self.board = Board(self.settings)

        self.dir = os.path.join(self.settings.folder, "config")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self, wx.ID_ANY, size=(21, 21), style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgCpu = self.registerPage(CpuPage, "CPU")
        self.pgPins = self.registerPage(PinoutsPage, "Pinouts")
        self.pgDisplay = self.registerPage(DisplayPage, "Display")
        self.pgHeaters = self.registerPage(HeatersPage, "Heaters")
        self.pgSensors = self.registerPage(
            SensorsPage, "Temperature Sensors", heatersPage=self.pgHeaters
        )
        self.pgCommunications = self.registerPage(CommunicationsPage, "Communications")

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()

    def registerPage(self, klass, label, *args, **kwargs):
        page = klass(
            self, self.nb, len(self.pages), *args, font=self.settings.font, **kwargs
        )
        self.nb.AddPage(page, label)
        self.pages.append(page)
        self.titles.append(label)
        self.pageModified.append(False)
        self.pageValid.append(True)
        return page

    def getCPUInfo(self):
        return self.board.getCPUInfo()

    def assertModified(self, pg, flag=True):
        self.pageModified[pg] = flag
        self.modifyTab(pg)

    def isModified(self):
        return True in self.pageModified

    def isValid(self):
        return not (False in self.pageValid)

    def hasData(self):
        return self.board.hasData()

    def getFileName(self):
        return self.board.getFileName()

    def assertValid(self, pg, flag=True):
        self.pageValid[pg] = flag
        self.modifyTab(pg)

        if False in self.pageValid:
            self.parent.enableSaveBoard(False, False)
        else:
            self.parent.enableSaveBoard(not self.protFileLoaded, True)

    def modifyTab(self, pg):
        if self.pageModified[pg] and not self.pageValid[pg]:
            pfx = "?* "
        elif self.pageModified[pg]:
            pfx = "* "
        elif not self.pageValid[pg]:
            pfx = "? "
        else:
            pfx = ""

        self.nb.SetPageText(pg, pfx + self.titles[pg])
        if True in self.pageModified and False in self.pageValid:
            pfx = "?* "
        elif True in self.pageModified:
            pfx = "* "
        elif False in self.pageValid:
            pfx = "? "
        else:
            pfx = ""
        self.parent.setBoardTabDecor(pfx)

    def setHeaters(self, ht):
        self.parent.setHeaters(ht)

    def onClose(self, evt):
        if not self.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def confirmLoseChanges(self, msg):
        if True not in self.pageModified:
            return True

        dlg = wx.MessageDialog(
            self,
            "Are you sure you want to " + msg + "?\n"
            "There are changes to your board "
            "configuration that will be lost.",
            "Changes pending",
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION,
        )
        rc = dlg.ShowModal()
        dlg.Destroy()

        if rc != wx.ID_YES:
            return False

        return True

    def onLoadConfig(self, evt):
        if not self.confirmLoseChanges("load a new board configuration"):
            return

        if platform.startswith("darwin"):
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Board configuration (board.*.h)|*.h"
        else:
            wildcard = "Board configuration (board.*.h)|board.*.h"

        dlg = wx.FileDialog(
            self,
            message="Choose a board config file",
            defaultDir=self.dir,
            defaultFile="",
            wildcard=wildcard,
            style=wx.FD_OPEN | wx.FD_CHANGE_DIR,
        )

        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

        dlg.Destroy()
        if path is None:
            return

        self.dir = os.path.dirname(path)
        rc, efn = self.loadConfigFile(path)

        if not rc:
            dlg = wx.MessageDialog(
                self,
                "Unable to process file %s." % efn,
                "File error",
                wx.OK + wx.ICON_ERROR,
            )
            dlg.ShowModal()
            dlg.Destroy()
            return

    def loadConfigFile(self, fn):
        ok, file = self.board.loadConfigFile(fn)
        if not ok:
            return ok, file

        if os.path.basename(fn) in protectedFiles:
            self.parent.enableSaveBoard(False, True)
            self.protFileLoaded = True
        else:
            self.protFileLoaded = False
            self.parent.enableSaveBoard(True, True)

        self.parent.setBoardTabFile(os.path.basename(fn))
        self.pgHeaters.setCandidatePins(self.board.candHeatPins)
        self.pgSensors.setCandidatePins(self.board.candThermPins)
        self.pgCpu.setCandidateProcessors(self.board.candProcessors)
        self.pgCpu.setCandidateClocks(self.board.candClocks)

        for pg in self.pages:
            pg.insertValues(self.board.cfgValues)
            pg.setHelpText(self.board.helpText)

        self.pgSensors.setSensors(self.board.sensors)
        self.pgHeaters.setHeaters(self.board.heaters)

        return True, None

    def onSaveConfig(self, evt):
        path = self.getFileName()
        return self.saveConfigFile(path)

    def onSaveConfigAs(self, evt):
        if platform.startswith("darwin"):
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Board configuration (board.*.h)|*.h"
        else:
            wildcard = "Board configuration (board.*.h)|board.*.h"

        dlg = wx.FileDialog(
            self,
            message="Save as ...",
            defaultDir=self.dir,
            defaultFile="",
            wildcard=wildcard,
            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
        )

        val = dlg.ShowModal()

        if val != wx.ID_OK:
            dlg.Destroy()
            return

        path = dlg.GetPath()
        dlg.Destroy()

        rc = self.saveConfigFile(path)
        if rc:
            self.parent.setBoardTabFile(os.path.basename(path))
            self.protFileLoaded = False
            self.parent.enableSaveBoard(True, True)
        return rc

    def saveConfigFile(self, path):
        if os.path.basename(path) in protectedFiles:
            dlg = wx.MessageDialog(
                self,
                "It's not allowed to overwrite files "
                "distributed by Teacup. Choose another name.",
                "Protected file error",
                wx.OK + wx.ICON_ERROR,
            )
            dlg.ShowModal()
            dlg.Destroy()
            return False

        if not os.path.basename(path).startswith("board."):
            dlg = wx.MessageDialog(
                self,
                "Illegal file name: %s.\n" 'File name must begin with "board."' % path,
                "Illegal file name",
                wx.OK + wx.ICON_ERROR,
            )
            dlg.ShowModal()
            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)

        if ext == "":
            path += ".h"

        try:
            self.board.saveConfigFile(path, values)
        except:
            dlg = wx.MessageDialog(
                self,
                "Unable to write to file %s." % path,
                "File error",
                wx.OK + wx.ICON_ERROR,
            )
            dlg.ShowModal()
            dlg.Destroy()
            return False

        return self.generateTempTables()

    def generateTempTables(self):
        if not generateTempTables(self.board.sensors, self.settings):
            dlg = wx.MessageDialog(
                self,
                "Error writing to file thermistortable.h.",
                "File error",
                wx.OK + wx.ICON_ERROR,
            )
            dlg.ShowModal()
            dlg.Destroy()
            return False

        return True
コード例 #18
0
class PrinterPanel(wx.Panel):
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent

        self.deco = Decoration()
        self.configFile = None
        self.protFileLoaded = False

        self.settings = settings

        self.cfgValues = {}
        self.heaters = []
        self.dir = os.path.join(self.settings.folder, "config")
        self.cfgDir = os.path.join(self.settings.folder, "configtool")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgMech = MechanicalPage(self, self.nb, len(self.pages),
                                     self.settings.font)
        text = "Mechanical"
        self.nb.AddPage(self.pgMech, text)
        self.pages.append(self.pgMech)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        self.pgAcc = AccelerationPage(self, self.nb, len(self.pages),
                                      self.settings.font)
        text = "Acceleration"
        self.nb.AddPage(self.pgAcc, text)
        self.pages.append(self.pgAcc)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        self.pgMiscellaneous = MiscellaneousPage(self, self.nb,
                                                 len(self.pages),
                                                 self.settings.font)
        text = "Miscellaneous"
        self.nb.AddPage(self.pgMiscellaneous, text)
        self.pages.append(self.pgMiscellaneous)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()

    def getFileName(self):
        return self.configFile

    def assertModified(self, pg, flag=True):
        self.pageModified[pg] = flag
        self.modifyTab(pg)

    def isModified(self):
        return (True in self.pageModified)

    def isValid(self):
        return not (False in self.pageValid)

    def hasData(self):
        return (self.configFile != None)

    def assertValid(self, pg, flag=True):
        self.pageValid[pg] = flag
        self.modifyTab(pg)

        if False in self.pageValid:
            self.parent.enableSavePrinter(False, False)
        else:
            self.parent.enableSavePrinter(not self.protFileLoaded, True)

    def modifyTab(self, pg):
        if self.pageModified[pg] and not self.pageValid[pg]:
            pfx = "?* "
        elif self.pageModified[pg]:
            pfx = "* "
        elif not self.pageValid[pg]:
            pfx = "? "
        else:
            pfx = ""

        self.nb.SetPageText(pg, pfx + self.titles[pg])
        if True in self.pageModified and False in self.pageValid:
            pfx = "?* "
        elif True in self.pageModified:
            pfx = "* "
        elif False in self.pageValid:
            pfx = "? "
        else:
            pfx = ""
        self.parent.setPrinterTabDecor(pfx)

    def setHeaters(self, ht):
        return self.pgMiscellaneous.setHeaters(ht)

    def onClose(self, evt):
        if not self.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def confirmLoseChanges(self, msg):
        if True not in self.pageModified:
            return True

        dlg = wx.MessageDialog(
            self, "Are you sure you want to " + msg + "?\n"
            "There are changes to your printer "
            "configuration that will be lost.", "Changes pending",
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()

        if rc != wx.ID_YES:
            return False

        return True

    def onLoadConfig(self, evt):
        if not self.confirmLoseChanges("load a new printer configuration"):
            return

        if platform == "darwin":
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Printer configuration (printer.*.h)|*.h"
        else:
            wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Choose a printer config file",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.OPEN | wx.CHANGE_DIR)

        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

        dlg.Destroy()
        if path is None:
            return

        self.dir = os.path.dirname(path)
        rc, efn = self.loadConfigFile(path)

        if not rc:
            dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            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

        self.processors = []
        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 = ""

            if self.parseDefineName(ln):
                continue

        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 = ""

            if self.parseDefineValue(ln):
                continue

        if os.path.basename(fn) in protectedFiles:
            self.parent.enableSavePrinter(False, True)
            self.protFileLoaded = True
        else:
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        self.parent.setPrinterTabFile(os.path.basename(fn))

        for pg in self.pages:
            pg.insertValues(self.cfgValues)
            pg.setHelpText(self.helpText)

        k = 'DC_EXTRUDER'
        if k in self.cfgValues.keys() and self.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 = reDefBoolBL.search(ln)
        if m:
            t = m.groups()
            if len(t) == 1 and (t[0] in self.cfgNames):
                self.cfgValues[t[0]] = True
                return True

        return False

    def onSaveConfig(self, evt):
        path = self.configFile
        return self.saveConfigFile(path)

    def onSaveConfigAs(self, evt):
        wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Save as ...",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        val = dlg.ShowModal()

        if val != wx.ID_OK:
            dlg.Destroy()
            return

        path = dlg.GetPath()
        dlg.Destroy()

        rc = self.saveConfigFile(path)
        if rc:
            self.parent.setPrinterTabFile(os.path.basename(path))
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        return rc

    def saveConfigFile(self, path):
        if os.path.basename(path) in protectedFiles:
            dlg = wx.MessageDialog(
                self, "It's not allowed to overwrite files "
                "distributed by Teacup. Choose another name.",
                "Protected file error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        if not os.path.basename(path).startswith("printer."):
            dlg = wx.MessageDialog(
                self, "Illegal file name: %s.\n"
                "File name must begin with \"printer.\"" % path,
                "Illegal file name", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        ext = os.path.splitext(os.path.basename(path))[1]
        self.dir = os.path.dirname(path)

        if ext == "":
            path += ".h"

        try:
            fp = file(path, 'w')
        except:
            dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            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
コード例 #19
0
ファイル: page.py プロジェクト: DEMI1/Teacup_Firmware
class Page:
  def __init__(self, font):
    self.modified = False
    self.valid = True
    self.fieldValid = {}
    self.textControls = {}
    self.checkBoxes = {}
    self.radioButtons = {}
    self.radioButtonBoxes = {}
    self.choices = {}
    self.deco = Decoration()
    self.font = font

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

  def enableAll(self, flag = True):
    for c in self.textControls.keys():
      self.textControls[c].Enable(flag)
    for c in self.checkBoxes.keys():
      self.checkBoxes[c].Enable(flag)
    for c in self.radioButtons.keys():
      self.radioButtons[c].Enable(flag)
    for c in self.choices.keys():
      self.choices[c].Enable(flag)

  def addTextCtrl(self, name, labelWidth, validator):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name] + " ",
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetTcLabel)

    tc = wx.TextCtrl(self, wx.ID_ANY, "", style = wx.TE_RIGHT, name = name)
    tc.SetFont(self.font)
    self.fieldValid[name] = True
    tc.Bind(wx.EVT_TEXT, validator)
    self.textControls[name] = tc
    lsz.Add(tc)

    return lsz

  def addCheckBox(self, name, validator):
    if name in self.labels.keys():
      lbl = self.labels[name]
    else:
      lbl = name
    cb = wx.CheckBox(self, wx.ID_ANY, lbl)
    cb.SetFont(self.font)
    cb.Bind(wx.EVT_CHECKBOX, validator)
    self.checkBoxes[name] = cb

    return cb

  def addRadioButton(self, name, style, validator, sbox = None):
    rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style = style)
    rb.SetFont(self.font)
    self.Bind(wx.EVT_RADIOBUTTON, validator, rb)
    self.radioButtons[name] = rb
    if sbox is not None:
      self.radioButtonBoxes[name] = sbox

    return rb

  def addChoice(self, name, choices, selection, labelWidth, validator,
                size = (-1, -1)):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetChLabel)

    ch = wx.Choice(self, wx.ID_ANY, choices = choices, size = size, name = name)
    ch.SetBackgroundColour(self.deco.getBackgroundColour())
    ch.SetFont(self.font)
    ch.Bind(wx.EVT_CHOICE, validator)
    ch.SetSelection(selection)
    lsz.Add(ch)
    self.choices[name] = ch

    return lsz

  def addPinChoice(self, name, choiceVal, pins, allowBlank , labelWidth):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetChLabel)

    if allowBlank:
      opts = ["-"] + pins
    else:
      opts = pins

    ch = wx.Choice(self, wx.ID_ANY, choices = opts, name = name,
                   style = wx.CB_SORT)
    ch.SetBackgroundColour(self.deco.getBackgroundColour())
    ch.SetFont(self.font)
    ch.Bind(wx.EVT_CHOICE, self.onChoice)
    self.choices[name] = ch
    try:
      sv = self.pinNames.index(choiceVal)
    except:
      sv = 0
    ch.SetSelection(sv)
    lsz.Add(ch)

    return lsz

  def setChoice(self, name, cfgValues, default):
    if name in cfgValues.keys():
      bv = cfgValues[name]
    else:
      bv = default

    s = self.choices[name].FindString(bv)
    if s < 0:
      s = self.choices[name].FindString(default)
      if s < 0:
        s = 0

    self.choices[name].SetSelection(s)

  def onTextCtrlInteger(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    name = tc.GetName()
    w = tc.GetValue().strip()
    if w == "":
      valid = True
    else:
      m = reInteger.match(w)
      if m:
        valid = True
      else:
        valid = False

    self.setFieldValidity(name, valid)

    if valid:
      tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    else:
      tc.SetBackgroundColour("pink")
    tc.Refresh()
    evt.Skip()

  def onTextCtrlFloat(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    name = tc.GetName()
    w = tc.GetValue().strip()
    if w == "":
      valid = True
    else:
      m = reFloat.match(w)
      if m:
        valid = True
      else:
        valid = False

    self.setFieldValidity(name, valid)

    if valid:
      tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    else:
      tc.SetBackgroundColour("pink")
    tc.Refresh()
    evt.Skip()

  def onTextCtrlPin(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    self.validatePin(tc)
    evt.Skip()

  def onTextCtrl(self, evt):
    self.assertModified(True)
    evt.Skip()

  def onChoice(self, evt):
    self.assertModified(True)
    evt.Skip()

  def onCheckBox(self, evt):
    self.assertModified(True)
    evt.Skip()

  def setHelpText(self, ht):
    for k in self.textControls.keys():
      if k in ht.keys():
        self.textControls[k].SetToolTipString(ht[k])

    for k in self.checkBoxes.keys():
      if k in ht.keys():
        self.checkBoxes[k].SetToolTipString(ht[k])

    for k in self.radioButtons.keys():
      if k in ht.keys():
        self.radioButtons[k].SetToolTipString(ht[k])
        if k in self.radioButtonBoxes.keys():
          self.radioButtonBoxes[k].SetToolTipString(ht[k])

    for k in self.choices.keys():
      if k in ht.keys():
        self.choices[k].SetToolTipString(ht[k])

  def getValues(self):
    self.assertModified(False)
    result = {}
    for k in self.checkBoxes.keys():
      cb = self.checkBoxes[k]
      result[k] = cb.IsChecked()

    for k in self.textControls.keys():
      v = self.textControls[k].GetValue()
      result[k] = v

    for k in self.radioButtons.keys():
      result[k] = self.radioButtons[k].GetValue()

    for k in self.choices.keys():
      v = self.choices[k].GetSelection()
      result[k] = self.choices[k].GetString(v)

    return result

  def assertModified(self, flag):
    if flag != self.modified:
      self.parent.assertModified(self.id, flag)
      self.modified = flag

  def setFieldValidity(self, name, flag):
    self.fieldValid[name] = flag

    pgValid = True
    for k in self.fieldValid.keys():
      if not self.fieldValid[k]:
        pgValid = False
        break

    self.assertValid(pgValid)

  def assertValid(self, flag):
    if flag != self.valid:
      self.parent.assertValid(self.id, flag)
      self.valid = flag
コード例 #20
0
ファイル: printerpanel.py プロジェクト: DEMI1/Teacup_Firmware
class PrinterPanel(wx.Panel):
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent

    self.deco = Decoration()
    self.configFile = None
    self.protFileLoaded = False

    self.settings = settings

    self.cfgValues = {}
    self.heaters = []
    self.dir = os.path.join(self.settings.folder, "config")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgMech = MechanicalPage(self, self.nb, len(self.pages),
                                 self.settings.font)
    text = "Mechanical"
    self.nb.AddPage(self.pgMech, text)
    self.pages.append(self.pgMech)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgAcc = AccelerationPage(self, self.nb, len(self.pages),
                                  self.settings.font)
    text = "Acceleration"
    self.nb.AddPage(self.pgAcc, text)
    self.pages.append(self.pgAcc)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgMiscellaneous = MiscellaneousPage(self, self.nb, len(self.pages),
                                             self.settings.font)
    text = "Miscellaneous"
    self.nb.AddPage(self.pgMiscellaneous, text)
    self.pages.append(self.pgMiscellaneous)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()

  def getFileName(self):
    return self.configFile

  def assertModified(self, pg, flag = True):
    self.pageModified[pg] = flag
    self.modifyTab(pg)

  def isModified(self):
    return (True in self.pageModified)

  def isValid(self):
    return not (False in self.pageValid)

  def hasData(self):
    return (self.configFile != None)

  def assertValid(self, pg, flag = True):
    self.pageValid[pg] = flag
    self.modifyTab(pg)

    if False in self.pageValid:
      self.parent.enableSavePrinter(False, False)
    else:
      self.parent.enableSavePrinter(not self.protFileLoaded, True)

  def modifyTab(self, pg):
    if self.pageModified[pg] and not self.pageValid[pg]:
      pfx = "?* "
    elif self.pageModified[pg]:
      pfx = "* "
    elif not self.pageValid[pg]:
      pfx = "? "
    else:
      pfx = ""

    self.nb.SetPageText(pg, pfx + self.titles[pg])
    if True in self.pageModified and False in self.pageValid:
      pfx = "?* "
    elif True in self.pageModified:
      pfx = "* "
    elif False in self.pageValid:
      pfx = "? "
    else:
      pfx = ""
    self.parent.setPrinterTabDecor(pfx)

  def setHeaters(self, ht):
    return self.pgMiscellaneous.setHeaters(ht)

  def onClose(self, evt):
    if not self.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def confirmLoseChanges(self, msg):
    if True not in self.pageModified:
      return True

    dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
                                 "There are changes to your printer "
                                 "configuration that will be lost.",
                           "Changes pending",
                           wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
    rc = dlg.ShowModal()
    dlg.Destroy()

    if rc != wx.ID_YES:
      return False

    return True

  def onLoadConfig(self, evt):
    if not self.confirmLoseChanges("load a new printer configuration"):
      return

    if platform == "darwin":
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Printer configuration (printer.*.h)|*.h"
    else:
      wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Choose a printer config file",
                        defaultDir = self.dir, defaultFile = "",
                        wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)

    path = None
    if dlg.ShowModal() == wx.ID_OK:
      path = dlg.GetPath()

    dlg.Destroy()
    if path is None:
      return

    self.dir = os.path.dirname(path)
    rc = self.loadConfigFile(path)

    if not rc:
      dlg = wx.MessageDialog(self, "Unable to process file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

  def loadConfigFile(self, fn):
    try:
      self.cfgBuffer = list(open(fn))
    except:
      return False

    self.configFile = fn

    self.processors = []
    gatheringHelpText = False
    helpTextString = ""
    helpKey = None

    self.cfgValues = {}
    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 = ""

      if ln.lstrip().startswith("//"):
        continue

      if ln.lstrip().startswith("#define"):
        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:
                self.cfgValues[t[0]] = tt[0]
                continue
              elif len(tt) > 1:
                self.cfgValues[t[0]] = tt
                continue

        m = reDefine.search(ln)
        if m:
          t = m.groups()
          if len(t) == 2:
            self.cfgValues[t[0]] = t[1]
            continue

        m = reDefBool.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.cfgValues[t[0]] = True

    if os.path.basename(fn) in protectedFiles:
      self.parent.enableSavePrinter(False, True)
      self.protFileLoaded = True
    else:
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    self.parent.setPrinterTabFile(os.path.basename(fn))

    for pg in self.pages:
      pg.insertValues(self.cfgValues)
      pg.setHelpText(self.helpText)

    k = 'DC_EXTRUDER'
    if k in self.cfgValues.keys():
      self.pgMiscellaneous.setOriginalHeater(self.cfgValues[k])
    else:
      self.pgMiscellaneous.setOriginalHeater(None)

    return True

  def onSaveConfig(self, evt):
    path = self.configFile
    return self.saveConfigFile(path)

  def onSaveConfigAs(self, evt):
    wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
                        defaultFile = "", wildcard = wildcard,
                        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

    val = dlg.ShowModal()

    if val != wx.ID_OK:
      dlg.Destroy()
      return

    path = dlg.GetPath()
    dlg.Destroy()

    rc = self.saveConfigFile(path)
    if rc:
      self.parent.setPrinterTabFile(os.path.basename(path))
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    return rc

  def saveConfigFile(self, path):
    if os.path.basename(path) in protectedFiles:
      dlg = wx.MessageDialog(self, "Unable to overwrite %s." % path,
                             "Protected file error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    if not os.path.basename(path).startswith("printer."):
      dlg = wx.MessageDialog(self, "Illegal file name: %s.\n"
                             "File name must begin with \"printer.\"" % path,
                             "Illegal file name", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    ext = os.path.splitext(os.path.basename(path))[1]
    self.dir = os.path.dirname(path)

    if ext == "":
      path += ".h"

    try:
      fp = file(path, 'w')
    except:
      dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    self.configFile = path

    values = {}
    labelFound = []

    for pg in self.pages:
      v1 = pg.getValues()
      for k in v1.keys():
        values[k] = v1[k]

    for ln in self.cfgBuffer:
      m = reDefineBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 2:
          if t[0] in values.keys() and values[t[0]] != "":
            fp.write(defineValueFormat % (t[0], values[t[0]]))
            self.cfgValues[t[0]] = values[t[0]]
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write("//" + ln)
            if t[0] in self.cfgValues.keys():
              del self.cfgValues[t[0]]
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reDefBoolBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if t[0] in values.keys() and values[t[0]]:
            fp.write(defineBoolFormat % t[0])
            self.cfgValues[t[0]] = True
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write("//" + ln)
            if t[0] in self.cfgValues.keys():
              del self.cfgValues[t[0]]
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reCommDefBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 2:
          if t[0] in values.keys() and values[t[0]] != "":
            fp.write(defineValueFormat % (t[0], values[t[0]]))
            self.cfgValues[t[0]] =  values[t[0]]
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write(ln)
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reCommDefBoolBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if t[0] in values.keys() and values[t[0]]:
            fp.write(defineBoolFormat % t[0])
            self.cfgValues[t[0]] = True
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write(ln)
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      fp.write(ln)

    for k in labelFound:
      del values[k]

    newLabels = ""
    for k in values.keys():
      if newLabels == "":
        newLabels = k
      else:
        newLabels += ", " + k
      self.addNewDefine(fp, k, values[k])

    if newLabels != "":
      dlg = wx.MessageDialog(self, "New defines added to printer config:\n" +
                             newLabels, "New defines",
                             wx.OK + wx.ICON_INFORMATION)
      dlg.ShowModal()
      dlg.Destroy()

    fp.close()

    return True

  def addNewDefine(self, fp, key, val):
    fp.write("\n")
    fp.write("/** \\def %s\n" % key)
    fp.write("  Add help text here.\n")
    fp.write("*/\n")
    if val == True:
      fp.write(defineBoolFormat % key)
    elif val == False:
      fp.write("//#define %s\n" % key)
    elif val == "":
      fp.write("//#define %s\n" % key)
    else:
      fp.write(defineValueFormat % (key, val))
コード例 #21
0
ファイル: page.py プロジェクト: Wurstnase/Teacup_Firmware
class Page:
  def __init__(self, font):
    self.modified = False
    self.valid = True
    self.fieldValid = {}
    self.textControls = {}
    self.textControlsOriginal = {}
    self.checkBoxes = {}
    self.radioButtons = {}
    self.radioButtonBoxes = {}
    self.choices = {}
    self.choicesOriginal = {}
    self.boolChoices = {}
    self.deco = Decoration()
    self.font = font

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

  def enableAll(self, flag = True):
    for c in self.textControls.keys():
      self.textControls[c].Enable(flag)
    for c in self.checkBoxes.keys():
      self.checkBoxes[c].Enable(flag)
    for c in self.radioButtons.keys():
      self.radioButtons[c].Enable(flag)
    for c in self.choices.keys():
      self.choices[c].Enable(flag)

  def addTextCtrl(self, name, labelWidth, validator):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name] + " ",
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetTcLabel)

    tc = wx.TextCtrl(self, wx.ID_ANY, "", style = wx.TE_RIGHT, name = name)
    tc.SetFont(self.font)
    self.fieldValid[name] = True
    tc.Bind(wx.EVT_TEXT, validator)
    self.textControls[name] = tc
    lsz.Add(tc)

    return lsz

  def addCheckBox(self, name, validator):
    if name in self.labels.keys():
      lbl = self.labels[name]
    else:
      lbl = name
    cb = wx.CheckBox(self, wx.ID_ANY, lbl)
    cb.SetFont(self.font)
    cb.Bind(wx.EVT_CHECKBOX, validator)
    self.checkBoxes[name] = cb

    return cb

  def addRadioButton(self, name, style, validator, sbox = None):
    rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style = style)
    rb.SetFont(self.font)
    self.Bind(wx.EVT_RADIOBUTTON, validator, rb)
    self.radioButtons[name] = rb
    if sbox is not None:
      self.radioButtonBoxes[name] = sbox

    return rb

  def addChoice(self, name, choices, selection, labelWidth, validator,
                size = (-1, -1)):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetChLabel)

    ch = wx.Choice(self, wx.ID_ANY, choices = choices, size = size, name = name)
    ch.SetBackgroundColour(self.deco.getBackgroundColour())
    ch.SetFont(self.font)
    ch.Bind(wx.EVT_CHOICE, validator)
    ch.SetSelection(selection)
    lsz.Add(ch)
    self.choices[name] = ch

    return lsz

  def addPinChoice(self, name, choiceVal, pins, allowBlank , labelWidth):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetChLabel)

    if allowBlank:
      opts = ["-"] + pins
    else:
      opts = pins

    ch = wx.Choice(self, wx.ID_ANY, choices = opts, name = name,
                   style = wx.CB_SORT)
    ch.SetBackgroundColour(self.deco.getBackgroundColour())
    ch.SetFont(self.font)
    ch.Bind(wx.EVT_CHOICE, self.onChoice)
    self.choices[name] = ch
    try:
      sv = self.pinNames.index(choiceVal)
    except:
      sv = 0
    ch.SetSelection(sv)
    lsz.Add(ch)

    return lsz

  # addChoice handles #defines with value, this handles choices for
  # sets of boolean #defines.
  def addBoolChoice(self, name, allowBlank, labelWidth, validator,
                    size = (-1, -1)):
    lsz = wx.BoxSizer(wx.HORIZONTAL)
    st = wx.StaticText(self, wx.ID_ANY, self.labels[name],
                       size = (labelWidth, -1), style = wx.ALIGN_RIGHT)
    st.SetFont(self.font)
    lsz.Add(st, 1, wx.TOP, offsetChLabel)

    ch = wx.Choice(self, wx.ID_ANY, size = size, name = name)
    ch.SetBackgroundColour(self.deco.getBackgroundColour())
    ch.SetFont(self.font)
    ch.Bind(wx.EVT_CHOICE, validator)

    if allowBlank:
      ch.Append("(none)")
      ch.SetSelection(0)

    lsz.Add(ch)
    self.boolChoices[name] = ch

    return lsz

  def setChoice(self, name, cfgValues, default):
    if name in cfgValues.keys() and cfgValues[name][1] == True:
      bv = cfgValues[name][0]
    else:
      bv = default

    s = self.choices[name].FindString(bv)
    if s < 0:
      s = self.choices[name].FindString(default)
      if s < 0:
        s = 0

    self.choices[name].SetSelection(s)

  def onTextCtrlInteger(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    name = tc.GetName()
    w = tc.GetValue().strip()
    if w == "":
      valid = True
    else:
      m = reInteger.match(w)
      if m:
        valid = True
      else:
        valid = False

    self.setFieldValidity(name, valid)

    if valid:
      tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    else:
      tc.SetBackgroundColour("pink")
    tc.Refresh()
    evt.Skip()

  def onTextCtrlFloat(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    name = tc.GetName()
    w = tc.GetValue().strip()
    if w == "":
      valid = True
    else:
      m = reFloat.match(w)
      if m:
        valid = True
      else:
        valid = False

    self.setFieldValidity(name, valid)

    if valid:
      tc.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    else:
      tc.SetBackgroundColour("pink")
    tc.Refresh()
    evt.Skip()

  def onTextCtrlPin(self, evt):
    self.assertModified(True)
    tc = evt.GetEventObject()
    self.validatePin(tc)
    evt.Skip()

  def onTextCtrl(self, evt):
    self.assertModified(True)
    evt.Skip()

  def onChoice(self, evt):
    self.assertModified(True)
    evt.Skip()

  def onCheckBox(self, evt):
    self.assertModified(True)
    evt.Skip()

  def setHelpText(self, ht):
    for k in self.textControls.keys():
      if k in ht.keys():
        self.textControls[k].SetToolTipString(ht[k])

    for k in self.checkBoxes.keys():
      if k in ht.keys():
        self.checkBoxes[k].SetToolTipString(ht[k])

    for k in self.radioButtons.keys():
      if k in ht.keys():
        self.radioButtons[k].SetToolTipString(ht[k])
        if k in self.radioButtonBoxes.keys():
          self.radioButtonBoxes[k].SetToolTipString(ht[k])

    for k in self.choices.keys():
      if k in ht.keys():
        self.choices[k].SetToolTipString(ht[k])

    for k in self.boolChoices.keys():
      for candidate in ht.keys():
        if candidate.startswith(k):
          self.boolChoices[k].SetToolTipString(ht[candidate])
          break

  def insertValues(self, cfgValues):
    self.assertValid(True)
    self.enableAll(True)
    for k in self.fieldValid.keys():
      self.fieldValid[k] = True

    for k in self.checkBoxes.keys():
      if k in cfgValues.keys() and cfgValues[k]:
        self.checkBoxes[k].SetValue(True)
      else:
        self.checkBoxes[k].SetValue(False)

    for k in self.textControls.keys():
      if k in cfgValues.keys():
        self.textControlsOriginal[k] = cfgValues[k]
        if cfgValues[k][1] == True:
          self.textControls[k].SetValue(str(cfgValues[k][0]))
        else:
          self.textControls[k].SetValue("")
      else:
        print "Key " + k + " not found in config data."

    for k in self.choices.keys():
      if k in cfgValues.keys():
        self.choicesOriginal[k] = cfgValues[k]
        self.setChoice(k, cfgValues, "-")
      else:
        print "Key " + k + " not found in config data."

    for k in self.boolChoices.keys():
      choice = self.boolChoices[k]

      # Remove items left behind from the previous configuration.
      while (choice.GetCount() and
             not choice.GetString(choice.GetCount() - 1).startswith('(')):
        choice.Delete(choice.GetCount() - 1)

      # Add items found in this configuration.
      for cfg in cfgValues.keys():
        if cfg.startswith(k):
          if cfg in self.labels.keys():
            choice.Append(self.labels[cfg])
          else:
            choice.Append(cfg)

          # As we want to write the configuration name later, not the user
          # friendly string, we store the configuration name as client data.
          n = choice.GetCount() - 1
          choice.SetClientData(n, cfg)

          if cfgValues[cfg]:
            choice.SetSelection(n)

    self.assertModified(False)

  def getValues(self):
    self.assertModified(False)
    result = {}

    for k in self.checkBoxes.keys():
      cb = self.checkBoxes[k]
      result[k] = cb.IsChecked()

    for k in self.textControls.keys():
      v = self.textControls[k].GetValue()
      if v == "":
        if k in self.textControlsOriginal.keys():
          result[k] = self.textControlsOriginal[k][0], False
        else:
          result[k] = "", False
      else:
        result[k] = v, True

    for k in self.radioButtons.keys():
      result[k] = self.radioButtons[k].GetValue(), True

    for k in self.choices.keys():
      v = self.choices[k].GetSelection()
      s = self.choices[k].GetString(v)
      if s == "-":
        if k in self.choicesOriginal.keys():
          result[k] = self.choicesOriginal[k][0], False
        else:
          result[k] = "", False
      else:
        result[k] = s, True

    for k in self.boolChoices.keys():
      choice = self.boolChoices[k]
      for i in range(choice.GetCount()):
        s = choice.GetClientData(i)
        if s:
          result[s] = (i == choice.GetSelection())

    return result

  def assertModified(self, flag):
    if flag != self.modified:
      self.parent.assertModified(self.id, flag)
      self.modified = flag

  def setFieldValidity(self, name, flag):
    self.fieldValid[name] = flag

    pgValid = True
    for k in self.fieldValid.keys():
      if not self.fieldValid[k]:
        pgValid = False
        break

    self.assertValid(pgValid)

  def assertValid(self, flag):
    if flag != self.valid:
      self.parent.assertValid(self.id, flag)
      self.valid = flag
コード例 #22
0
ファイル: boardpanel.py プロジェクト: pezr/Teacup_Firmware
class BoardPanel(wx.Panel):
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent
        self.settings = settings
        self.protFileLoaded = False

        self.deco = Decoration()
        self.configFile = None

        self.cfgValues = {}
        self.heaters = []
        self.sensors = []
        self.candHeatPins = []
        self.candThermPins = []
        self.dir = os.path.join(self.settings.folder, "config")
        self.cfgDir = os.path.join(self.settings.folder, "configtool")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgCpu = self.registerPage(CpuPage, "CPU")
        self.pgPins = self.registerPage(PinoutsPage, "Pinouts")
        self.pgDisplay = self.registerPage(DisplayPage, "Display")
        self.pgHeaters = self.registerPage(HeatersPage, "Heaters")
        self.pgSensors = self.registerPage(SensorsPage,
                                           "Temperature Sensors",
                                           heatersPage=self.pgHeaters)
        self.pgCommunications = self.registerPage(CommunicationsPage,
                                                  "Communications")

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()

    def registerPage(self, klass, label, *args, **kwargs):
        page = klass(self,
                     self.nb,
                     len(self.pages),
                     *args,
                     font=self.settings.font,
                     **kwargs)
        self.nb.AddPage(page, label)
        self.pages.append(page)
        self.titles.append(label)
        self.pageModified.append(False)
        self.pageValid.append(True)
        return page

    def getCPUInfo(self):
        vF_CPU = None
        if 'F_CPU' in self.cfgValues.keys():
            vF_CPU = self.cfgValues['F_CPU'][0]

        vCPU = None
        if 'CPU' in self.cfgValues.keys():
            vCPU = self.cfgValues['CPU'][0]

        return vF_CPU, vCPU

    def assertModified(self, pg, flag=True):
        self.pageModified[pg] = flag
        self.modifyTab(pg)

    def isModified(self):
        return (True in self.pageModified)

    def isValid(self):
        return not (False in self.pageValid)

    def hasData(self):
        return (self.configFile != None)

    def getFileName(self):
        return self.configFile

    def assertValid(self, pg, flag=True):
        self.pageValid[pg] = flag
        self.modifyTab(pg)

        if False in self.pageValid:
            self.parent.enableSaveBoard(False, False)
        else:
            self.parent.enableSaveBoard(not self.protFileLoaded, True)

    def modifyTab(self, pg):
        if self.pageModified[pg] and not self.pageValid[pg]:
            pfx = "?* "
        elif self.pageModified[pg]:
            pfx = "* "
        elif not self.pageValid[pg]:
            pfx = "? "
        else:
            pfx = ""

        self.nb.SetPageText(pg, pfx + self.titles[pg])
        if True in self.pageModified and False in self.pageValid:
            pfx = "?* "
        elif True in self.pageModified:
            pfx = "* "
        elif False in self.pageValid:
            pfx = "? "
        else:
            pfx = ""
        self.parent.setBoardTabDecor(pfx)

    def setHeaters(self, ht):
        self.parent.setHeaters(ht)

    def onClose(self, evt):
        if not self.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def confirmLoseChanges(self, msg):
        if True not in self.pageModified:
            return True

        dlg = wx.MessageDialog(
            self, "Are you sure you want to " + msg + "?\n"
            "There are changes to your board "
            "configuration that will be lost.", "Changes pending",
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()

        if rc != wx.ID_YES:
            return False

        return True

    def onLoadConfig(self, evt):
        if not self.confirmLoseChanges("load a new board configuration"):
            return

        if platform == "darwin":
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Board configuration (board.*.h)|*.h"
        else:
            wildcard = "Board configuration (board.*.h)|board.*.h"

        dlg = wx.FileDialog(self,
                            message="Choose a board config file",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.OPEN | wx.CHANGE_DIR)

        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

        dlg.Destroy()
        if path is None:
            return

        self.dir = os.path.dirname(path)
        rc, efn = self.loadConfigFile(path)

        if not rc:
            dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

    def loadConfigFile(self, fn):
        cfgFn = os.path.join(self.cfgDir, "board.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

        self.processors = []
        self.sensors = []
        self.heaters = []
        self.candHeatPins = []
        self.candThermPins = []
        self.candProcessors = []
        self.candClocks = []
        self.tempTables = {}
        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 = ""

            if self.parseCandidateValues(ln):
                continue

            if self.parseDefineName(ln):
                continue

        # Ignore candidates in the metadata file.
        self.candHeatPins = []
        self.candThermPins = []
        self.candProcessors = []
        self.candClocks = []
        self.tempTables = {}
        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 = ""

            if self.parseCandidateValues(ln):
                continue

            elif self.parseDefineValue(ln):
                continue

            else:
                m = reDefTS.search(ln)
                if m:
                    t = m.groups()
                    if len(t) == 1:
                        s = self.parseSensor(t[0])
                        if s:
                            self.sensors.append(s)
                            continue

                m = reDefHT.search(ln)
                if m:
                    t = m.groups()
                    if len(t) == 1:
                        s = self.parseHeater(t[0])
                        if s:
                            self.heaters.append(s)
                            continue

        # Parsing done. All parsed stuff is now in these arrays and dicts.
        # Uncomment for debugging.
        #print self.processors
        #print self.sensors
        #print self.heaters
        #print self.candHeatPins
        #print self.candThermPins
        #print self.candProcessors
        #print self.candClocks
        #print self.tempTables
        #print self.cfgValues  # #defines with a value and booleans.
        #print self.cfgNames   # Names found in the generic file.
        #print self.helpText

        for k in range(len(self.sensors)):
            tn = self.sensors[k][0].upper()
            if tn in self.tempTables.keys():
                self.sensors[k][3] = self.tempTables[tn]
            else:
                self.sensors[k][3] = None

        if os.path.basename(fn) in protectedFiles:
            self.parent.enableSaveBoard(False, True)
            self.protFileLoaded = True
        else:
            self.protFileLoaded = False
            self.parent.enableSaveBoard(True, True)

        self.parent.setBoardTabFile(os.path.basename(fn))
        self.pgHeaters.setCandidatePins(self.candHeatPins)
        self.pgSensors.setCandidatePins(self.candThermPins)
        self.pgCpu.setCandidateProcessors(self.candProcessors)
        self.pgCpu.setCandidateClocks(self.candClocks)

        for pg in self.pages:
            pg.insertValues(self.cfgValues)
            pg.setHelpText(self.helpText)

        self.pgSensors.setSensors(self.sensors)
        self.pgHeaters.setHeaters(self.heaters)

        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()
            if len(t) == 1 and (t[0] in self.cfgNames):
                if reDefBoolBL.search(ln):
                    self.cfgValues[t[0]] = True
                else:
                    self.cfgValues[t[0]] = False
                return True

        return False

    def parseCandidateValues(self, ln):
        m = reCandThermPins.match(ln)
        if m:
            t = m.groups()
            if len(t) == 1:
                self.candThermPins.append(t[0])
            return True

        m = reCandHeatPins.match(ln)
        if m:
            t = m.groups()
            if len(t) == 1:
                self.candHeatPins.append(t[0])
            return True

        m = reCandProcessors.match(ln)
        if m:
            t = m.groups()
            if len(t) == 1:
                self.candProcessors.append(t[0])
            return True

        m = reCandCPUClocks.match(ln)
        if m:
            t = m.groups()
            if len(t) == 1:
                self.candClocks.append(t[0])
            return True

        m = reDefTT.match(ln)
        if m:
            t = m.groups()
            if len(t) == 2:
                s = self.parseTempTable(t[1])
                if s:
                    self.tempTables[t[0]] = s
            return True

        return False

    def parseSensor(self, s):
        m = reSensor.search(s)
        if m:
            t = m.groups()
            if len(t) == 4:
                return list(t)
        return None

    def parseHeater(self, s):
        m = reHeater4.search(s)
        if m:
            t = m.groups()
            if len(t) == 4:
                return list(t)
        # reHeater3 deprecated, for compatibility with old config files only.
        m = reHeater3.search(s)
        if m:
            t = m.groups()
            if len(t) == 3:
                t = list(t)
                t.insert(2, '0')
                return t
        # End of deprecated part.
        return None

    def parseTempTable(self, s):
        m = reTempTable4.search(s)
        if m:
            t = m.groups()
            if len(t) == 4:
                return list(t)
        m = reTempTable7.search(s)
        if m:
            t = m.groups()
            if len(t) == 7:
                return list(t)
        return None

    def onSaveConfig(self, evt):
        path = self.configFile
        return self.saveConfigFile(path)

    def onSaveConfigAs(self, evt):
        wildcard = "Board configuration (board.*.h)|board.*.h"

        dlg = wx.FileDialog(self,
                            message="Save as ...",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        val = dlg.ShowModal()

        if val != wx.ID_OK:
            dlg.Destroy()
            return

        path = dlg.GetPath()
        dlg.Destroy()

        rc = self.saveConfigFile(path)
        if rc:
            self.parent.setBoardTabFile(os.path.basename(path))
            self.protFileLoaded = False
            self.parent.enableSaveBoard(True, True)
        return rc

    def saveConfigFile(self, path):
        if os.path.basename(path) in protectedFiles:
            dlg = wx.MessageDialog(
                self, "It's not allowed to overwrite files "
                "distributed by Teacup. Choose another name.",
                "Protected file error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        if not os.path.basename(path).startswith("board."):
            dlg = wx.MessageDialog(
                self, "Illegal file name: %s.\n"
                "File name must begin with \"board.\"" % path,
                "Illegal file name", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        ext = os.path.splitext(os.path.basename(path))[1]
        self.dir = os.path.dirname(path)

        if ext == "":
            path += ".h"

        try:
            fp = file(path, 'w')
        except:
            dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            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]

        skipToSensorEnd = False
        skipToHeaterEnd = False
        candThermPinsWritten = False
        candHeatPinsWritten = False
        candProcessorsWritten = False
        candCPUClocksWritten = False

        for ln in self.cfgBuffer:
            m = reStartSensors.match(ln)
            if m:
                fp.write(ln)
                fp.write("//                 name      type           pin    "
                         "additional\n")
                ttString = "\n"
                ttString += "// Beta algorithm      r0      beta  r2    vadc\n"
                ttString += "// Steinhart-Hart      rp      t0    r0      t1    "
                ttString += "r1      t2    r2\n"
                for s in self.sensors:
                    sstr = "%-10s%-15s%-7s" % ((s[0] + ","), (s[1] + ","),
                                               (s[2] + ","))
                    if s[3] is None:
                        sstr += "0"
                    else:
                        sstr += "THERMISTOR_%s" % s[0].upper()
                        tt = s[3]
                        if len(tt) == 4:
                            ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-6s%s)\n" % \
                                        (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                                         (tt[2] + ","), tt[3])
                        else:
                            ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-8s%-6s%-8s%-6s%s)\n" % \
                                        (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                                         (tt[2] + ","), (tt[3] + ","), (tt[4] + ","),
                                         (tt[5] + ","), tt[6])
                    fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr)
                fp.write(ttString)
                skipToSensorEnd = True
                continue

            if skipToSensorEnd:
                m = reEndSensors.match(ln)
                if m:
                    fp.write(ln)
                    skipToSensorEnd = False
                continue

            m = reStartHeaters.match(ln)
            if m:
                fp.write(ln)
                fp.write("//            name      pin      invert  pwm\n")
                for s in self.heaters:
                    sstr = "%-10s%-9s%-8s%s" % ((s[0] + ","), (s[1] + ","),
                                                (s[2] + ","), s[3])
                    fp.write("DEFINE_HEATER(%s)\n" % sstr)
                fp.write("\n")
                for s in self.heaters:
                    fp.write(defineHeaterFormat % (s[0].upper(), s[0]))
                skipToHeaterEnd = True
                continue

            if skipToHeaterEnd:
                m = reEndHeaters.match(ln)
                if m:
                    fp.write(ln)
                    skipToHeaterEnd = False
                continue

            if reCandThermPins.match(ln):
                if not candThermPinsWritten:
                    for pin in self.candThermPins:
                        fp.write("//#define TEMP_SENSOR_PIN " + pin + "\n")
                    candThermPinsWritten = True
                continue

            if reCandHeatPins.match(ln):
                if not candHeatPinsWritten:
                    for pin in self.candHeatPins:
                        fp.write("//#define HEATER_PIN " + pin + "\n")
                    candHeatPinsWritten = True
                continue

            if reCandProcessors.match(ln):
                if not candProcessorsWritten:
                    for pin in self.candProcessors:
                        fp.write("//#define CPU_TYPE " + pin + "\n")
                    candProcessorsWritten = True
                continue

            if reCandCPUClocks.match(ln):
                if not candCPUClocksWritten:
                    for pin in self.candClocks:
                        fp.write("//#define F_CPU_OPT " + pin + "\n")
                    candCPUClocksWritten = True
                continue

            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:
                    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:
                    if t[0] == 'MOTHERBOARD':
                        # Known to be absent in the GUI, also won't be added anytime soon.
                        fp.write(ln)
                    else:
                        print "Boolean key " + t[0] + " not found in GUI."

                continue

            fp.write(ln)

        fp.close()
        return self.generateTempTables()

    def generateTempTables(self):
        if not generateTempTables(self.sensors, self.settings):
            dlg = wx.MessageDialog(self,
                                   "Error writing to file thermistortable.h.",
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        return True
コード例 #23
0
class BoardPanel(wx.Panel):
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent
    self.settings = settings
    self.protFileLoaded = False

    self.deco = Decoration()
    self.configFile = None

    self.cfgValues = {}
    self.heaters = []
    self.sensors = []
    self.candHeatPins = []
    self.candThermPins = []
    self.dir = os.path.join(self.settings.folder, "config")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgCpu = CpuPage(self, self.nb, len(self.pages), self.settings.font)
    text = "CPU"
    self.nb.AddPage(self.pgCpu, text)
    self.pages.append(self.pgCpu)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgPins = PinoutsPage(self, self.nb, len(self.pages),
                              self.settings.font)
    text = "Pinouts"
    self.nb.AddPage(self.pgPins, text)
    self.pages.append(self.pgPins)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgHeaters = HeatersPage(self, self.nb, len(self.pages),
                                 self.settings.font)
    text = "Heaters"
    self.nb.AddPage(self.pgHeaters, text)
    self.pages.append(self.pgHeaters)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgSensors = SensorsPage(self, self.nb, len(self.pages), self.pgHeaters,
                                 self.settings.font)
    text = "Temperature Sensors"
    self.nb.AddPage(self.pgSensors, text)
    self.pages.append(self.pgSensors)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    self.pgCommunications = CommunicationsPage(self, self.nb, len(self.pages),
                                               self.settings.font)
    text = "Communications"
    self.nb.AddPage(self.pgCommunications, text)
    self.pages.append(self.pgCommunications)
    self.titles.append(text)
    self.pageModified.append(False)
    self.pageValid.append(True)

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()

  def getCPUInfo(self):
    vF_CPU = None
    if 'F_CPU' in self.cfgValues.keys():
      vF_CPU = self.cfgValues['F_CPU']

    vCPU = None
    if 'CPU' in self.cfgValues.keys():
      vCPU = self.cfgValues['CPU']

    return vF_CPU, vCPU

  def assertModified(self, pg, flag = True):
    self.pageModified[pg] = flag
    self.modifyTab(pg)

  def isModified(self):
    return (True in self.pageModified)

  def isValid(self):
    return not (False in self.pageValid)

  def hasData(self):
    return (self.configFile != None)

  def getFileName(self):
    return self.configFile

  def assertValid(self, pg, flag = True):
    self.pageValid[pg] = flag
    self.modifyTab(pg)

    if False in self.pageValid:
      self.parent.enableSaveBoard(False, False)
    else:
      self.parent.enableSaveBoard(not self.protFileLoaded, True)

  def modifyTab(self, pg):
    if self.pageModified[pg] and not self.pageValid[pg]:
      pfx = "?* "
    elif self.pageModified[pg]:
      pfx = "* "
    elif not self.pageValid[pg]:
      pfx = "? "
    else:
      pfx = ""

    self.nb.SetPageText(pg, pfx + self.titles[pg])
    if True in self.pageModified and False in self.pageValid:
      pfx = "?* "
    elif True in self.pageModified:
      pfx = "* "
    elif False in self.pageValid:
      pfx = "? "
    else:
      pfx = ""
    self.parent.setBoardTabDecor(pfx)

  def setHeaters(self, ht):
    self.parent.setHeaters(ht)

  def onClose(self, evt):
    if not self.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def confirmLoseChanges(self, msg):
    if True not in self.pageModified:
      return True

    dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
                                 "There are changes to your board "
                                 "configuration that will be lost.",
                           "Changes pending",
                           wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
    rc = dlg.ShowModal()
    dlg.Destroy()

    if rc != wx.ID_YES:
      return False

    return True

  def onLoadConfig(self, evt):
    if not self.confirmLoseChanges("load a new board configuration"):
      return

    if platform == "darwin":
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Board configuration (board.*.h)|*.h"
    else:
      wildcard = "Board configuration (board.*.h)|board.*.h"

    dlg = wx.FileDialog(self, message = "Choose a board config file",
                        defaultDir = self.dir, defaultFile = "",
                        wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)

    path = None
    if dlg.ShowModal() == wx.ID_OK:
      path = dlg.GetPath()

    dlg.Destroy()
    if path is None:
      return

    self.dir = os.path.dirname(path)
    rc = self.loadConfigFile(path)

    if not rc:
      dlg = wx.MessageDialog(self, "Unable to process file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

  def loadConfigFile(self, fn):
    try:
      self.cfgBuffer = list(open(fn))
    except:
      return False

    self.configFile = fn

    self.processors = []
    self.sensors = []
    self.heaters = []
    self.candHeatPins = []
    self.candThermPins = []
    self.candProcessors = []
    self.candClocks = []
    tempTables = {}
    gatheringHelpText = False
    helpTextString = ""
    helpKey = None

    self.cfgValues = {}
    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 = ""

      if ln.lstrip().startswith("//"):
        m = reCandThermPins.match(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.candThermPins.append(t[0])
            continue

        m = reCandHeatPins.match(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.candHeatPins.append(t[0])
            continue

        m = reCandProcessors.match(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.candProcessors.append(t[0])
            continue

        m = reCandCPUClocks.match(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.candClocks.append(t[0])
            continue

        m = reDefTT.match(ln)
        if m:
          t = m.groups()
          if len(t) == 2:
            s = self.parseTempTable(t[1])
            if s:
              tempTables[t[0]] = s
            continue

        continue

      if ln.lstrip().startswith("#define"):
        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:
                self.cfgValues[t[0]] = tt[0]
                continue
              elif len(tt) > 1:
                self.cfgValues[t[0]] = tt
                continue

        m = reDefine.search(ln)
        if m:
          t = m.groups()
          if len(t) == 2:
            self.cfgValues[t[0]] = t[1]
            if reFloatAttr.search(ln):
              pass
            continue

        m = reDefBool.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            self.cfgValues[t[0]] = True

      else:
        m = reDefTS.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            s = self.parseSensor(t[0])
            if s:
              self.sensors.append(s)
            continue

        m = reDefHT.search(ln)
        if m:
          t = m.groups()
          if len(t) == 1:
            s = self.parseHeater(t[0])
            if s:
              self.heaters.append(s)
            continue

    for k in range(len(self.sensors)):
      tn = self.sensors[k][0].upper()
      if tn in tempTables.keys():
        self.sensors[k][3] = tempTables[tn]
      else:
        self.sensors[k][3] = None

    if os.path.basename(fn) in protectedFiles:
      self.parent.enableSaveBoard(False, True)
      self.protFileLoaded = True
    else:
      self.protFileLoaded = False
      self.parent.enableSaveBoard(True, True)
    self.parent.setBoardTabFile(os.path.basename(fn))
    self.pgHeaters.setCandidatePins(self.candHeatPins)
    self.pgSensors.setCandidatePins(self.candThermPins)
    self.pgCpu.setCandidateProcessors(self.candProcessors)
    self.pgCpu.setCandidateClocks(self.candClocks)

    for pg in self.pages:
      pg.insertValues(self.cfgValues)
      pg.setHelpText(self.helpText)

    self.pgSensors.setSensors(self.sensors)
    self.pgHeaters.setHeaters(self.heaters)

    return True

  def parseSensor(self, s):
    m = reSensor.search(s)
    if m:
      t = m.groups()
      if len(t) == 4:
        return list(t)
    return None

  def parseHeater(self, s):
    m = reHeater.search(s)
    if m:
      t = m.groups()
      if len(t) == 3:
        return list(t)
    return None

  def parseTempTable(self, s):
    m = reTempTable4.search(s)
    if m:
      t = m.groups()
      if len(t) == 4:
        return list(t)
    m = reTempTable7.search(s)
    if m:
      t = m.groups()
      if len(t) == 7:
        return list(t)
    return None

  def onSaveConfig(self, evt):
    path = self.configFile
    return self.saveConfigFile(path)

  def onSaveConfigAs(self, evt):
    wildcard = "Board configuration (board.*.h)|board.*.h"

    dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
                        defaultFile = "", wildcard = wildcard,
                        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

    val = dlg.ShowModal()

    if val != wx.ID_OK:
      dlg.Destroy()
      return

    path = dlg.GetPath()
    dlg.Destroy()

    rc = self.saveConfigFile(path)
    if rc:
      self.parent.setBoardTabFile(os.path.basename(path))
      self.protFileLoaded = False
      self.parent.enableSaveBoard(True, True)
    return rc

  def saveConfigFile(self, path):
    if os.path.basename(path) in protectedFiles:
      dlg = wx.MessageDialog(self, "Unable to overwrite %s." % path,
                             "Protected file error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    if not os.path.basename(path).startswith("board."):
      dlg = wx.MessageDialog(self, "Illegal file name: %s.\n"
                                   "File name must begin with \"board.\"" % path,
                             "Illegal file name", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    ext = os.path.splitext(os.path.basename(path))[1]
    self.dir = os.path.dirname(path)

    if ext == "":
      path += ".h"

    try:
      fp = file(path, 'w')
    except:
      dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    self.configFile = path

    values = {}
    labelFound = []

    for pg in self.pages:
      v1 = pg.getValues()
      for k in v1.keys():
        values[k] = v1[k]

    skipToSensorEnd = False
    skipToHeaterEnd = False
    tempTables = {}
    for ln in self.cfgBuffer:
      m = reStartSensors.match(ln)
      if m:
        fp.write(ln)
        fp.write("//                 name      type           pin    "
                 "additional\n");
        ttString = "\n"
        ttString += "// Beta algorithm      r0      beta  r2    vadc\n"
        ttString += "// Steinhart-Hart      rp      t0    r0      t1    "
        ttString += "r1      t2    r2\n"
        for s in self.sensors:
          sstr = "%-10s%-15s%-7s" % ((s[0] + ","), (s[1] + ","), (s[2] + ","))
          if s[3] is None:
            sstr += "0"
          else:
            sstr += "THERMISTOR_%s" % s[0].upper()
            tt = s[3]
            if len(tt) == 4:
              ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-6s%s)\n" % \
                          (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                           (tt[2] + ","), tt[3])
            else:
              ttString += "//TEMP_TABLE %-8s (%-8s%-6s%-8s%-6s%-8s%-6s%s)\n" % \
                          (s[0].upper(), (tt[0] + ","), (tt[1] + ","),
                           (tt[2] + ","), (tt[3] + ","), (tt[4] + ","),
                           (tt[5] + ","), tt[6])
          fp.write("DEFINE_TEMP_SENSOR(%s)\n" % sstr)
        fp.write(ttString)
        skipToSensorEnd = True
        continue

      if skipToSensorEnd:
        m = reEndSensors.match(ln)
        if m:
          fp.write(ln)
          skipToSensorEnd = False
        continue

      m = reStartHeaters.match(ln)
      if m:
        fp.write(ln)
        fp.write("//            name      port   pwm\n")
        for s in self.heaters:
          sstr = "%-10s%-7s%s" % ((s[0] + ","), (s[1] + ","), s[2])
          fp.write("DEFINE_HEATER(%s)\n" % sstr)
        fp.write("\n")
        for s in self.heaters:
          fp.write(defineHeaterFormat % (s[0].upper(), s[0]))
        skipToHeaterEnd = True
        continue

      if skipToHeaterEnd:
        m = reEndHeaters.match(ln)
        if m:
          fp.write(ln)
          skipToHeaterEnd = False
        continue

      m = reDefineBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 2:
          if t[0] in values.keys() and values[t[0]] != "":
            fp.write(defineValueFormat % (t[0], values[t[0]]))
            self.cfgValues[t[0]] = values[t[0]]
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write("//" + ln)
            if t[0] in self.cfgValues.keys():
              del self.cfgValues[t[0]]
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reDefBoolBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if t[0] in values.keys() and values[t[0]]:
            fp.write(defineBoolFormat % t[0])
            self.cfgValues[t[0]] = True
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write("//" + ln)
            if t[0] in self.cfgValues.keys():
              del self.cfgValues[t[0]]
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reCommDefBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 2:
          if t[0] in values.keys() and values[t[0]] != "":
            fp.write(defineValueFormat % (t[0], values[t[0]]))
            self.cfgValues[t[0]]  = values[t[0]]
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write(ln)
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      m = reCommDefBoolBL.match(ln)
      if m:
        t = m.groups()
        if len(t) == 1:
          if t[0] in values.keys() and values[t[0]]:
            fp.write(defineBoolFormat % t[0])
            self.cfgValues[t[0]] = True
            labelFound.append(t[0])
          elif t[0] in values.keys():
            fp.write(ln)
            labelFound.append(t[0])
          else:
            fp.write(ln)
          continue

      fp.write(ln)

    for k in labelFound:
      del values[k]

    newLabels = ""
    for k in values.keys():
      if newLabels == "":
        newLabels = k
      else:
        newLabels += ", " + k
      self.addNewDefine(fp, k, values[k])

    if newLabels != "":
      dlg = wx.MessageDialog(self, "New defines added to board config:\n" +
                             newLabels, "New defines",
                             wx.OK + wx.ICON_INFORMATION)
      dlg.ShowModal()
      dlg.Destroy()

    fp.close()
    return self.generateTempTables()

  def generateTempTables(self):
    if not generateTempTables(self.sensors, self.settings):
      dlg = wx.MessageDialog(self, "Error writing to file thermistortable.h.",
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    return True

  def addNewDefine(self, fp, key, val):
    fp.write("\n")
    fp.write("/** \\def %s\n" % key)
    fp.write("  Add help text here.\n")
    fp.write("*/\n")
    if val == True:
      fp.write(defineBoolFormat % key)
    elif val == False:
      fp.write("//#define %s\n" % key)
    elif val == "":
      fp.write("//#define %s\n" % key)
    else:
      fp.write(defineValueFormat % (key, val))
コード例 #24
0
class Page:
    def __init__(self, font):
        self.modified = False
        self.valid = True
        self.fieldValid = {}
        self.textControls = {}
        self.textControlsOriginal = {}
        self.checkBoxes = {}
        self.radioButtons = {}
        self.radioButtonBoxes = {}
        self.choices = {}
        self.choicesOriginal = {}
        self.deco = Decoration()
        self.font = font

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

    def enableAll(self, flag=True):
        for c in self.textControls.keys():
            self.textControls[c].Enable(flag)
        for c in self.checkBoxes.keys():
            self.checkBoxes[c].Enable(flag)
        for c in self.radioButtons.keys():
            self.radioButtons[c].Enable(flag)
        for c in self.choices.keys():
            self.choices[c].Enable(flag)

    def addTextCtrl(self, name, labelWidth, validator):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(self,
                           wx.ID_ANY,
                           self.labels[name] + " ",
                           size=(labelWidth, -1),
                           style=wx.ALIGN_RIGHT)
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetTcLabel)

        tc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_RIGHT, name=name)
        tc.SetFont(self.font)
        self.fieldValid[name] = True
        tc.Bind(wx.EVT_TEXT, validator)
        self.textControls[name] = tc
        lsz.Add(tc)

        return lsz

    def addCheckBox(self, name, validator):
        if name in self.labels.keys():
            lbl = self.labels[name]
        else:
            lbl = name
        cb = wx.CheckBox(self, wx.ID_ANY, lbl)
        cb.SetFont(self.font)
        cb.Bind(wx.EVT_CHECKBOX, validator)
        self.checkBoxes[name] = cb

        return cb

    def addRadioButton(self, name, style, validator, sbox=None):
        rb = wx.RadioButton(self, wx.ID_ANY, self.labels[name], style=style)
        rb.SetFont(self.font)
        self.Bind(wx.EVT_RADIOBUTTON, validator, rb)
        self.radioButtons[name] = rb
        if sbox is not None:
            self.radioButtonBoxes[name] = sbox

        return rb

    def addChoice(self,
                  name,
                  choices,
                  selection,
                  labelWidth,
                  validator,
                  size=(-1, -1)):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(self,
                           wx.ID_ANY,
                           self.labels[name],
                           size=(labelWidth, -1),
                           style=wx.ALIGN_RIGHT)
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetChLabel)

        ch = wx.Choice(self, wx.ID_ANY, choices=choices, size=size, name=name)
        ch.SetBackgroundColour(self.deco.getBackgroundColour())
        ch.SetFont(self.font)
        ch.Bind(wx.EVT_CHOICE, validator)
        ch.SetSelection(selection)
        lsz.Add(ch)
        self.choices[name] = ch

        return lsz

    def addPinChoice(self, name, choiceVal, pins, allowBlank, labelWidth):
        lsz = wx.BoxSizer(wx.HORIZONTAL)
        st = wx.StaticText(self,
                           wx.ID_ANY,
                           self.labels[name],
                           size=(labelWidth, -1),
                           style=wx.ALIGN_RIGHT)
        st.SetFont(self.font)
        lsz.Add(st, 1, wx.TOP, offsetChLabel)

        if allowBlank:
            opts = ["-"] + pins
        else:
            opts = pins

        ch = wx.Choice(self,
                       wx.ID_ANY,
                       choices=opts,
                       name=name,
                       style=wx.CB_SORT)
        ch.SetBackgroundColour(self.deco.getBackgroundColour())
        ch.SetFont(self.font)
        ch.Bind(wx.EVT_CHOICE, self.onChoice)
        self.choices[name] = ch
        try:
            sv = self.pinNames.index(choiceVal)
        except:
            sv = 0
        ch.SetSelection(sv)
        lsz.Add(ch)

        return lsz

    def setChoice(self, name, cfgValues, default):
        if name in cfgValues.keys() and cfgValues[name][1] == True:
            bv = cfgValues[name][0]
        else:
            bv = default

        s = self.choices[name].FindString(bv)
        if s < 0:
            s = self.choices[name].FindString(default)
            if s < 0:
                s = 0

        self.choices[name].SetSelection(s)

    def onTextCtrlInteger(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        name = tc.GetName()
        w = tc.GetValue().strip()
        if w == "":
            valid = True
        else:
            m = reInteger.match(w)
            if m:
                valid = True
            else:
                valid = False

        self.setFieldValidity(name, valid)

        if valid:
            tc.SetBackgroundColour(
                wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
        else:
            tc.SetBackgroundColour("pink")
        tc.Refresh()
        evt.Skip()

    def onTextCtrlFloat(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        name = tc.GetName()
        w = tc.GetValue().strip()
        if w == "":
            valid = True
        else:
            m = reFloat.match(w)
            if m:
                valid = True
            else:
                valid = False

        self.setFieldValidity(name, valid)

        if valid:
            tc.SetBackgroundColour(
                wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
        else:
            tc.SetBackgroundColour("pink")
        tc.Refresh()
        evt.Skip()

    def onTextCtrlPin(self, evt):
        self.assertModified(True)
        tc = evt.GetEventObject()
        self.validatePin(tc)
        evt.Skip()

    def onTextCtrl(self, evt):
        self.assertModified(True)
        evt.Skip()

    def onChoice(self, evt):
        self.assertModified(True)
        evt.Skip()

    def onCheckBox(self, evt):
        self.assertModified(True)
        evt.Skip()

    def setHelpText(self, ht):
        for k in self.textControls.keys():
            if k in ht.keys():
                self.textControls[k].SetToolTipString(ht[k])

        for k in self.checkBoxes.keys():
            if k in ht.keys():
                self.checkBoxes[k].SetToolTipString(ht[k])

        for k in self.radioButtons.keys():
            if k in ht.keys():
                self.radioButtons[k].SetToolTipString(ht[k])
                if k in self.radioButtonBoxes.keys():
                    self.radioButtonBoxes[k].SetToolTipString(ht[k])

        for k in self.choices.keys():
            if k in ht.keys():
                self.choices[k].SetToolTipString(ht[k])

    def insertValues(self, cfgValues):
        self.assertValid(True)
        self.enableAll(True)
        for k in self.fieldValid.keys():
            self.fieldValid[k] = True

        for k in self.checkBoxes.keys():
            if k in cfgValues.keys() and cfgValues[k]:
                self.checkBoxes[k].SetValue(True)
            else:
                self.checkBoxes[k].SetValue(False)

        for k in self.textControls.keys():
            if k in cfgValues.keys():
                self.textControlsOriginal[k] = cfgValues[k]
                if cfgValues[k][1] == True:
                    self.textControls[k].SetValue(str(cfgValues[k][0]))
                else:
                    self.textControls[k].SetValue("")
            else:
                print "Key " + k + " not found in config data."

        self.assertModified(False)

    def getValues(self):
        self.assertModified(False)
        result = {}

        for k in self.checkBoxes.keys():
            cb = self.checkBoxes[k]
            result[k] = cb.IsChecked()

        for k in self.textControls.keys():
            v = self.textControls[k].GetValue()
            if v == "":
                if k in self.textControlsOriginal.keys():
                    result[k] = self.textControlsOriginal[k][0], False
                else:
                    result[k] = "", False
            else:
                result[k] = v, True

        for k in self.radioButtons.keys():
            result[k] = self.radioButtons[k].GetValue(), True

        for k in self.choices.keys():
            v = self.choices[k].GetSelection()
            result[k] = self.choices[k].GetString(v), True

        return result

    def assertModified(self, flag):
        if flag != self.modified:
            self.parent.assertModified(self.id, flag)
            self.modified = flag

    def setFieldValidity(self, name, flag):
        self.fieldValid[name] = flag

        pgValid = True
        for k in self.fieldValid.keys():
            if not self.fieldValid[k]:
                pgValid = False
                break

        self.assertValid(pgValid)

    def assertValid(self, flag):
        if flag != self.valid:
            self.parent.assertValid(self.id, flag)
            self.valid = flag
コード例 #25
0
class PrinterPanel(wx.Panel):
    def __init__(self, parent, nb, settings):
        wx.Panel.__init__(self, nb, wx.ID_ANY)
        self.parent = parent

        self.deco = Decoration()
        self.configFile = None
        self.protFileLoaded = False

        self.settings = settings

        self.cfgValues = {}
        self.heaters = []
        self.dir = os.path.join(self.settings.folder, "config")

        self.SetBackgroundColour(self.deco.getBackgroundColour())
        self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(self,
                              wx.ID_ANY,
                              size=(21, 21),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.pages = []
        self.titles = []
        self.pageModified = []
        self.pageValid = []

        self.pgMech = MechanicalPage(self, self.nb, len(self.pages),
                                     self.settings.font)
        text = "Mechanical"
        self.nb.AddPage(self.pgMech, text)
        self.pages.append(self.pgMech)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        self.pgAcc = AccelerationPage(self, self.nb, len(self.pages),
                                      self.settings.font)
        text = "Acceleration"
        self.nb.AddPage(self.pgAcc, text)
        self.pages.append(self.pgAcc)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        self.pgMiscellaneous = MiscellaneousPage(self, self.nb,
                                                 len(self.pages),
                                                 self.settings.font)
        text = "Miscellaneous"
        self.nb.AddPage(self.pgMiscellaneous, text)
        self.pages.append(self.pgMiscellaneous)
        self.titles.append(text)
        self.pageModified.append(False)
        self.pageValid.append(True)

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

        self.SetSizer(sz)
        self.Fit()

    def getFileName(self):
        return self.configFile

    def assertModified(self, pg, flag=True):
        self.pageModified[pg] = flag
        self.modifyTab(pg)

    def isModified(self):
        return (True in self.pageModified)

    def isValid(self):
        return not (False in self.pageValid)

    def hasData(self):
        return (self.configFile != None)

    def assertValid(self, pg, flag=True):
        self.pageValid[pg] = flag
        self.modifyTab(pg)

        if False in self.pageValid:
            self.parent.enableSavePrinter(False, False)
        else:
            self.parent.enableSavePrinter(not self.protFileLoaded, True)

    def modifyTab(self, pg):
        if self.pageModified[pg] and not self.pageValid[pg]:
            pfx = "?* "
        elif self.pageModified[pg]:
            pfx = "* "
        elif not self.pageValid[pg]:
            pfx = "? "
        else:
            pfx = ""

        self.nb.SetPageText(pg, pfx + self.titles[pg])
        if True in self.pageModified and False in self.pageValid:
            pfx = "?* "
        elif True in self.pageModified:
            pfx = "* "
        elif False in self.pageValid:
            pfx = "? "
        else:
            pfx = ""
        self.parent.setPrinterTabDecor(pfx)

    def setHeaters(self, ht):
        return self.pgMiscellaneous.setHeaters(ht)

    def onClose(self, evt):
        if not self.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def confirmLoseChanges(self, msg):
        if True not in self.pageModified:
            return True

        dlg = wx.MessageDialog(
            self, "Are you sure you want to " + msg + "?\n"
            "There are changes to your printer "
            "configuration that will be lost.", "Changes pending",
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
        rc = dlg.ShowModal()
        dlg.Destroy()

        if rc != wx.ID_YES:
            return False

        return True

    def onLoadConfig(self, evt):
        if not self.confirmLoseChanges("load a new printer configuration"):
            return

        if platform == "darwin":
            # Mac OS X appears to be a bit limited on wildcards.
            wildcard = "Printer configuration (printer.*.h)|*.h"
        else:
            wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Choose a printer config file",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.OPEN | wx.CHANGE_DIR)

        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

        dlg.Destroy()
        if path is None:
            return

        self.dir = os.path.dirname(path)
        rc = self.loadConfigFile(path)

        if not rc:
            dlg = wx.MessageDialog(self, "Unable to process file %s." % path,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

    def loadConfigFile(self, fn):
        try:
            self.cfgBuffer = list(open(fn))
        except:
            return False

        self.configFile = fn

        self.processors = []
        gatheringHelpText = False
        helpTextString = ""
        helpKey = None

        self.cfgValues = {}
        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 = ""

            if ln.lstrip().startswith("//"):
                continue

            if ln.lstrip().startswith("#define"):
                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:
                                self.cfgValues[t[0]] = tt[0]
                                continue
                            elif len(tt) > 1:
                                self.cfgValues[t[0]] = tt
                                continue

                m = reDefine.search(ln)
                if m:
                    t = m.groups()
                    if len(t) == 2:
                        self.cfgValues[t[0]] = t[1]
                        continue

                m = reDefBool.search(ln)
                if m:
                    t = m.groups()
                    if len(t) == 1:
                        self.cfgValues[t[0]] = True

        if os.path.basename(fn) in protectedFiles:
            self.parent.enableSavePrinter(False, True)
            self.protFileLoaded = True
        else:
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        self.parent.setPrinterTabFile(os.path.basename(fn))

        for pg in self.pages:
            pg.insertValues(self.cfgValues)
            pg.setHelpText(self.helpText)

        k = 'DC_EXTRUDER'
        if k in self.cfgValues.keys():
            self.pgMiscellaneous.setOriginalHeater(self.cfgValues[k])
        else:
            self.pgMiscellaneous.setOriginalHeater(None)

        return True

    def onSaveConfig(self, evt):
        path = self.configFile
        return self.saveConfigFile(path)

    def onSaveConfigAs(self, evt):
        wildcard = "Printer configuration (printer.*.h)|printer.*.h"

        dlg = wx.FileDialog(self,
                            message="Save as ...",
                            defaultDir=self.dir,
                            defaultFile="",
                            wildcard=wildcard,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        val = dlg.ShowModal()

        if val != wx.ID_OK:
            dlg.Destroy()
            return

        path = dlg.GetPath()
        dlg.Destroy()

        rc = self.saveConfigFile(path)
        if rc:
            self.parent.setPrinterTabFile(os.path.basename(path))
            self.protFileLoaded = False
            self.parent.enableSavePrinter(True, True)
        return rc

    def saveConfigFile(self, path):
        if os.path.basename(path) in protectedFiles:
            dlg = wx.MessageDialog(self, "Unable to overwrite %s." % path,
                                   "Protected file error",
                                   wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        if not os.path.basename(path).startswith("printer."):
            dlg = wx.MessageDialog(
                self, "Illegal file name: %s.\n"
                "File name must begin with \"printer.\"" % path,
                "Illegal file name", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        ext = os.path.splitext(os.path.basename(path))[1]
        self.dir = os.path.dirname(path)

        if ext == "":
            path += ".h"

        try:
            fp = file(path, 'w')
        except:
            dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                                   "File error", wx.OK + wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return False

        self.configFile = path

        values = {}
        labelFound = []

        for pg in self.pages:
            v1 = pg.getValues()
            for k in v1.keys():
                values[k] = v1[k]

        for ln in self.cfgBuffer:
            m = reDefineBL.match(ln)
            if m:
                t = m.groups()
                if len(t) == 2:
                    if t[0] in values.keys() and values[t[0]] != "":
                        fp.write(defineValueFormat % (t[0], values[t[0]]))
                        self.cfgValues[t[0]] = values[t[0]]
                        labelFound.append(t[0])
                    elif t[0] in values.keys():
                        fp.write("//" + ln)
                        if t[0] in self.cfgValues.keys():
                            del self.cfgValues[t[0]]
                        labelFound.append(t[0])
                    else:
                        fp.write(ln)
                    continue

            m = reDefBoolBL.match(ln)
            if m:
                t = m.groups()
                if len(t) == 1:
                    if t[0] in values.keys() and values[t[0]]:
                        fp.write(defineBoolFormat % t[0])
                        self.cfgValues[t[0]] = True
                        labelFound.append(t[0])
                    elif t[0] in values.keys():
                        fp.write("//" + ln)
                        if t[0] in self.cfgValues.keys():
                            del self.cfgValues[t[0]]
                        labelFound.append(t[0])
                    else:
                        fp.write(ln)
                    continue

            m = reCommDefBL.match(ln)
            if m:
                t = m.groups()
                if len(t) == 2:
                    if t[0] in values.keys() and values[t[0]] != "":
                        fp.write(defineValueFormat % (t[0], values[t[0]]))
                        self.cfgValues[t[0]] = values[t[0]]
                        labelFound.append(t[0])
                    elif t[0] in values.keys():
                        fp.write(ln)
                        labelFound.append(t[0])
                    else:
                        fp.write(ln)
                    continue

            m = reCommDefBoolBL.match(ln)
            if m:
                t = m.groups()
                if len(t) == 1:
                    if t[0] in values.keys() and values[t[0]]:
                        fp.write(defineBoolFormat % t[0])
                        self.cfgValues[t[0]] = True
                        labelFound.append(t[0])
                    elif t[0] in values.keys():
                        fp.write(ln)
                        labelFound.append(t[0])
                    else:
                        fp.write(ln)
                    continue

            fp.write(ln)

        for k in labelFound:
            del values[k]

        newLabels = ""
        for k in values.keys():
            if newLabels == "":
                newLabels = k
            else:
                newLabels += ", " + k
            self.addNewDefine(fp, k, values[k])

        if newLabels != "":
            dlg = wx.MessageDialog(
                self, "New defines added to printer config:\n" + newLabels,
                "New defines", wx.OK + wx.ICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()

        fp.close()

        return True

    def addNewDefine(self, fp, key, val):
        fp.write("\n")
        fp.write("/** \\def %s\n" % key)
        fp.write("  Add help text here.\n")
        fp.write("*/\n")
        if val == True:
            fp.write(defineBoolFormat % key)
        elif val == False:
            fp.write("//#define %s\n" % key)
        elif val == "":
            fp.write("//#define %s\n" % key)
        else:
            fp.write(defineValueFormat % (key, val))
コード例 #26
0
class ConfigFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Teacup Configtool", size=(880, 550))
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.Bind(wx.EVT_SIZE, self.onResize)

        self.deco = Decoration()

        panel = wx.Panel(self, -1)
        panel.SetBackgroundColour(self.deco.getBackgroundColour())
        panel.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)

        self.settings = Settings(self, cmd_folder)
        self.settings.font = wx.Font(8, wx.FONTFAMILY_SWISS,
                                     wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)
        self.settings.folder = cmd_folder

        self.heaters = []
        self.savePrtEna = False
        self.saveBrdEna = False
        self.protPrtFile = False
        self.protBrdFile = False

        sz = wx.BoxSizer(wx.HORIZONTAL)

        self.nb = wx.Notebook(panel,
                              wx.ID_ANY,
                              size=(880, 550),
                              style=wx.BK_DEFAULT)
        self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
        self.nb.SetFont(self.settings.font)

        self.printerFileName = None
        self.printerTabDecor = ""
        self.printerBaseText = "Printer"
        self.pgPrinter = PrinterPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgPrinter, self.printerBaseText)

        self.boardFileName = None
        self.boardTabDecor = ""
        self.boardBaseText = "Board"
        self.pgBoard = BoardPanel(self, self.nb, self.settings)
        self.nb.AddPage(self.pgBoard, self.boardBaseText)

        panel.Fit()
        self.panel = panel

        sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)
        self.SetSizer(sz)
        self.makeMenu()

    def onClose(self, evt):
        if not self.pgPrinter.confirmLoseChanges("exit"):
            return

        if not self.pgBoard.confirmLoseChanges("exit"):
            return

        self.Destroy()

    def onResize(self, evt):
        self.panel.SetSize(self.GetClientSize())
        self.Refresh()
        evt.Skip()

    def setPrinterTabFile(self, fn):
        self.printerFileName = fn
        self.updatePrinterTab()

    def setPrinterTabDecor(self, prefix):
        self.printerTabDecor = prefix
        self.updatePrinterTab()

    def updatePrinterTab(self):
        txt = self.printerTabDecor + self.printerBaseText
        if self.printerFileName:
            txt += " <%s>" % self.printerFileName
        self.nb.SetPageText(0, txt)

    def setBoardTabFile(self, fn):
        self.boardFileName = fn
        self.updateBoardTab()

    def setBoardTabDecor(self, prefix):
        self.boardTabDecor = prefix
        self.updateBoardTab()

    def updateBoardTab(self):
        txt = self.boardTabDecor + self.boardBaseText
        if self.boardFileName:
            txt += " <%s>" % self.boardFileName
        self.nb.SetPageText(1, txt)

    def setHeaters(self, ht):
        self.heaters = ht
        self.pgPrinter.setHeaters(ht)

    def makeMenu(self):
        file_menu = wx.Menu()

        file_menu.Append(
            ID_LOAD_CONFIG, "Load config.h",
            "Load config.h and its named printer and board files.")
        self.Bind(wx.EVT_MENU, self.onLoadConfig, id=ID_LOAD_CONFIG)
        file_menu.Enable(ID_LOAD_CONFIG, False)

        file_menu.Append(ID_SAVE_CONFIG, "Save config.h",
                         "Save config.h file.")
        self.Bind(wx.EVT_MENU, self.onSaveConfig, id=ID_SAVE_CONFIG)
        file_menu.Enable(ID_SAVE_CONFIG, False)

        file_menu.AppendSeparator()

        file_menu.Append(ID_LOAD_PRINTER, "Load printer",
                         "Load a printer configuration file.")
        self.Bind(wx.EVT_MENU, self.pgPrinter.onLoadConfig, id=ID_LOAD_PRINTER)

        file_menu.Append(ID_SAVE_PRINTER, "Save printer",
                         "Save printer configuration.")
        self.Bind(wx.EVT_MENU, self.onSavePrinterConfig, id=ID_SAVE_PRINTER)
        file_menu.Enable(ID_SAVE_PRINTER, False)

        file_menu.Append(ID_SAVE_PRINTER_AS, "Save printer as...",
                         "Save printer configuration to a new file.")
        self.Bind(wx.EVT_MENU,
                  self.onSavePrinterConfigAs,
                  id=ID_SAVE_PRINTER_AS)
        file_menu.Enable(ID_SAVE_PRINTER_AS, False)

        file_menu.AppendSeparator()

        file_menu.Append(ID_LOAD_BOARD, "Load board",
                         "Load a board configuration file.")
        self.Bind(wx.EVT_MENU, self.pgBoard.onLoadConfig, id=ID_LOAD_BOARD)

        file_menu.Append(ID_SAVE_BOARD, "Save board",
                         "Save board configuration.")
        self.Bind(wx.EVT_MENU, self.onSaveBoardConfig, id=ID_SAVE_BOARD)
        file_menu.Enable(ID_SAVE_BOARD, False)

        file_menu.Append(ID_SAVE_BOARD_AS, "Save board as...",
                         "Save board configuration to a new file.")
        self.Bind(wx.EVT_MENU, self.onSaveBoardConfigAs, id=ID_SAVE_BOARD_AS)
        file_menu.Enable(ID_SAVE_BOARD_AS, False)

        file_menu.AppendSeparator()

        file_menu.Append(wx.ID_EXIT, "E&xit", "Exit the application.")
        self.Bind(wx.EVT_MENU, self.onClose, id=wx.ID_EXIT)

        self.fileMenu = file_menu

        menu_bar = wx.MenuBar()

        menu_bar.Append(file_menu, "&File")

        edit_menu = wx.Menu()

        edit_menu.Append(ID_SETTINGS, "Settings", "Change settings.")
        self.Bind(wx.EVT_MENU, self.onEditSettings, id=ID_SETTINGS)

        self.editMenu = edit_menu

        menu_bar.Append(edit_menu, "&Edit")

        build_menu = wx.Menu()

        build_menu.Append(ID_BUILD, "Build", "Build the executable.")
        self.Bind(wx.EVT_MENU, self.onBuild, id=ID_BUILD)

        build_menu.Append(ID_UPLOAD, "Upload", "Upload the executable.")
        self.Bind(wx.EVT_MENU, self.onUpload, id=ID_UPLOAD)

        self.buildMenu = build_menu

        menu_bar.Append(build_menu, "&Build")

        self.SetMenuBar(menu_bar)
        loadFlag = self.checkEnableLoadConfig()
        self.checkEnableUpload()
        if loadFlag:
            self.loadConfigFile("config.h")

    def onSaveBoardConfig(self, evt):
        rc = self.pgBoard.onSaveConfig(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSaveBoardConfigAs(self, evt):
        rc = self.pgBoard.onSaveConfigAs(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSavePrinterConfig(self, evt):
        rc = self.pgPrinter.onSaveConfig(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def onSavePrinterConfigAs(self, evt):
        rc = self.pgPrinter.onSaveConfigAs(evt)
        if rc:
            self.checkEnableLoadConfig()
        return rc

    def checkEnableLoadConfig(self):
        fn = os.path.join(cmd_folder, "config.h")
        if os.path.isfile(fn):
            self.fileMenu.Enable(ID_LOAD_CONFIG, True)
            self.buildMenu.Enable(ID_BUILD, True)
            return True
        else:
            self.fileMenu.Enable(ID_LOAD_CONFIG, False)
            self.buildMenu.Enable(ID_BUILD, False)
            return False

    def checkEnableUpload(self):
        fn = os.path.join(cmd_folder, "teacup.hex")
        if os.path.isfile(fn):
            self.buildMenu.Enable(ID_UPLOAD, True)
        else:
            self.buildMenu.Enable(ID_UPLOAD, False)

    def enableSavePrinter(self, saveFlag, saveAsFlag):
        self.fileMenu.Enable(ID_SAVE_PRINTER, saveFlag)
        self.fileMenu.Enable(ID_SAVE_PRINTER_AS, saveAsFlag)
        self.savePrtEna = saveAsFlag
        self.protPrtFile = not saveFlag
        if self.savePrtEna and self.saveBrdEna:
            self.enableSaveConfig(True)
        else:
            self.enableSaveConfig(False)

    def enableSaveBoard(self, saveFlag, saveAsFlag):
        self.fileMenu.Enable(ID_SAVE_BOARD, saveFlag)
        self.fileMenu.Enable(ID_SAVE_BOARD_AS, saveAsFlag)
        self.saveBrdEna = saveAsFlag
        self.protBrdFile = not saveFlag
        if self.savePrtEna and self.saveBrdEna:
            self.enableSaveConfig(True)
        else:
            self.enableSaveConfig(False)

    def enableSaveConfig(self, flag):
        self.fileMenu.Enable(ID_SAVE_CONFIG, flag)

    def onLoadConfig(self, evt):
        self.loadConfigFile("config.h")

    def loadConfigFile(self, fn):
        if not self.pgPrinter.confirmLoseChanges("load config"):
            return False

        if not self.pgBoard.confirmLoseChanges("load config"):
            return False

        pfile, bfile = self.getConfigFileNames(fn)

        if not pfile:
            self.message(
                "Config file did not contain a printer file "
                "include statement.", "Config error")
            return False
        else:
            if not self.pgPrinter.loadConfigFile(pfile):
                self.message(
                    "There was a problem loading the printer config file:\n%s"
                    % pfile, "Config error")
                return False

        if not bfile:
            self.message(
                "Config file did not contain a board file "
                "include statement.", "Config error")
            return False
        else:
            if not self.pgBoard.loadConfigFile(bfile):
                self.message(
                    "There was a problem loading the board config file:\n%s" %
                    bfile, "Config error")
                return False

        return True

    def getConfigFileNames(self, fn):
        pfile = None
        bfile = None
        path = os.path.join(cmd_folder, fn)
        try:
            cfgBuffer = list(open(path))
        except:
            self.message("Unable to process config file %s." % fn,
                         "File error")
            return None, None

        for ln in cfgBuffer:
            if not ln.lstrip().startswith("#include"):
                continue

            m = reInclude.search(ln)
            if m:
                t = m.groups()
                if len(t) == 1:
                    if "printer." in t[0]:
                        if pfile:
                            self.message(
                                "Multiple printer file include statements.\n"
                                "Ignoring %s." % ln, "Config error",
                                wx.OK + wx.ICON_WARNING)
                        else:
                            pfile = os.path.join(cmd_folder, t[0])
                    elif "board." in t[0]:
                        if bfile:
                            self.message(
                                "Multiple board file include statements.\n"
                                "Ignoring %s." % ln, "Config error",
                                wx.OK + wx.ICON_WARNING)
                        else:
                            bfile = os.path.join(cmd_folder, t[0])
                    else:
                        self.message(
                            "Unable to parse include statement:\n%s" % ln,
                            "Config error")

        return pfile, bfile

    def onSaveConfig(self, evt):
        fn = os.path.join(cmd_folder, "config.h")
        try:
            fp = open(fn, 'w')
        except:
            self.message("Unable to open config.h for output.", "File error")
            return False

        bfn = self.pgBoard.getFileName()
        if self.pgBoard.isModified() and self.pgBoard.isValid():
            if not self.pgBoard.saveConfigFile(bfn):
                return False
        else:
            self.pgBoard.generateTempTables()

        pfn = self.pgPrinter.getFileName()
        if self.pgPrinter.isModified() and self.pgPrinter.isValid():
            if not self.pgPrinter.saveConfigFile(pfn):
                return False

        prefix = cmd_folder + os.path.sep
        lpfx = len(prefix)

        if bfn.startswith(prefix):
            rbfn = bfn[lpfx:]
        else:
            rbfn = bfn

        if pfn.startswith(prefix):
            rpfn = pfn[lpfx:]
        else:
            rpfn = pfn

        fp.write("\n")
        fp.write("// Configuration for controller board.\n")
        fp.write("#include \"%s\"\n" % rbfn)
        fp.write("\n")
        fp.write("// Configuration for printer board.\n")
        fp.write("#include \"%s\"\n" % rpfn)

        fp.close()

        self.checkEnableLoadConfig()
        return True

    def onBuild(self, evt):
        self.onBuildorUpload(True)

    def onUpload(self, evt):
        self.onBuildorUpload(False)

    def onBuildorUpload(self, buildFlag):
        if not (self.pgPrinter.hasData() or self.pgBoard.hasData()):
            dlg = wx.MessageDialog(
                self, "Data needs to be loaded. "
                "Click Yes to load config.h.", "Data missing",
                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
            rc = dlg.ShowModal()
            dlg.Destroy()
            if rc != wx.ID_YES:
                return

            self.loadConfigFile("config.h")
        else:
            if self.pgPrinter.isModified():
                dlg = wx.MessageDialog(
                    self, "Printer data needs to be saved. Click "
                    "Yes to save printer configuration.", "Changes pending",
                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
                rc = dlg.ShowModal()
                dlg.Destroy()
                if rc != wx.ID_YES:
                    return

                if self.protPrtFile:
                    rc = self.onSavePrinterConfigAs(None)
                else:
                    rc = self.onSavePrinterConfig(None)
                if not rc:
                    return

            if self.pgBoard.isModified():
                dlg = wx.MessageDialog(
                    self, "Board data needs to be saved. Click "
                    "Yes to save board configuration.", "Changes pending",
                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
                rc = dlg.ShowModal()
                dlg.Destroy()
                if rc != wx.ID_YES:
                    return

                if self.protBrdFile:
                    rc = self.onSaveBoardConfigAs(None)
                else:
                    rc = self.onSaveBoardConfig(None)
                if not rc:
                    return

        if not self.verifyConfigLoaded():
            dlg = wx.MessageDialog(
                self, "Loaded configuration does not match the "
                "config.h file. Click Yes to save config.h.",
                "Configuration changed",
                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
            rc = dlg.ShowModal()
            dlg.Destroy()
            if rc != wx.ID_YES:
                return

            if not self.onSaveConfig(None):
                return

        f_cpu, cpu = self.pgBoard.getCPUInfo()
        if not cpu:
            dlg = wx.MessageDialog(self, "Unable to determine CPU type.",
                                   "CPU type error", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        if not f_cpu:
            dlg = wx.MessageDialog(self, "Unable to determine CPU clock rate.",
                                   "CPU clock rate error",
                                   wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        if buildFlag:
            dlg = Build(self, self.settings, f_cpu, cpu)
            dlg.ShowModal()
            dlg.Destroy()
            self.checkEnableUpload()
        else:
            dlg = Upload(self, self.settings, f_cpu, cpu)
            dlg.ShowModal()
            dlg.Destroy()

    def verifyConfigLoaded(self):
        pfile, bfile = self.getConfigFileNames("config.h")
        lpfile = self.pgPrinter.getFileName()
        lbfile = self.pgBoard.getFileName()

        return ((pfile == lpfile) and (bfile == lbfile))

    def onEditSettings(self, evt):
        dlg = SettingsDlg(self, self.settings)
        rc = dlg.ShowModal()
        dlg.Destroy()

    def message(self, text, title, style=wx.OK + wx.ICON_ERROR):
        dlg = wx.MessageDialog(self, text, title, style)
        dlg.ShowModal()
        dlg.Destroy()
コード例 #27
0
class PrinterPanel(wx.Panel):
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent

    self.deco = Decoration()
    self.protFileLoaded = False

    self.settings = settings

    self.printer = Printer(self.settings)

    self.dir = os.path.join(self.settings.folder, "config")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgMech = self.registerPage(MechanicalPage, "Mechanical")
    self.pgAcc = self.registerPage(AccelerationPage, "Acceleration")
    self.pgMiscellaneous = self.registerPage(MiscellaneousPage,
                                             "Miscellaneous")

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()

  def registerPage(self, klass, label, *args, **kwargs):
    page = klass(self, self.nb, len(self.pages), *args,
                 font = self.settings.font, **kwargs)
    self.nb.AddPage(page, label)
    self.pages.append(page)
    self.titles.append(label)
    self.pageModified.append(False)
    self.pageValid.append(True)
    return page

  def assertModified(self, pg, flag = True):
    self.pageModified[pg] = flag
    self.modifyTab(pg)

  def isModified(self):
    return (True in self.pageModified)

  def isValid(self):
    return not (False in self.pageValid)

  def hasData(self):
    return self.printer.hasData()

  def getFileName(self):
    return self.printer.configFile

  def assertValid(self, pg, flag = True):
    self.pageValid[pg] = flag
    self.modifyTab(pg)

    if False in self.pageValid:
      self.parent.enableSavePrinter(False, False)
    else:
      self.parent.enableSavePrinter(not self.protFileLoaded, True)

  def modifyTab(self, pg):
    if self.pageModified[pg] and not self.pageValid[pg]:
      pfx = "?* "
    elif self.pageModified[pg]:
      pfx = "* "
    elif not self.pageValid[pg]:
      pfx = "? "
    else:
      pfx = ""

    self.nb.SetPageText(pg, pfx + self.titles[pg])
    if True in self.pageModified and False in self.pageValid:
      pfx = "?* "
    elif True in self.pageModified:
      pfx = "* "
    elif False in self.pageValid:
      pfx = "? "
    else:
      pfx = ""
    self.parent.setPrinterTabDecor(pfx)

  def setHeaters(self, ht):
    return self.pgMiscellaneous.setHeaters(ht)

  def onClose(self, evt):
    if not self.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def confirmLoseChanges(self, msg):
    if True not in self.pageModified:
      return True

    dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
                                 "There are changes to your printer "
                                 "configuration that will be lost.",
                           "Changes pending",
                           wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
    rc = dlg.ShowModal()
    dlg.Destroy()

    if rc != wx.ID_YES:
      return False

    return True

  def onLoadConfig(self, evt):
    if not self.confirmLoseChanges("load a new printer configuration"):
      return

    if platform.startswith("darwin"):
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Printer configuration (printer.*.h)|*.h"
    else:
      wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Choose a printer config file",
                        defaultDir = self.dir, defaultFile = "",
                        wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)

    path = None
    if dlg.ShowModal() == wx.ID_OK:
      path = dlg.GetPath()

    dlg.Destroy()
    if path is None:
      return

    self.dir = os.path.dirname(path)
    rc, efn = self.loadConfigFile(path)

    if not rc:
      dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return

  def loadConfigFile(self, fn):
    ok, file = self.printer.loadConfigFile(fn)
    if not ok:
      return ok, file

    if os.path.basename(fn) in protectedFiles:
      self.parent.enableSavePrinter(False, True)
      self.protFileLoaded = True
    else:
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    self.parent.setPrinterTabFile(os.path.basename(fn))

    for pg in self.pages:
      pg.insertValues(self.printer.cfgValues)
      pg.setHelpText(self.printer.helpText)

    k = 'DC_EXTRUDER'
    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 onSaveConfig(self, evt):
    path = self.getFileName()
    return self.saveConfigFile(path)

  def onSaveConfigAs(self, evt):
    if platform.startswith("darwin"):
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Printer configuration (printer.*.h)|*.h"
    else:
      wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
                        defaultFile = "", wildcard = wildcard,
                        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

    val = dlg.ShowModal()

    if val != wx.ID_OK:
      dlg.Destroy()
      return

    path = dlg.GetPath()
    dlg.Destroy()

    rc = self.saveConfigFile(path)
    if rc:
      self.parent.setPrinterTabFile(os.path.basename(path))
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    return rc

  def saveConfigFile(self, path):
    if os.path.basename(path) in protectedFiles:
      dlg = wx.MessageDialog(self, "It's not allowed to overwrite files "
                             "distributed by Teacup. Choose another name.",
                             "Protected file error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    if not os.path.basename(path).startswith("printer."):
      dlg = wx.MessageDialog(self, "Illegal file name: %s.\n"
                             "File name must begin with \"printer.\"" % path,
                             "Illegal file name", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      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)

    if ext == "":
      path += ".h"

    try:
      self.printer.saveConfigFile(path, values)
    except:
      dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    return True
コード例 #28
0
class PrinterPanel(wx.Panel):
  def __init__(self, parent, nb, settings):
    wx.Panel.__init__(self, nb, wx.ID_ANY)
    self.parent = parent

    self.deco = Decoration()
    self.configFile = None
    self.protFileLoaded = False

    self.settings = settings

    self.cfgValues = {}
    self.heaters = []
    self.dir = os.path.join(self.settings.folder, "config")
    self.cfgDir = os.path.join(self.settings.folder, "configtool")

    self.SetBackgroundColour(self.deco.getBackgroundColour())
    self.Bind(wx.EVT_PAINT, self.deco.onPaintBackground)
    sz = wx.BoxSizer(wx.HORIZONTAL)

    self.nb = wx.Notebook(self, wx.ID_ANY, size = (21, 21),
                          style = wx.BK_DEFAULT)
    self.nb.SetBackgroundColour(self.deco.getBackgroundColour())
    self.nb.SetFont(self.settings.font)

    self.pages = []
    self.titles = []
    self.pageModified = []
    self.pageValid = []

    self.pgMech = self.registerPage(MechanicalPage, "Mechanical")
    self.pgAcc = self.registerPage(AccelerationPage, "Acceleration")
    self.pgMiscellaneous = self.registerPage(MiscellaneousPage,
                                             "Miscellaneous")

    sz.Add(self.nb, 1, wx.EXPAND + wx.ALL, 5)

    self.SetSizer(sz)
    self.Fit()

  def registerPage(self, klass, label, *args, **kwargs):
    page = klass(self, self.nb, len(self.pages), *args,
                 font = self.settings.font, **kwargs)
    self.nb.AddPage(page, label)
    self.pages.append(page)
    self.titles.append(label)
    self.pageModified.append(False)
    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)

  def isModified(self):
    return (True in self.pageModified)

  def isValid(self):
    return not (False in self.pageValid)

  def hasData(self):
    return (self.configFile != None)

  def assertValid(self, pg, flag = True):
    self.pageValid[pg] = flag
    self.modifyTab(pg)

    if False in self.pageValid:
      self.parent.enableSavePrinter(False, False)
    else:
      self.parent.enableSavePrinter(not self.protFileLoaded, True)

  def modifyTab(self, pg):
    if self.pageModified[pg] and not self.pageValid[pg]:
      pfx = "?* "
    elif self.pageModified[pg]:
      pfx = "* "
    elif not self.pageValid[pg]:
      pfx = "? "
    else:
      pfx = ""

    self.nb.SetPageText(pg, pfx + self.titles[pg])
    if True in self.pageModified and False in self.pageValid:
      pfx = "?* "
    elif True in self.pageModified:
      pfx = "* "
    elif False in self.pageValid:
      pfx = "? "
    else:
      pfx = ""
    self.parent.setPrinterTabDecor(pfx)

  def setHeaters(self, ht):
    return self.pgMiscellaneous.setHeaters(ht)

  def onClose(self, evt):
    if not self.confirmLoseChanges("exit"):
      return

    self.Destroy()

  def confirmLoseChanges(self, msg):
    if True not in self.pageModified:
      return True

    dlg = wx.MessageDialog(self, "Are you sure you want to " + msg + "?\n"
                                 "There are changes to your printer "
                                 "configuration that will be lost.",
                           "Changes pending",
                           wx.YES_NO | wx.NO_DEFAULT | wx.ICON_INFORMATION)
    rc = dlg.ShowModal()
    dlg.Destroy()

    if rc != wx.ID_YES:
      return False

    return True

  def onLoadConfig(self, evt):
    if not self.confirmLoseChanges("load a new printer configuration"):
      return

    if platform == "darwin":
      # Mac OS X appears to be a bit limited on wildcards.
      wildcard = "Printer configuration (printer.*.h)|*.h"
    else:
      wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Choose a printer config file",
                        defaultDir = self.dir, defaultFile = "",
                        wildcard = wildcard, style = wx.OPEN | wx.CHANGE_DIR)

    path = None
    if dlg.ShowModal() == wx.ID_OK:
      path = dlg.GetPath()

    dlg.Destroy()
    if path is None:
      return

    self.dir = os.path.dirname(path)
    rc, efn = self.loadConfigFile(path)

    if not rc:
      dlg = wx.MessageDialog(self, "Unable to process file %s." % efn,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      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 = ""

      if self.parseDefineName(ln):
        continue

    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 = ""

      if self.parseDefineValue(ln):
        continue

    # 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

    if os.path.basename(fn) in protectedFiles:
      self.parent.enableSavePrinter(False, True)
      self.protFileLoaded = True
    else:
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    self.parent.setPrinterTabFile(os.path.basename(fn))

    for pg in self.pages:
      pg.insertValues(self.cfgValues)
      pg.setHelpText(self.helpText)

    k = 'DC_EXTRUDER'
    if k in self.cfgValues.keys() and self.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()
      if len(t) == 1 and (t[0] in self.cfgNames):
        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
    return self.saveConfigFile(path)

  def onSaveConfigAs(self, evt):
    wildcard = "Printer configuration (printer.*.h)|printer.*.h"

    dlg = wx.FileDialog(self, message = "Save as ...", defaultDir = self.dir,
                        defaultFile = "", wildcard = wildcard,
                        style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

    val = dlg.ShowModal()

    if val != wx.ID_OK:
      dlg.Destroy()
      return

    path = dlg.GetPath()
    dlg.Destroy()

    rc = self.saveConfigFile(path)
    if rc:
      self.parent.setPrinterTabFile(os.path.basename(path))
      self.protFileLoaded = False
      self.parent.enableSavePrinter(True, True)
    return rc

  def saveConfigFile(self, path):
    if os.path.basename(path) in protectedFiles:
      dlg = wx.MessageDialog(self, "It's not allowed to overwrite files "
                             "distributed by Teacup. Choose another name.",
                             "Protected file error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    if not os.path.basename(path).startswith("printer."):
      dlg = wx.MessageDialog(self, "Illegal file name: %s.\n"
                             "File name must begin with \"printer.\"" % path,
                             "Illegal file name", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      dlg.Destroy()
      return False

    ext = os.path.splitext(os.path.basename(path))[1]
    self.dir = os.path.dirname(path)

    if ext == "":
      path += ".h"

    try:
      fp = file(path, 'w')
    except:
      dlg = wx.MessageDialog(self, "Unable to write to file %s." % path,
                             "File error", wx.OK + wx.ICON_ERROR)
      dlg.ShowModal()
      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