From: arjen Date: Tue, 19 Nov 2002 19:21:18 +0000 (+0000) Subject: Initial revision X-Git-Tag: V0_0_2~4 X-Git-Url: http://www.andromeda.nl/gitweb/?p=gnucomo.git;a=commitdiff_plain;h=65faa6e21c8c0cb768698b9c17c05709c7813773 Initial revision --- diff --git a/src/coconf/README b/src/coconf/README new file mode 100644 index 0000000..3359efb --- /dev/null +++ b/src/coconf/README @@ -0,0 +1,17 @@ +This is a testversion of CoConf, (c) Copyright 2002, Peter Roozemaal. + + GnuCoMo/CoConf is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. See the file COPYING. + +CoConf runs under Python 1.5 and later versions; it requires tkinter and xml +support. Visit www.python.org for more information about Python or to download +Python. + +The author can be contacted as mathfox@xs4all.nl. + +Known problems: + RedHat 7.3 + Python 2.2 (python2) + SystemError: Py_UNICODE and Tcl_UniChar differ in size + Workaround: use Python 1.5 (python) diff --git a/src/coconf/TODO b/src/coconf/TODO new file mode 100644 index 0000000..bd07da4 --- /dev/null +++ b/src/coconf/TODO @@ -0,0 +1,5 @@ +TODO: + implement types and + make a parser for expression evaluation + implement valid and enabled tags + check and improve documentation diff --git a/src/coconf/coconf b/src/coconf/coconf new file mode 100755 index 0000000..51b25b5 --- /dev/null +++ b/src/coconf/coconf @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +# $Id: coconf,v 1.1 2002-11-19 19:21:18 arjen Exp $ + +if [ -f coconf.pyw ] +then + COCONFDIR=`pwd` +elif [ -d /usr/local/share/coconf ] +then + COCONFDIR=/usr/local/share/coconf +elif [ -d /opt/coconf ] +then + COCONFDIR=/opt/coconf +elif [ -d /usr/share/coconf ] +then + COCONFDIR=/usr/share/coconf +else + COCONFDIR=`pwd` +fi + +export COCONFDIR + +python -OO ${COCONFDIR}/coconf.pyw "$@" diff --git a/src/coconf/coconf.pyw b/src/coconf/coconf.pyw new file mode 100644 index 0000000..adb3c9d --- /dev/null +++ b/src/coconf/coconf.pyw @@ -0,0 +1,19 @@ +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +import sys +import cotk +from textbase import txt + +_id = "$Id: coconf.pyw,v 1.1 2002-11-19 19:21:18 arjen Exp $" + +if len(sys.argv) > 2: + print stderr, txt("usage", "usage: coconf []") +main = cotk.Main() +if len(sys.argv) == 2: + main.load(sys.argv[1]) +main.mainloop() diff --git a/src/coconf/cotest1.ccf b/src/coconf/cotest1.ccf new file mode 100644 index 0000000..86f619a --- /dev/null +++ b/src/coconf/cotest1.ccf @@ -0,0 +1,28 @@ + +
+ + + This is form level help text in english. + + + Dit is nederlandstalige hulp voor het formulier. + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Try this one too! + + + Probeer deze ook eens! + + + diff --git a/src/coconf/cotest2.ccf b/src/coconf/cotest2.ccf new file mode 100644 index 0000000..9e79a3d --- /dev/null +++ b/src/coconf/cotest2.ccf @@ -0,0 +1,28 @@ + +
+ + + This is form level help text in english. + + + Dit is nederlandstalige hulp voor het formulier. + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Please enter some random text. + + + Tik maar wat. + + + diff --git a/src/coconf/cotest3.ccf b/src/coconf/cotest3.ccf new file mode 100644 index 0000000..f05e87c --- /dev/null +++ b/src/coconf/cotest3.ccf @@ -0,0 +1,68 @@ + +
+ + + This is form level help text in english. + + + Dit is nederlandstalige hulp voor het formulier. + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Please enter some random text. + + + Tik maar wat. + + + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Try this one too! + + + Probeer deze ook eens! + + + + + + + + Please enter some random text. + + + Tik maar wat. + + + diff --git a/src/coconf/cotest4.ccf b/src/coconf/cotest4.ccf new file mode 100644 index 0000000..a3901d2 --- /dev/null +++ b/src/coconf/cotest4.ccf @@ -0,0 +1,75 @@ + +
+ + + This is form level help text in english. + + + Dit is nederlandstalige hulp voor het formulier. + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Please enter some random text. + + + Tik maar wat. + + + + + + + + + Just try to toggle it! + + + Druk eens op de schakelaar! + + + + + + Try this one too! + + + Probeer deze ook eens! + + + + + + + + + + + Please enter some random text. + + + Tik maar wat. + + + diff --git a/src/coconf/cotk.py b/src/coconf/cotk.py new file mode 100644 index 0000000..425f379 --- /dev/null +++ b/src/coconf/cotk.py @@ -0,0 +1,232 @@ +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +# TODO: error handling + +import string +import Tkinter +import tkFileDialog +import tkMessageBox +import coxmlfile +import cotkwidget +import textbase +import tkFont +from textbase import txt + +_id = "$Id: cotk.py,v 1.1 2002-11-19 19:21:18 arjen Exp $" + +version = "0.0.1 $Date: 2002-11-19 19:21:18 $" + +copy = "Copyright (C) 2002, Peter Roozemaal" + +licence = txt("lice", "CoConf is free software; you may distribute it under the terms of the GNU General Public License") + +ids = ( "CoConf Version "+version, "", copy, licence, "", + _id, cotkwidget._id, coxmlfile._id, textbase._id ) + +def is_a_form(dom): + return dom.documentElement.tagName == "form" + +# toplevel window +class Main(Tkinter.Frame): + # TODO: translation + filetypes_forms = ( + ( "Cocola forms", ".ccf" ), + ( "All files", ".*" ) + ) + filetypes_load = ( + ( "Coconf files", ".ccs" ), + ( "Coconf files", ".ccx" ), + ( "Coconf files", ".gcm" ), + ( "Coconf save files", ".ccs" ), + ( "Coconf export files", ".ccx" ), + ( "Gnucomo configuration files", ".gcm" ), + ( "All files", ".*" ) + ) + filetypes_save = ( + ( "Coconf save files", ".ccs" ), + ( "All files", ".*" ) + ) + filetypes_exp = ( + ( "Coconf export files", ".ccx" ), + ( "Gnucomo configuration files", ".gcm" ), + ( "All files", ".*" ) + ) + def __init__(self, master=None): + Tkinter.Frame.__init__(self, master) + # The following command is important for security; it disables + # remote control and spying via the send command. + try: + self.tk.call(("rename", "send", "")) + except Tkinter.TclError: + pass + self.pack(expand=1, fill="both") + self.master.title(txt("ctitle", "Coconf configuration editor")) + self.menubar = MenuBar(self) + self.menubar.pack(side="top", fill="x") + self.status = StatusBar(self) + self.status.pack(side="bottom", fill="x") + self.main = MainFrame(self) + self.main.pack(side="top", fill="both", expand=1) + self.filename = "" + self.formname = "" + def load(self, file): + dom = coxmlfile.load_from_file(file) + if is_a_form(dom): + self.main.new_form(dom) + self.status.set_formname(file) + self.formname = file + self.menubar.helpmenu.entryconfigure(2, state="normal") + # TODO: process datafiles + dom.unlink() + def save(self, file, export): + document = coxmlfile.Document() + self.main.value_dom(document, export) + if not export: + document.documentElement.setAttribute("formfile", self.formname) + f = open(file, "w") + document.writexml(f) + f.close() + document.unlink() + def load_form(self): + filename = tkFileDialog.askopenfilename(filetypes=self.filetypes_forms) + if filename: + self.load(filename) + def load_file(self): + filename = tkFileDialog.askopenfilename(filetypes=self.filetypes_load) + if filename: + self.load(filename) + def save_file(self): + if self.filename: + self.save(self.filename, 0) + else: + self.save_as() + def save_copy(self): + filename = tkFileDialog.asksaveasfilename(filetypes=self.filetypes_save, + defaultextension=".ccs") + if filename: + self.save(filename, 0) + def save_as(self): + filename = tkFileDialog.asksaveasfilename(filetypes=self.filetypes_save, + defaultextension=".ccs") + if filename: + self.save(filename, 0) + self.filename = filename + def export(self): + filename = tkFileDialog.asksaveasfilename(filetypes=self.filetypes_exp, + defaultextension=".ccx") + if filename: + self.save(filename, 1) + def formhelp(self): + self.main.form.provide_help() + def about(self): + cotkwidget.HelpWin("About CoConf", string.join(ids, '\n')) + def help(self): + tkMessageBox.showerror(title=txt("sorry", "Sorry"), + message=txt("findhelp", "Can't find helpfile.")) + +# menu bar +class MenuBar(Tkinter.Frame): + def __init__(self, master): + Tkinter.Frame.__init__(self, master, relief="raised", borderwidth=2) + + self.file = Tkinter.Menubutton(self, text=txt("mfile", "File")) + self.file.pack(side="left") + self.filemenu = Tkinter.Menu(self.file) + self.filemenu.add_command(label=txt("mform", "Form..."), + command=master.load_form) + self.filemenu.add_command(label=txt("mopen", "Open..."), + command=master.load_file) + self.filemenu.add_command(label=txt("msave", "Save"), + command=master.save_file) + self.filemenu.add_command(label=txt("msaveas", "Save as..."), + command=master.save_as) + self.filemenu.add_command(label=txt("msavecopy", "Save copy..."), + command=master.save_as) + self.filemenu.add_command(label=txt("mexport", "Export..."), + command=master.export) + self.filemenu.add_command(label=txt("mquit", "Quit"), + command=master.quit) + self.file["menu"] = self.filemenu + + self.set = Tkinter.Menubutton(self, text=txt("mset", "Settings"), + state="disabled") + self.set.pack(side="left") + + self.help = Tkinter.Menubutton(self, text=txt("mhelp", "Help")) + self.help.pack(side="right") + self.helpmenu = Tkinter.Menu(self.help) + self.helpmenu.add_command(label=txt("mwork", "Working..."), + command=master.help) + self.helpmenu.add_command(label=txt("mform", "Form..."), + state="disabled", command=master.formhelp) + self.helpmenu.add_separator() + self.helpmenu.add_command(label=txt("mabout", "About..."), + command=master.about) + self.help["menu"] = self.helpmenu + +# main form window with scrollbars +class MainFrame(Tkinter.Frame): + def __init__(self, master): + Tkinter.Frame.__init__(self, master) + self.canvas = Tkinter.Canvas(self, scrollregion=(0, 0, 200, 200)) + self.canvas.grid(row=0, column=0, sticky="news") + self.scrollY = Tkinter.Scrollbar(self, orient=Tkinter.VERTICAL, + command=self.canvas.yview) + self.scrollY.grid(row=0, column=1, sticky="ns") + self.canvas["yscrollcommand"] = self.scrollY.set + self.scrollX = Tkinter.Scrollbar(self, orient=Tkinter.HORIZONTAL, + command=self.canvas.xview) + self.scrollX.grid(row=1, column=0, sticky="ew") + self.canvas["xscrollcommand"] = self.scrollX.set + self.grid_columnconfigure(0, weight=1, minsize=0) + self.grid_rowconfigure(0, weight=1, minsize=0) + self.formid = None + self.form = None + def new_form(self, dom): + if self.formid != None: + self.canvas.delete(self.formid) + if self.form != None: + self.form.cleanup() + self.form = cotkwidget.FormWin(self.canvas, dom.documentElement) + self.formid = self.canvas.create_window(0, 0, window=self.form, + anchor="nw") + self.canvas.update(); + self.canvas["scrollregion"] = self.canvas.bbox("all") + def value_dom(self, dom, flags): + self.form.value_dom(dom, dom, flags) + +# the status bar +class StatusBar(Tkinter.Frame): + def __init__(self, master): + Tkinter.Frame.__init__(self, master, relief="raised", borderwidth=2) + self.lform = Tkinter.Label(self, text=txt("noform", ""), + relief="sunken", borderwidth=2) + self.lform.pack(side="left") + self.lfile = Tkinter.Label(self, text=txt("nofile", ""), + relief="sunken", borderwidth=2) + self.lfile.pack(side="left") + self.modinc = Tkinter.Label(self, text=" ", relief="sunken", + borderwidth=2) + self.modinc.pack(side="left") + self.filler = Tkinter.Label(self, relief="sunken", borderwidth=2) + self.filler.pack(side="right", fill="x", expand=1) + def set_filename(self, name): + if name: + self.lfile["text"] = name + else: + self.lfile["text"] = txt("nofile", "") + def set_formname(self, name): + if name: + self.lform["text"] = name + else: + self.lform["text"] = txt("noform", "") + def set_modified(self, mod): + if mod: + self.modinc["text"] = "*" + else: + self.modinc["text"] = " " diff --git a/src/coconf/cotkwidget.py b/src/coconf/cotkwidget.py new file mode 100644 index 0000000..21dc381 --- /dev/null +++ b/src/coconf/cotkwidget.py @@ -0,0 +1,222 @@ +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +"The widget definitions that build a form" + +import string +import os +import Tkinter +import tkMessageBox +import ScrolledText +from textbase import txt + +_id = "$Id: cotkwidget.py,v 1.1 2002-11-19 19:21:18 arjen Exp $" + +_helpwins = {} + +class HelpWin(Tkinter.Toplevel): + def __init__(self, item, text): + global _helpwins + Tkinter.Toplevel.__init__(self) + self.title(txt("helpon","help on")+" "+item) + _helpwins[item] = self + self.name = item + self.bind("", self.cleanup) + self.textwin = ScrolledText.ScrolledText(self, takefocus=0, wrap="word") + self.textwin.pack(side="top") + self.textwin.insert("1.0", text) + self.textwin["state"] = "disabled" + self.button = Tkinter.Button(self, text=txt("thanks", "Thank You"), + relief="groove", borderwidth=4, + command=self.destroy) + self.button.pack(side="bottom") + def cleanup(self, event): + if _helpwins.has_key(self.name): + del _helpwins[self.name] + +class _BaseWidget: + widgetname = "" + curhelp = "" + defhelp = "" + help = {} + + def cleanup(self): + self.destroy() + + def readDom(self, dom): + self.widgetname = dom.getAttribute("name") + for i in self.translate: + att = dom.getAttribute(i) + setattr(self, "cur"+i, att) + setattr(self, "def"+i, att) + setattr(self, i, {}) + getattr(self, i)[dom.getAttribute("language")] = att + el = dom.firstChild + while el != None: + if el.nodeType == el.ELEMENT_NODE: + if el.tagName == "help": + self.readHelp(el) + elif el.tagName == "translate": + self.readTrans(el) + else: + print self.widgetname, "bad element:", el.tagName + #else: + #print self.widgetname, "bad xml node:", el.nodeName + el = el.nextSibling + + def readHelp(self, dom): + lang = dom.getAttribute("language") + text = "" + el = dom.firstChild + while el != None: + if el.nodeType == el.TEXT_NODE: + text = text + el.data + el = el.nextSibling + text = string.join(string.split(text)) + if self.curhelp == "": + self.curhelp = text + if self.defhelp == "": + self.defhelp = text + self.help[lang] = text + + def readTrans(self, dom): + pass + + def provide_help(self): + if _helpwins.has_key(self.widgetname): + _helpwins[self.widgetname].lift() + elif self.curhelp: + HelpWin(self.widgetname, self.curhelp) + else: + tkMessageBox.showinfo(title=txt("sorry", "Sorry"), + message=txt("nohelp", "The creator of the form didn't provide a help message.")) + + def value_dom(self, document, parent, flags): + #TODO: check flags + node = document.createElement("variable") + node.setAttribute("name", self.widgetname) + #the next line isn't OO clean + node.setAttribute("value", str(self.variable.get())) + parent.appendChild(node) + +class _ComposedWidget(_BaseWidget): + def readDom(self, dom): + self.widgetname = dom.getAttribute("name") + for i in self.translate: + att = dom.getAttribute(i) + setattr(self, "cur"+i, att) + setattr(self, "def"+i, att) + setattr(self, i, {}) + getattr(self, i)[dom.getAttribute("language")] = att + el = dom.firstChild + while el != None: + if el.nodeType == el.ELEMENT_NODE: + if el.tagName == "help": + self.readHelp(el) + elif el.tagName == "translate": + self.readTrans(el) + elif _subwidgets.has_key(el.tagName): + w = _subwidgets[el.tagName](self, el) + self.add_widget(w) + else: + print self.widgetname, "bad element:", el.tagName + #else: + #print self.widgetname, "bad xml node:", el.nodeName + el = el.nextSibling + +class FormWin(Tkinter.Frame, _ComposedWidget): + translate = ( "title", ) + def __init__(self, master, dom): + Tkinter.Frame.__init__(self, master) + self.wlist = [] + self.readDom(dom) + def cleanup(self): + for sub in self.wlist: + sub.cleanup() + self.destroy() + def add_widget(self, wid): + self.wlist.append(wid) + wid.pack(side="top", fill="x") + def value_dom(self, document, parent, flags): + if flags: + node = document.createElement("export") + else: + node = document.createElement("save") + node.setAttribute("form", self.widgetname) + parent.appendChild(node) + for sub in self.wlist: + sub.value_dom(document, node, flags) + +class Group(Tkinter.Frame, _ComposedWidget): + translate = () + def __init__(self, master, dom): + Tkinter.Frame.__init__(self, master) + self.wlist = [] + self.filler = Tkinter.Frame(self, width="7m") + self.filler.pack(side="left", fill="y") + self.inner = Tkinter.Frame(self) + self.inner.pack(side="right", fill="both", expand=1) + self.readDom(dom) + def cleanup(self): + for sub in self.wlist: + sub.cleanup() + self.destroy() + def add_widget(self, wid): + self.wlist.append(wid) + wid.pack(side="top", fill="x", in_=self.inner) + def value_dom(self, document, parent, flags): + #TODO: check flags + node = document.createElement("group") + node.setAttribute("name", self.widgetname) + parent.appendChild(node) + for sub in self.wlist: + sub.value_dom(document, node, flags) + +class Boolean(Tkinter.Frame, _BaseWidget): + translate = ( "label", ) + def __init__(self, master, dom): + Tkinter.Frame.__init__(self, master) + self.readDom(dom) + self.button = Tkinter.Checkbutton(self, text=self.curlabel) + self.button.pack(side="left") + self.variable = Tkinter.BooleanVar() + self.button["variable"] = self.variable + if os.name == "posix": + self.button["selectcolor"] = "green" + self.helpbutton = Tkinter.Button(self, text=txt("lhelp", "?"), + command=self.provide_help) + self.helpbutton.pack(side="right") + +class String(Tkinter.Frame, _BaseWidget): + translate = ( "label", ) + def __init__(self, master, dom): + Tkinter.Frame.__init__(self, master) + self.readDom(dom) + self.label = Tkinter.Label(self, text=self.curlabel) + self.label.pack(side="left") + self.variable = Tkinter.StringVar() + self.veld = Tkinter.Entry(self, textvariable=self.variable) + self.helpbutton = Tkinter.Button(self, text=txt("lhelp", "?"), + command=self.provide_help) + self.helpbutton.pack(side="right") + self.veld.pack(side="right", fill="x") + +class Ruler(Tkinter.Frame): + def __init__(self, master, dom): + Tkinter.Frame.__init__(self, master, relief="sunken", height=4, + borderwidth=2) + def value_dom(self, document, parent, flags): + pass + def cleanup(self): + self.destroy() + +_subwidgets = { + "boolean" : Boolean, + "group" : Group, + "ruler" : Ruler, + "string" : String +} diff --git a/src/coconf/coxmlfile.py b/src/coconf/coxmlfile.py new file mode 100644 index 0000000..f3a0366 --- /dev/null +++ b/src/coconf/coxmlfile.py @@ -0,0 +1,42 @@ +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +import string +from xml.dom.minidom import parse, Document + +_id = "$Id: coxmlfile.py,v 1.1 2002-11-19 19:21:18 arjen Exp $" + +def emptytext(node): + return node.nodeType == node.TEXT_NODE and string.strip(node.data) == "" + +# NOTE: the normalise function doesn't work under python 2.0. +def normalise(xmlnode): + "We strip blanks-only text nodes" + child = xmlnode.firstChild + while child != None: + if emptytext(child): + remove = child + child = child.nextSibling + xmlnode.removeChild(remove) + remove.unlink() + else: + if child.hasChildNodes(): + normalise(child) + child = child.nextSibling + return xmlnode; + +def load_from_file(filename): + file = open(filename, "r") + dom = parse(file) + file.close() +# return normalise(dom) + return dom + +def save_to_file(dom, filename): + file = open(filename, "w") + dom.writexml(file) + file.close() diff --git a/src/coconf/textbase.py b/src/coconf/textbase.py new file mode 100644 index 0000000..82909b0 --- /dev/null +++ b/src/coconf/textbase.py @@ -0,0 +1,22 @@ +# Copyright (C) 2002, Peter Roozemaal. +# +# GnuCoMo/CoConf is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. See the file COPYING. + +"""The textbase module implements the internationalisation interface for the + coconf application. + +Exported functions: + txt(tag, default) - localise a string + TODO! +""" + +_id = "$Id: textbase.py,v 1.1 2002-11-19 19:21:18 arjen Exp $" + +def txt(tag, default): + """Returns the localised string for tag; + default if no string can be found in localisation database""" + #TODO! + return default