#!/usr/bin/env python
|
#!/usr/bin/env python
|
#
|
#
|
# coding: utf8
|
# coding: utf8
|
#
|
#
|
|
|
import gtk
|
import gtk
|
import re
|
import re
|
|
|
import sys
|
import sys
|
import os.path
|
import os.path
|
|
|
INSTANCES = []
|
INSTANCES = []
|
|
|
class ConfigFile:
|
class ConfigFile:
|
|
|
def __init__(self, filename):
|
def __init__(self, filename):
|
|
|
self.filename = filename
|
self.filename = filename
|
|
|
self.title = os.path.basename(filename)
|
self.title = os.path.basename(filename)
|
self.file = open(filename, "r")
|
self.file = open(filename, "r")
|
|
|
self.config = {
|
self.config = {
|
"comment": "//",
|
"comment": "//",
|
"define": "`define",
|
"define": "`define",
|
"command": "//="
|
"command": "//="
|
}
|
}
|
|
|
self.lines = []
|
self.lines = []
|
|
|
current_tab = "Main"
|
current_tab = "Main"
|
self.tabs = {current_tab: []}
|
self.tabs = {current_tab: []}
|
self.tabs_titles = [current_tab]
|
self.tabs_titles = [current_tab]
|
|
|
re0 = re.compile("//\s(\w.+)")
|
re0 = re.compile("//\s(\w.+)")
|
re1 = re.compile("\/\/=(valid)\s(.+)")
|
re1 = re.compile("\/\/=(valid)\s(.+)")
|
re2 = re.compile("(\/\/)?`define\s+(\w+)((\s+([\w'\.\"]+))|(\s+\/\/\s*(.*)))?\s+")
|
re2 = re.compile("(\/\/)?`define\s+(\w+)((\s+([\w'\.\"]+))|(\s+\/\/\s*(.*)))?\s+")
|
|
|
current_title = ""
|
current_title = ""
|
current_valid = ""
|
current_valid = ""
|
current_select = None
|
current_select = None
|
current_ifdef = 0
|
current_ifdef = 0
|
|
|
for n, row in enumerate(self.file):
|
for n, row in enumerate(self.file):
|
|
|
self.lines.append(row)
|
self.lines.append(row)
|
|
|
if re.match("\s+", row):
|
if re.match("\s+", row):
|
current_title = ""
|
current_title = ""
|
current_valid = ""
|
current_valid = ""
|
continue
|
continue
|
|
|
if re.match("\/\/=select", row):
|
if re.match("\/\/=select", row):
|
current_select = ConfigOptionSelect(
|
current_select = ConfigOptionSelect(
|
title = current_title
|
title = current_title
|
)
|
)
|
continue
|
continue
|
|
|
if re.match("\/\/=end", row):
|
if re.match("\/\/=end", row):
|
self.tabs[current_tab].append(current_select)
|
self.tabs[current_tab].append(current_select)
|
current_select = None
|
current_select = None
|
continue
|
continue
|
|
|
m = re.match("\/\/=comment(\s+)(.*)(\s*)", row)
|
m = re.match("\/\/=comment(\s+)(.*)(\s*)", row)
|
|
|
if m:
|
if m:
|
self.tabs[current_tab].append(ConfigLabel(m.group(2)))
|
self.tabs[current_tab].append(ConfigLabel(m.group(2)))
|
continue
|
continue
|
|
|
if re.match("\s*`ifn?def.*", row):
|
if re.match("\s*`ifn?def.*", row):
|
current_ifdef += 1
|
current_ifdef += 1
|
|
|
if re.match("\s*`endif.*", row):
|
if re.match("\s*`endif.*", row):
|
current_ifdef -= 1
|
current_ifdef -= 1
|
|
|
if current_ifdef > 0:
|
if current_ifdef > 0:
|
continue
|
continue
|
|
|
m = re.match("\/\/=tab ([\w ]+)\s+", row)
|
m = re.match("\/\/=tab ([\w ]+)\s+", row)
|
|
|
if m:
|
if m:
|
current_tab = m.group(1)
|
current_tab = m.group(1)
|
if current_tab not in self.tabs_titles:
|
if current_tab not in self.tabs_titles:
|
self.tabs[current_tab] = []
|
self.tabs[current_tab] = []
|
self.tabs_titles.append(current_tab)
|
self.tabs_titles.append(current_tab)
|
continue
|
continue
|
|
|
m = re0.match(row)
|
m = re0.match(row)
|
|
|
if m:
|
if m:
|
current_title = m.group(1)
|
current_title = m.group(1)
|
continue
|
continue
|
|
|
m = re1.match(row)
|
m = re1.match(row)
|
|
|
if m:
|
if m:
|
current_valid = m.group(2)
|
current_valid = m.group(2)
|
continue
|
continue
|
|
|
m = re2.match(row)
|
m = re2.match(row)
|
|
|
if m:
|
if m:
|
(current_select if (current_select is not None) else self.tabs[current_tab]).append(ConfigOption(
|
(current_select if (current_select is not None) else self.tabs[current_tab]).append(ConfigOption(
|
line = n,
|
line = n,
|
name = m.group(2),
|
name = m.group(2),
|
title = ((m.group(7) if (m.group(7) is not None) else m.group(2)) if (current_select is not None) else (current_title if len(current_title) > 0 else m.group(2))),
|
title = ((m.group(7) if (m.group(7) is not None) else m.group(2)) if (current_select is not None) else (current_title if len(current_title) > 0 else m.group(2))),
|
valid = current_valid,
|
valid = current_valid,
|
checkbox = (m.group(4) is None),
|
checkbox = (m.group(4) is None),
|
default = (m.group(5) if (m.group(5) is not None) else (m.group(1) is None))
|
default = (m.group(5) if (m.group(5) is not None) else (m.group(1) is None))
|
))
|
))
|
current_title = ""
|
current_title = ""
|
current_valid = ""
|
current_valid = ""
|
continue
|
continue
|
|
|
|
|
self.file.close()
|
self.file.close()
|
|
|
|
|
def save(self):
|
def save(self):
|
|
|
for tab in self.tabs:
|
for tab in self.tabs:
|
for opt in self.tabs[tab]:
|
for opt in self.tabs[tab]:
|
opt.save(self)
|
opt.save(self)
|
|
|
self.file = open(self.filename, "w")
|
self.file = open(self.filename, "w")
|
|
|
for line in self.lines:
|
for line in self.lines:
|
self.file.write(line.rstrip(" \n\r") + "\n")
|
self.file.write(line.rstrip(" \n\r") + "\n")
|
|
|
self.file.close()
|
self.file.close()
|
|
|
|
|
|
|
class ConfigLabel(gtk.Label):
|
class ConfigLabel(gtk.Label):
|
|
|
def __init__(self, text):
|
def __init__(self, text):
|
|
|
gtk.Label.__init__(self, "\n" + text)
|
gtk.Label.__init__(self, "\n" + text)
|
|
self.set_alignment(0, .5)
|
|
self.set_use_markup(True)
|
|
|
|
|
def save(self, *args): pass
|
def save(self, *args): pass
|
|
|
|
|
class ConfigOption(gtk.HBox):
|
class ConfigOption(gtk.HBox):
|
|
|
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
|
|
gtk.HBox.__init__(self, True)
|
gtk.HBox.__init__(self, True)
|
|
|
self.options = kwargs
|
self.options = kwargs
|
|
|
if kwargs['checkbox']:
|
if kwargs['checkbox']:
|
self.entry = gtk.CheckButton()
|
self.entry = gtk.CheckButton()
|
self.entry.set_active(kwargs['default'])
|
self.entry.set_active(kwargs['default'])
|
else:
|
else:
|
self.entry = gtk.Entry()
|
self.entry = gtk.Entry()
|
self.entry.set_text(kwargs['default'])
|
self.entry.set_text(kwargs['default'])
|
|
|
self.pack_start(gtk.Label(kwargs['title']))
|
self.pack_start(gtk.Label(kwargs['title']))
|
self.pack_start(self.entry)
|
self.pack_start(self.entry)
|
|
|
|
|
def save(self, cfgfile, comment = ""):
|
def save(self, cfgfile, comment = ""):
|
|
|
s = ""
|
s = ""
|
|
|
if self.options['checkbox']:
|
if self.options['checkbox']:
|
s += "" if self.entry.get_active() else "//"
|
s += "" if self.entry.get_active() else "//"
|
|
|
s += "`define "
|
s += "`define "
|
s += self.options['name']
|
s += self.options['name']
|
|
|
if not self.options['checkbox']:
|
if not self.options['checkbox']:
|
s += " "
|
s += " "
|
s += self.entry.get_text()
|
s += self.entry.get_text()
|
|
|
if len(comment) > 0:
|
if len(comment) > 0:
|
s += " // " + comment
|
s += " // " + comment
|
|
|
cfgfile.lines[self.options['line']] = s
|
cfgfile.lines[self.options['line']] = s
|
|
|
|
|
|
|
class ConfigOptionSelect(gtk.HBox):
|
class ConfigOptionSelect(gtk.HBox):
|
|
|
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
|
|
gtk.HBox.__init__(self, True)
|
gtk.HBox.__init__(self, True)
|
|
|
self.opts = []
|
self.opts = []
|
self.options = kwargs
|
self.options = kwargs
|
|
|
self.entry = gtk.combo_box_new_text()
|
self.entry = gtk.combo_box_new_text()
|
|
|
self.pack_start(gtk.Label(kwargs['title']))
|
self.pack_start(gtk.Label(kwargs['title']))
|
self.pack_start(self.entry)
|
self.pack_start(self.entry)
|
|
|
self.entry.connect("changed", self.onchanged)
|
self.entry.connect("changed", self.onchanged)
|
|
|
|
|
def append(self, opt):
|
def append(self, opt):
|
|
|
self.opts.append(opt)
|
self.opts.append(opt)
|
self.entry.append_text(opt.options['title'])
|
self.entry.append_text(opt.options['title'])
|
|
|
if opt.options['default']:
|
if opt.options['default']:
|
self.entry.set_active(len(self.opts) - 1)
|
self.entry.set_active(len(self.opts) - 1)
|
|
|
|
|
def onchanged(self, *args):
|
def onchanged(self, *args):
|
|
|
for i, opt in enumerate(self.opts):
|
for i, opt in enumerate(self.opts):
|
opt.entry.set_active(i == self.entry.get_active())
|
opt.entry.set_active(i == self.entry.get_active())
|
|
|
|
|
def save(self, cfgfile):
|
def save(self, cfgfile):
|
|
|
for opt in self.opts:
|
for opt in self.opts:
|
opt.save(cfgfile, opt.options['title'])
|
opt.save(cfgfile, opt.options['title'])
|
|
|
|
|
|
|
class ConfigWindow(gtk.Window):
|
class ConfigWindow(gtk.Window):
|
|
|
def __init__(self, cfgfilename = None):
|
def __init__(self, cfgfilename = None):
|
|
|
INSTANCES.append(self)
|
INSTANCES.append(self)
|
|
|
gtk.Window.__init__(self)
|
gtk.Window.__init__(self)
|
|
|
self.set_title("Configurator")
|
self.set_title("Configurator")
|
self.set_default_size(400, 600)
|
self.set_default_size(400, 600)
|
|
|
self.box = gtk.VBox()
|
self.box = gtk.VBox()
|
self.notebook = gtk.Notebook()
|
self.notebook = gtk.Notebook()
|
self.toolbar = ConfigToolbar(self)
|
self.toolbar = ConfigToolbar(self)
|
|
|
self.add(self.box)
|
self.add(self.box)
|
|
|
self.box.pack_start(self.toolbar, False)
|
self.box.pack_start(self.toolbar, False)
|
self.box.pack_start(self.notebook, True)
|
self.box.pack_start(self.notebook, True)
|
|
|
if cfgfilename is not None:
|
if cfgfilename is not None:
|
self.load(cfgfilename)
|
self.load(cfgfilename)
|
else:
|
else:
|
self.configfile = None
|
self.configfile = None
|
|
|
self.connect("delete_event", self.close)
|
self.connect("delete_event", self.close)
|
self.show_all()
|
self.show_all()
|
|
|
|
|
def load(self, cfgfilename):
|
def load(self, cfgfilename):
|
|
|
cfg = ConfigFile(cfgfilename)
|
cfg = ConfigFile(cfgfilename)
|
|
|
self.set_title(cfg.title + " - Configurator")
|
self.set_title(cfg.title + " - Configurator")
|
|
|
self.configfile = cfg
|
self.configfile = cfg
|
|
|
for tab in cfg.tabs_titles:
|
for tab in cfg.tabs_titles:
|
box = gtk.VBox()
|
box = gtk.VBox()
|
for opt in cfg.tabs[tab]:
|
for opt in cfg.tabs[tab]:
|
box.pack_start(opt, False)
|
box.pack_start(opt, False)
|
box.pack_start(gtk.Label(""), True)
|
box.pack_start(gtk.Label(""), True)
|
sw = gtk.ScrolledWindow()
|
sw = gtk.ScrolledWindow()
|
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
sw.add_with_viewport(box)
|
sw.add_with_viewport(box)
|
self.notebook.append_page(sw, gtk.Label(tab))
|
self.notebook.append_page(sw, gtk.Label(tab))
|
|
|
self.show_all()
|
self.show_all()
|
|
|
|
|
def save(self):
|
def save(self):
|
|
|
self.configfile.save()
|
self.configfile.save()
|
|
|
|
|
def close(self, *args):
|
def close(self, *args):
|
|
|
# Maybe check if file modified and ask to save it?
|
# Maybe check if file modified and ask to save it?
|
|
|
INSTANCES.remove(self)
|
INSTANCES.remove(self)
|
self.destroy();
|
self.destroy();
|
|
|
if len(INSTANCES) == 0:
|
if len(INSTANCES) == 0:
|
gtk.main_quit()
|
gtk.main_quit()
|
|
|
|
|
|
|
class ConfigToolbar(gtk.Toolbar):
|
class ConfigToolbar(gtk.Toolbar):
|
|
|
def __init__(self, cfg):
|
def __init__(self, cfg):
|
|
|
self.cfg = cfg
|
self.cfg = cfg
|
|
|
gtk.Toolbar.__init__(self)
|
gtk.Toolbar.__init__(self)
|
|
|
self.insert_stock(gtk.STOCK_OPEN, "Open a file", None, self.open, None, -1)
|
self.insert_stock(gtk.STOCK_OPEN, "Open a file", None, self.open, None, -1)
|
self.insert_stock(gtk.STOCK_SAVE, "Save the current file", None, self.save, None, -1)
|
self.insert_stock(gtk.STOCK_SAVE, "Save the current file", None, self.save, None, -1)
|
self.insert_stock(gtk.STOCK_CLOSE, "Close the current file", None, self.close, None, -1)
|
self.insert_stock(gtk.STOCK_CLOSE, "Close the current file", None, self.close, None, -1)
|
|
|
|
|
def open(self, *args):
|
def open(self, *args):
|
|
|
chooser = gtk.FileChooserDialog(
|
chooser = gtk.FileChooserDialog(
|
"Open file...", None,
|
"Open file...", None,
|
gtk.FILE_CHOOSER_ACTION_OPEN, (
|
gtk.FILE_CHOOSER_ACTION_OPEN, (
|
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
gtk.STOCK_OPEN, gtk.RESPONSE_OK
|
gtk.STOCK_OPEN, gtk.RESPONSE_OK
|
))
|
))
|
|
|
if chooser.run() != gtk.RESPONSE_OK:
|
if chooser.run() != gtk.RESPONSE_OK:
|
return
|
return
|
|
|
filename = chooser.get_filename()
|
filename = chooser.get_filename()
|
|
|
chooser.destroy()
|
chooser.destroy()
|
|
|
if self.cfg.configfile is None:
|
if self.cfg.configfile is None:
|
self.cfg.load(filename)
|
self.cfg.load(filename)
|
else:
|
else:
|
ConfigWindow(filename)
|
ConfigWindow(filename)
|
|
|
|
|
def save(self, *args):
|
def save(self, *args):
|
self.cfg.save()
|
self.cfg.save()
|
|
|
def close(self, *args):
|
def close(self, *args):
|
self.cfg.close()
|
self.cfg.close()
|
|
|
|
|
if __name__ == '__main__':
|
if __name__ == '__main__':
|
|
|
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
ConfigWindow()
|
ConfigWindow()
|
|
|
for f in sys.argv[1:]:
|
for f in sys.argv[1:]:
|
ConfigWindow(f)
|
ConfigWindow(f)
|
|
|
gtk.main()
|
try: gtk.main()
|
|
except KeyboardInterrupt: pass
|
|
|
|
|