refactoring in progress

Mon, 04 Feb 2008 19:49:48 +0100

author
David Douard <david.douard@logilab.fr>
date
Mon, 04 Feb 2008 19:49:48 +0100
changeset 39
8becd52c2171
parent 38
73bd2fe81005
child 40
1bbea188a7e5

refactoring in progress

HP3562A/__init__.py file | annotate | diff | comparison | revisions
HP3562A/q3562A.py file | annotate | diff | comparison | revisions
HP3562A/q3562A.ui file | annotate | diff | comparison | revisions
bin/read_coord file | annotate | diff | comparison | revisions
bin/read_state file | annotate | diff | comparison | revisions
bin/read_trace file | annotate | diff | comparison | revisions
plotter/hpgl_plotter.qrc file | annotate | diff | comparison | revisions
plotter/icons/led_green.svg file | annotate | diff | comparison | revisions
plotter/icons/led_green_off.svg file | annotate | diff | comparison | revisions
plotter/icons/led_red.svg file | annotate | diff | comparison | revisions
plotter/icons/led_red_off.svg file | annotate | diff | comparison | revisions
plotter/qpreferences.py file | annotate | diff | comparison | revisions
plotter/qpreferences_dialog.ui file | annotate | diff | comparison | revisions
qt4/icons/led_green.svg file | annotate | diff | comparison | revisions
qt4/icons/led_green_off.svg file | annotate | diff | comparison | revisions
qt4/icons/led_red.svg file | annotate | diff | comparison | revisions
qt4/icons/led_red_off.svg file | annotate | diff | comparison | revisions
qt4/qpreferences.py file | annotate | diff | comparison | revisions
qt4/qpreferences_dialog.ui file | annotate | diff | comparison | revisions
qt4/resources.qrc file | annotate | diff | comparison | revisions
--- a/HP3562A/__init__.py	Mon Feb 04 19:19:57 2008 +0100
+++ b/HP3562A/__init__.py	Mon Feb 04 19:49:48 2008 +0100
@@ -14,7 +14,7 @@
 """
 import struct
 import re
-import gpib
+import pygpib as gpib
 import numpy
 
 ########################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HP3562A/q3562A.py	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,346 @@
+#
+
+import os, sys
+import time
+import glob
+
+from PyQt4 import QtGui, QtCore, uic
+from PyQt4.QtCore import SIGNAL, Qt
+
+if "-m" in sys.argv:
+    from dump_datablock_mockup import HP3562dumper
+else:
+    from dump_datablock import HP3562dumper
+import q3562A_rc
+
+ldir = os.path.abspath(os.path.dirname(__file__))
+sys.path.append(ldir)
+form_class, base_class = uic.loadUiType(os.path.join(ldir, "q3562A.ui"))
+
+from qpreferences import BaseItem, IntItem, UnicodeItem, ColorItem
+from qpreferences import PointItem, SizeItem, ByteArrayItem
+from qpreferences import AbstractPreferences
+from qpreferenceseditor import PreferencesEditor
+
+from tools import str_num_cmp
+
+class Preferences(AbstractPreferences):
+    ORGANISATION="Logilab"
+    APPLICATION="qgpib_plotter"
+
+    _pos = PointItem()
+    _size = SizeItem()
+    _appState = ByteArrayItem()
+
+    device = UnicodeItem(default='/dev/ttyUSB0',
+                         name=u'device',
+                         description=u'GPIB device',
+                         group="GPIB settings")
+    address = IntItem(default=5, min=0, max=16,
+                      name=u'GPIB address',
+                      group="GPIB settings")
+    
+    background = ColorItem(default=QtGui.QColor("white"),
+                           name="Background",
+                           group="Colors")
+    color0 = ColorItem(default=QtGui.QColor("black"),
+                       name="Pen #0",
+                       group="Colors")
+    color1 = ColorItem(default=QtGui.QColor("green"),
+                       name="Pen #1",
+                       group="Colors")
+    color2 = ColorItem(default=QtGui.QColor("red"),
+                       name="Pen #2",
+                       group="Colors")
+    color3 = ColorItem(default=QtGui.QColor("blue"),
+                       name="Pen #3",
+                       group="Colors")
+    color4 = ColorItem(default=QtGui.QColor("yellow"),
+                       name="Pen #4",
+                       group="Colors")
+    color5 = ColorItem(default=QtGui.QColor("cyan"),
+                       name="Pen #5",
+                       group="Colors")
+    color6 = ColorItem(default=QtGui.QColor("magenta"),
+                       name="Pen #6",
+                       group="Colors")
+    color7 = ColorItem(default=QtGui.QColor("darkred"),
+                       name="Pen #7",
+                       group="Colors")
+    
+class QtHPGLPlotter(QtGui.QMainWindow, form_class):
+    def __init__(self, parent=None):
+        QtGui.QMainWindow.__init__(self, parent)
+        self._plots = {}        
+        self._prefs = Preferences()
+        self.setupUi()
+        self.initializeGPIB()
+        if self._prefs._pos:
+            self.move(self._prefs._pos)
+        if self._prefs._size:
+            self.resize(self._prefs._size)
+        if self._prefs._appState:
+            self.restoreState(self._prefs._appState)
+        self.readPreferences()
+
+    def readPreferences(self):
+        bg = self._prefs.background
+        if bg and bg.isValid():
+            self.plotterWidget.qview.setBackgroundBrush(QtGui.QBrush(bg))
+        pen_colors = [self._prefs["color%d"%i] for i in range(8)]
+        self.plotterWidget.pen_colors = pen_colors
+        
+    def replotCurrent(self):
+        self.currentPlotChanged(self.plotsView.currentIndex())
+        
+    def setupUi(self):
+        form_class.setupUi(self, self) # call qtdesigner generated form creation        
+        # actions defined in designer
+        self.connect(self.actionPreferences, SIGNAL('triggered(bool)'),
+                     self.preferencesTriggered)
+        self.connect(self.actionQuit, SIGNAL('triggered(bool)'),
+                     self.quitTriggered)
+        self.actionQuit.setShortcut(QtGui.QKeySequence(u'Ctrl+Q'))
+        self.connect(self.actionOpen, SIGNAL('triggered(bool)'),
+                     self.openTriggered)
+        self.actionOpen.setShortcut(QtGui.QKeySequence(u'Ctrl+O'))
+        self.connect(self.actionSave, SIGNAL('triggered(bool)'),
+                     self.saveTriggered)
+        self.actionSave.setShortcut(QtGui.QKeySequence(u'Ctrl+S'))
+        self.connect(self.actionSaveAs, SIGNAL('triggered(bool)'),
+                     self.saveAsTriggered)
+
+        self.plotterWidget = QHPGLPlotterWidget(self)
+        self.setCentralWidget(self.plotterWidget)
+
+        self.connect(self.captureButton, SIGNAL("toggled(bool)"),
+                     self.captureToggled)
+
+        self._plots_list = QtGui.QStringListModel()
+        self.plotsView.setModel(self._plots_list)
+        self.connect(self.plotsView, SIGNAL('activated(const QModelIndex&)'),
+                     self.currentPlotChanged)
+        self.connect(self.plotsView.selectionModel(),
+                     SIGNAL('currentChanged(const QModelIndex&, const QModelIndex&)'),
+                     self.currentPlotChanged)
+
+    def currentPlotChanged(self, index, old_index=None):
+        if index.isValid():
+            value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
+            
+            self.plotterWidget.clear()
+            self.plotterWidget.parse(self._plots[value])
+            
+    def preferencesTriggered(self, checked=False):
+        PreferencesEditor(self._prefs, self).exec_()
+        self.readPreferences()
+        self.replotCurrent()
+
+    def quitTriggered(self, checked=False):
+        self.close()
+
+    def closeEvent(self, event):
+        if 1:
+        #if self.promptForSave():
+            self._prefs._pos = self.pos()
+            self._prefs._size = self.size()
+            self._prefs._appState = self.saveState()
+            event.accept()
+        else:
+            event.ignore()
+        
+    def openTriggered(self, checked=False):
+        filenames = QtGui.QFileDialog.getOpenFileNames(self, "Open a HPGL file to display", '.', 'HPGL files (*.plt)\nAll files (*)')
+        self.openFiles(filenames)
+        self.displayFirst()
+        
+    def displayFirst(self):
+        if not self.plotsView.currentIndex().isValid():
+            self.plotsView.setCurrentIndex(self.plotsView.model().index(0, 0))
+        
+    def openFiles(self, filenames):
+        ok = False
+        for filename in filenames:
+            filename = str(filename)
+            if os.path.exists(filename):
+                data = open(filename).read()
+                name = os.path.basename(filename)
+                name = os.path.splitext(name)[0]
+                lst = self.plotsView.model().stringList()
+                lst.append(name)            
+                self._plots[name] = data
+                self.plotsView.model().setStringList(lst)
+                ok = True
+        return ok
+        
+    def plotReceived(self, num):
+        self._receiving = False
+        self.setReceivingLed()
+        plot, timestamp = self.captureThread.getPlot(num)
+        name = "plot_%s"%(num)
+        lst = self.plotsView.model().stringList()
+        lst.append(name)            
+        self._plots[name] = plot
+        self.plotsView.model().setStringList(lst)
+
+    def plotStarted(self):
+        self._receiving = True
+        self.setReceivingLed()
+        
+    def saveTriggered(self, checked=False):
+        print "save"
+        
+    def saveAsTriggered(self, checked=False):
+        index = self.plotsView.selectionModel().currentIndex()
+        if index.isValid():
+            filename = QtGui.QFileDialog.getSaveFileName(self, "Selecte a file name to save HPGL file", '.', 'HPGL files (*.plt)\nAll files (*)')
+            n = index.row()
+            value = unicode(self.plotsView.model().data(index, Qt.DisplayRole).toString())
+            open(filename, 'w').write(self._plots[value])
+            
+        
+    def initializeGPIB(self):
+        self._online = False
+        try:
+            self.gpib_plotter = QGPIBplotter(device=self._prefs.device,
+                                            address=self._prefs.address,
+                                            )
+            self.captureThread = GPIBReceiver(self.gpib_plotter)
+            self.connect(self.captureThread, SIGNAL('plotReceived(int)'),
+                         self.plotReceived)
+            self.connect(self.captureThread, SIGNAL('plotStarted()'),
+                         self.plotStarted)
+            self.captureThread.start()
+        except Exception, e:
+            #print e
+            self.gpib_plotter = None
+        self.setCaptureLed()
+
+    def captureToggled(self, state):
+        if state:
+            if self.gpib_plotter is None:
+                self.initializeGPIB()
+                if self.gpib_plotter is None:
+                    QtGui.QMessageBox.critical(self, self.tr("GPIB error"),
+                                               self.tr("<b>Unable to initialize GPIB connection</b>.<br>Please check your GPIB dongle and settings."))
+                    self._online = False
+                    self.setCaptureLed()
+                    return
+            self._online = True
+            self.captureThread.startCapture()
+        else:
+            if self.captureThread:
+                self.captureThread.stopCapture()
+            self._online = False
+        self.setCaptureLed()
+        
+    def setCaptureLed(self):
+        if self._online:
+            icn = QtGui.QIcon(':/icons/led_green.svg')
+        else:
+            icn = QtGui.QIcon(':/icons/led_green_off.svg')
+        self.captureButton.setIcon(icn)
+        self.captureButton.setChecked(self._online)
+
+    def setReceivingLed(self):
+        if self._receiving:
+            icn = QtGui.QIcon(':/icons/led_red.svg')
+        else:
+            icn = QtGui.QIcon(':/icons/led_red_off.svg')
+        self.receivingButton.setIcon(icn)
+
+class QGPIBplotter(GPIBplotter):
+    def __init__(self, device="/dev/ttyUSB0", baudrate=115200, timeout=0.1,
+                 address=5):
+        GPIBplotter.__init__(self, device, baudrate, timeout, address)        
+        self.emitter = None
+
+    def plotStarted(self):
+        if self.emitter:
+            self.emitter.emit(SIGNAL('plotStarted()'))
+            #self.emitter.msleep(1)
+        
+class GPIBReceiver(QtCore.QThread):
+    def __init__(self, cnx):
+        QtCore.QThread.__init__(self)
+        self.gpibplotter = cnx
+        self.gpibplotter.emitter = self
+        
+        self._cancelmutex = QtCore.QMutex()
+        self._cancel = False
+        #self._nreceived = 0
+        self._plotsmutex = QtCore.QMutex()
+        self._plots = []
+        self._startstopmutex = QtCore.QMutex()
+        self._startstop = QtCore.QWaitCondition()
+        self._capturing = False
+        
+    def cancel(self):
+        self._cancelmutex.lock()
+        self._cancel = True
+        self._cancelmutex.unlock()
+
+    def startCapture(self):
+        self._startstop.wakeOne()
+
+    def stopCapture(self):
+        self._startstopmutex.lock()
+        self._capturing = False
+        self._startstopmutex.unlock()
+
+    def run(self):
+        while 1:
+            self._cancelmutex.lock()
+            if self._cancel:
+                return
+            self._cancelmutex.unlock()
+            self._startstopmutex.lock()
+            if not self._capturing:
+                self._startstop.wait(self._startstopmutex)
+                self._capturing = True
+            self._startstopmutex.unlock()
+        
+            plot = self.gpibplotter.load_plot(wait_timeout=0.1)
+            timestamp = time.time()
+            if plot:
+                self._plotsmutex.lock()
+                self._plots.append((plot, timestamp))
+                n = len(self._plots)
+                self._plotsmutex.unlock()
+                self.emit(SIGNAL('plotReceived(int)'), n-1)
+            self.msleep(10)
+            
+    def getPlot(self, num):
+        self._plotsmutex.lock()
+        try:
+            return self._plots[num]
+        finally:
+            self._plotsmutex.unlock()
+
+def main():
+    import optparse
+    opt = optparse.OptionParser('A simple PyQt4 HP7470A GPIB plotter emulator for USB-GPIB bundle (ProLogix)')
+    opt.add_option('-m', '--mockup', default=False,
+                   action="store_true",
+                   dest='mockup',
+                   help='Use a pseudo GPIB connection (for test purpose)',
+                   )
+    opt.add_option('-v', '--verbose', default=False,
+                   action="store_true",
+                   dest="verbose",
+                   help="Verbose mode",)
+    
+    options, argv = opt.parse_args(sys.argv)
+
+    a = QtGui.QApplication(argv)
+    w = QtHPGLPlotter()
+    files = [f for f in argv[1:] if os.path.isfile(f)]
+    files.sort(cmp=str_num_cmp)
+    if w.openFiles(files):    
+        w.displayFirst()
+
+    w.show()
+    a.exec_()
+        
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HP3562A/q3562A.ui	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,179 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>507</width>
+    <height>492</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget" />
+  <widget class="QMenuBar" name="menubar" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>507</width>
+     <height>25</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menu_File" >
+    <property name="title" >
+     <string>&amp;File</string>
+    </property>
+    <addaction name="actionOpen" />
+    <addaction name="actionSave" />
+    <addaction name="actionSaveAs" />
+    <addaction name="separator" />
+    <addaction name="actionQuit" />
+   </widget>
+   <widget class="QMenu" name="menuEdit" >
+    <property name="title" >
+     <string>Edit</string>
+    </property>
+    <addaction name="actionPreferences" />
+   </widget>
+   <addaction name="menu_File" />
+   <addaction name="menuEdit" />
+  </widget>
+  <widget class="QStatusBar" name="statusbar" />
+  <widget class="QDockWidget" name="plotsDock" >
+   <attribute name="dockWidgetArea" >
+    <number>1</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents" >
+    <layout class="QVBoxLayout" >
+     <property name="spacing" >
+      <number>4</number>
+     </property>
+     <property name="leftMargin" >
+      <number>1</number>
+     </property>
+     <property name="topMargin" >
+      <number>4</number>
+     </property>
+     <property name="rightMargin" >
+      <number>1</number>
+     </property>
+     <property name="bottomMargin" >
+      <number>1</number>
+     </property>
+     <item>
+      <layout class="QHBoxLayout" >
+       <item>
+        <widget class="QToolButton" name="getTraceButton" >
+         <property name="minimumSize" >
+          <size>
+           <width>0</width>
+           <height>29</height>
+          </size>
+         </property>
+         <property name="text" >
+          <string>get trace</string>
+         </property>
+         <property name="icon" >
+          <iconset/>
+         </property>
+         <property name="iconSize" >
+          <size>
+           <width>16</width>
+           <height>16</height>
+          </size>
+         </property>
+         <property name="checkable" >
+          <bool>true</bool>
+         </property>
+         <property name="toolButtonStyle" >
+          <enum>Qt::ToolButtonTextBesideIcon</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="getStatusButton" >
+         <property name="minimumSize" >
+          <size>
+           <width>0</width>
+           <height>29</height>
+          </size>
+         </property>
+         <property name="text" >
+          <string>get status</string>
+         </property>
+         <property name="checkable" >
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="getCoordButton" >
+         <property name="minimumSize" >
+          <size>
+           <width>0</width>
+           <height>29</height>
+          </size>
+         </property>
+         <property name="text" >
+          <string>get coord</string>
+         </property>
+         <property name="checkable" >
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer>
+         <property name="orientation" >
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" >
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QListView" name="objectsView" />
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <action name="actionOpen" >
+   <property name="text" >
+    <string>&amp;Open</string>
+   </property>
+  </action>
+  <action name="actionSave" >
+   <property name="text" >
+    <string>&amp;Save</string>
+   </property>
+  </action>
+  <action name="actionSaveAs" >
+   <property name="text" >
+    <string>Save as...</string>
+   </property>
+  </action>
+  <action name="actionQuit" >
+   <property name="text" >
+    <string>&amp;Quit</string>
+   </property>
+  </action>
+  <action name="actionPreferences" >
+   <property name="text" >
+    <string>Preferences</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="q3562A.qrc" />
+ </resources>
+ <connections/>
+</ui>
--- a/bin/read_coord	Mon Feb 04 19:19:57 2008 +0100
+++ b/bin/read_coord	Mon Feb 04 19:49:48 2008 +0100
@@ -1,4 +1,9 @@
 #!/usr/bin/python
 
-from HP3562A.coord_decoder import main
+import sys, os
+try:
+    from HP3562A.coord_decoder import main
+except ImportError:
+    sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
+    from HP3562A.coord_decoder import main
 main()
--- a/bin/read_state	Mon Feb 04 19:19:57 2008 +0100
+++ b/bin/read_state	Mon Feb 04 19:49:48 2008 +0100
@@ -1,4 +1,9 @@
 #!/usr/bin/python
 
-from HP3562A.state_decoder import main
+import sys, os
+try:
+    from HP3562A.state_decoder import main
+except ImportError:
+    sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
+    from HP3562A.state_decoder import main
 main()
--- a/bin/read_trace	Mon Feb 04 19:19:57 2008 +0100
+++ b/bin/read_trace	Mon Feb 04 19:49:48 2008 +0100
@@ -1,4 +1,8 @@
 #!/usr/bin/python
-
-from HP3562A.trace_decoder import main
+import sys, os
+try:
+    from HP3562A.trace_decoder import main
+except ImportError:
+    sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
+    from HP3562A.trace_decoder import main
 main()
--- a/plotter/hpgl_plotter.qrc	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<RCC>
-    <qresource prefix="/" >
-        <file>icons/led_green.svg</file>
-        <file>icons/led_green_off.svg</file>
-        <file>icons/led_red.svg</file>
-        <file>icons/led_red_off.svg</file>
-    </qresource>
-</RCC>
--- a/plotter/icons/led_green.svg	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://web.resource.org/cc/"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="278.25241"
-   height="278.25241"
-   id="svg2"
-   sodipodi:version="0.32"
-   inkscape:version="0.45.1"
-   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
-   sodipodi:docname="led_green.svg"
-   inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
-  <defs
-     id="defs4">
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient4117">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop4119" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop4121" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3136">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3138" />
-      <stop
-         style="stop-color:#00ff00;stop-opacity:0;"
-         offset="1"
-         id="stop3140" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3136"
-       id="radialGradient3142"
-       cx="327.41925"
-       cy="34.101982"
-       fx="327.41925"
-       fy="34.101982"
-       r="130.1324"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4123"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4129"
-       gradientUnits="userSpaceOnUse"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.48082306"
-     inkscape:cx="372.04724"
-     inkscape:cy="207.1213"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     inkscape:window-width="996"
-     inkscape:window-height="714"
-     inkscape:window-x="25"
-     inkscape:window-y="4" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Calque 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-175.95852,-171.79899)">
-    <rect
-       style="opacity:1;fill:#00ff00;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
-       id="rect2160"
-       width="259.97089"
-       height="259.97089"
-       x="185.09927"
-       y="180.93974" />
-    <rect
-       y="176.38744"
-       x="180.54697"
-       height="269.0755"
-       width="269.0755"
-       id="rect2162"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#00c40b;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-    <rect
-       y="180.93974"
-       x="185.09927"
-       height="259.97089"
-       width="259.97089"
-       id="rect3134"
-       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
-    <path
-       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
-       id="path3144" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path3146"
-       sodipodi:cx="303.646"
-       sodipodi:cy="129.98544"
-       sodipodi:rx="0"
-       sodipodi:ry="7.2791853"
-       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
-  </g>
-</svg>
--- a/plotter/icons/led_green_off.svg	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://web.resource.org/cc/"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="278.25241"
-   height="278.25241"
-   id="svg2"
-   sodipodi:version="0.32"
-   inkscape:version="0.45.1"
-   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
-   sodipodi:docname="led_green_off.svg"
-   inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
-  <defs
-     id="defs4">
-    <linearGradient
-       id="linearGradient4117">
-      <stop
-         style="stop-color:#acacac;stop-opacity:0.68783069;"
-         offset="0"
-         id="stop4119" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop4121" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3136">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3138" />
-      <stop
-         style="stop-color:#00ff00;stop-opacity:0;"
-         offset="1"
-         id="stop3140" />
-    </linearGradient>
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4129"
-       gradientUnits="userSpaceOnUse"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.48082306"
-     inkscape:cx="372.04724"
-     inkscape:cy="-64.793696"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     inkscape:window-width="996"
-     inkscape:window-height="714"
-     inkscape:window-x="22"
-     inkscape:window-y="21" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Calque 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-175.95852,-171.79899)">
-    <rect
-       style="opacity:1;fill:#009900;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
-       id="rect2160"
-       width="259.97089"
-       height="259.97089"
-       x="185.09927"
-       y="180.93974" />
-    <rect
-       y="176.38744"
-       x="180.54697"
-       height="269.0755"
-       width="269.0755"
-       id="rect2162"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#008304;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-    <path
-       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
-       id="path3144" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path3146"
-       sodipodi:cx="303.646"
-       sodipodi:cy="129.98544"
-       sodipodi:rx="0"
-       sodipodi:ry="7.2791853"
-       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
-  </g>
-</svg>
--- a/plotter/icons/led_red.svg	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://web.resource.org/cc/"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="278.25241"
-   height="278.25241"
-   id="svg2"
-   sodipodi:version="0.32"
-   inkscape:version="0.45.1"
-   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
-   sodipodi:docname="led_red.svg"
-   inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
-  <defs
-     id="defs4">
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient4117">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop4119" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop4121" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3136">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3138" />
-      <stop
-         style="stop-color:#ff0000;stop-opacity:0;"
-         offset="1"
-         id="stop3140" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3136"
-       id="radialGradient3142"
-       cx="327.41925"
-       cy="34.101982"
-       fx="327.41925"
-       fy="34.101982"
-       r="130.1324"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4123"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4129"
-       gradientUnits="userSpaceOnUse"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.96164611"
-     inkscape:cx="326.38382"
-     inkscape:cy="89.862869"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     inkscape:window-width="996"
-     inkscape:window-height="714"
-     inkscape:window-x="11"
-     inkscape:window-y="13" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Calque 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-175.95852,-171.79899)">
-    <rect
-       style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
-       id="rect2160"
-       width="259.97089"
-       height="259.97089"
-       x="185.09927"
-       y="180.93974" />
-    <rect
-       y="176.38744"
-       x="180.54697"
-       height="269.0755"
-       width="269.0755"
-       id="rect2162"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-    <path
-       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
-       id="path3144" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path3146"
-       sodipodi:cx="303.646"
-       sodipodi:cy="129.98544"
-       sodipodi:rx="0"
-       sodipodi:ry="7.2791853"
-       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
-    <rect
-       y="180.93974"
-       x="185.09927"
-       height="259.97089"
-       width="259.97089"
-       id="rect3134"
-       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
-  </g>
-</svg>
--- a/plotter/icons/led_red_off.svg	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://web.resource.org/cc/"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="278.2525"
-   height="278.2525"
-   id="svg2"
-   sodipodi:version="0.32"
-   inkscape:version="0.45.1"
-   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
-   sodipodi:docname="led_red_off.svg"
-   inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
-  <defs
-     id="defs4">
-    <linearGradient
-       inkscape:collect="always"
-       id="linearGradient4117">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop4119" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop4121" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3136">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3138" />
-      <stop
-         style="stop-color:#aa0000;stop-opacity:0;"
-         offset="1"
-         id="stop3140" />
-    </linearGradient>
-    <radialGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient3136"
-       id="radialGradient3142"
-       cx="327.41925"
-       cy="34.101982"
-       fx="327.41925"
-       fy="34.101982"
-       r="130.1324"
-       gradientUnits="userSpaceOnUse"
-       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4123"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       inkscape:collect="always"
-       xlink:href="#linearGradient4117"
-       id="linearGradient4129"
-       gradientUnits="userSpaceOnUse"
-       x1="260.95242"
-       y1="121.18842"
-       x2="488.65955"
-       y2="351.48065"
-       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="0.96164611"
-     inkscape:cx="326.38382"
-     inkscape:cy="69.71549"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     inkscape:window-width="996"
-     inkscape:window-height="714"
-     inkscape:window-x="11"
-     inkscape:window-y="13" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Calque 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-175.95847,-171.79894)">
-    <rect
-       y="180.93974"
-       x="185.09927"
-       height="259.97089"
-       width="259.97089"
-       id="rect3134"
-       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
-    <rect
-       style="opacity:1;fill:#a20000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
-       id="rect2160"
-       width="259.97089"
-       height="259.97089"
-       x="185.09927"
-       y="180.93974" />
-    <rect
-       y="176.38744"
-       x="180.54697"
-       height="269.0755"
-       width="269.0755"
-       id="rect2162"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#950000;stroke-width:9.17700005;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-    <path
-       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
-       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
-       id="path3144" />
-    <path
-       sodipodi:type="arc"
-       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-       id="path3146"
-       sodipodi:cx="303.646"
-       sodipodi:cy="129.98544"
-       sodipodi:rx="0"
-       sodipodi:ry="7.2791853"
-       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
-  </g>
-</svg>
--- a/plotter/qpreferences.py	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-import os
-from PyQt4 import QtCore, QtGui, uic
-from tools import AbstractRegister 
-
-def fromVariant(v):
-    _cvrts = {0: lambda x:None,
-              1: lambda x:x.toBool(),
-              2: lambda x:x.toInt()[0],
-              6: lambda x:x.toDouble()[0],
-              10: lambda x:unicode(x.toString()),
-              12: lambda x:x.toByteArray(),
-              21: lambda x:x.toSize(),
-              22: lambda x:x.toSizeF(),
-              25: lambda x:x.toPoint(),
-              26: lambda x:x.toPointF(),
-              64: lambda x:QtGui.QFont(x),
-              67: lambda x:QtGui.QColor(x),
-              }
-    t = v.userType()
-    return _cvrts[t](v)
-
-class PreferenceMetaclass(type):
-    _widgets = {}
-    def __init__(cls, name, bases, dct):
-        # called at class creation
-        super(type, cls).__init__(name, bases, dct)
-        if name != "BaseItem":
-            ItemRegister().add(cls)
-
-class BaseItem(object):
-    #__metaclass__ = PreferenceMetaclass
-    _id = 0
-    def __init__(self, default=None, name=None, description=None, group=None):
-        self._default = default
-        self._id = BaseItem._id
-        self._name = name
-        self._description = description
-        self._group = group
-        BaseItem._id += 1
-
-    def validate(self, value):
-        return True
-    
-    def __get__(self, obj, cls):
-        if obj is None: #when called from the class, return the Item itself
-            return self
-        try:
-            return obj.getPref(self._id)
-        except Exception, e:
-            return None
-
-    def __set__(self, obj, value):
-        obj.setPref(self._id, value)
-
-class ItemRegister(AbstractRegister):
-    _registered_type = BaseItem
-    getItem = AbstractRegister.get_class
-
-class PointItem(BaseItem):
-    _type = QtCore.QPoint
-
-class SizeItem(BaseItem):
-    _type = QtCore.QSize
-
-class ByteArrayItem(BaseItem):
-    _type = QtCore.QByteArray
-    
-class UnicodeItem(BaseItem):
-    _type = unicode
-    def validate(self, value):
-        return isinstance(value, basestring)
-        
-class IntItem(BaseItem):
-    _type = int
-    def __init__(self, default=None, name=None, description=None, group=None, min=None, max=None):
-        BaseItem.__init__(self, default, name, description, group)
-        self._min = min
-        self._max = max
-
-    def validate(self, value):
-        try:
-            value = self._type(value)
-        except:
-            return False
-        if self._min is not None and value<self._min:
-            return False
-        if self._max is not None and value>self._max:
-            return False
-        return True
-
-class ColorItem(BaseItem):
-    _type = QtGui.QColor
-
-    def validate(self, value):
-        try:
-            self._type(value)
-            return True
-        except:
-            return False
-    
-class AbstractPreferences(QtCore.QObject):
-    def __init__(self):
-        QtCore.QObject.__init__(self)
-        self._settings = QtCore.QSettings(QtCore.QSettings.UserScope,
-                                          self.ORGANISATION, self.APPLICATION)
-        self._prefs = {}
-        self.groups = []
-        keys = []
-        for k in dir(self.__class__):
-            item = self.getItem(k)
-            if isinstance(item, BaseItem):
-                keys.append((k,item))
-        keys.sort(key=lambda x: x[1]._id)
-        for k, item in keys:
-            self._prefs[item._id] = k
-            if item._group not in self.groups:
-                self.groups.append(item._group)
-
-    def getItem(self, key):
-        return getattr(self.__class__, key)
-        #return self._prefs.get(key, None)
-    
-    def getPref(self, key):
-        key = self._prefs.get(key, key)
-        default = getattr(self.__class__, key)._default
-        if default is not None:
-            default = QtCore.QVariant(default)
-        else:
-            default = QtCore.QVariant()
-        val = fromVariant(self._settings.value(key, default))
-        return val
-    
-    def setPref(self, key, value):
-        key = self._prefs.get(key, key)
-        self._settings.setValue(key, QtCore.QVariant(value))
-
-    def keys(self, group=None):
-        return [k for k in self._prefs.values() if not k.startswith('_') and self.getItem(k)._group == group]
-
-    def getName(self, key):
-        item = getattr(self.__class__, key)
-        return item._name
-
-    def getDescription(self, key):
-        item = getattr(self.__class__, key)
-        return item._description
-
-    def __getitem__(self, key):
-        return getattr(self, key)
-    
--- a/plotter/qpreferences_dialog.ui	Mon Feb 04 19:19:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-<ui version="4.0" >
- <class>PreferencesDialog</class>
- <widget class="QDialog" name="PreferencesDialog" >
-  <property name="geometry" >
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>300</height>
-   </rect>
-  </property>
-  <property name="windowTitle" >
-   <string>Dialog</string>
-  </property>
-  <layout class="QVBoxLayout" >
-   <item>
-    <widget class="QTabWidget" name="centralTab" >
-     <property name="currentIndex" >
-      <number>0</number>
-     </property>
-     <widget class="QWidget" name="tab" >
-      <attribute name="title" >
-       <string>Tab 1</string>
-      </attribute>
-     </widget>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox" >
-     <property name="orientation" >
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons" >
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>PreferencesDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel" >
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel" >
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>PreferencesDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel" >
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel" >
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/icons/led_green.svg	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="278.25241"
+   height="278.25241"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
+   sodipodi:docname="led_green.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4117">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop4119" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4121" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3136">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3138" />
+      <stop
+         style="stop-color:#00ff00;stop-opacity:0;"
+         offset="1"
+         id="stop3140" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3136"
+       id="radialGradient3142"
+       cx="327.41925"
+       cy="34.101982"
+       fx="327.41925"
+       fy="34.101982"
+       r="130.1324"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4123"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4129"
+       gradientUnits="userSpaceOnUse"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.48082306"
+     inkscape:cx="372.04724"
+     inkscape:cy="207.1213"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="996"
+     inkscape:window-height="714"
+     inkscape:window-x="25"
+     inkscape:window-y="4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-175.95852,-171.79899)">
+    <rect
+       style="opacity:1;fill:#00ff00;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="259.97089"
+       height="259.97089"
+       x="185.09927"
+       y="180.93974" />
+    <rect
+       y="176.38744"
+       x="180.54697"
+       height="269.0755"
+       width="269.0755"
+       id="rect2162"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#00c40b;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       y="180.93974"
+       x="185.09927"
+       height="259.97089"
+       width="259.97089"
+       id="rect3134"
+       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
+    <path
+       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
+       id="path3144" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3146"
+       sodipodi:cx="303.646"
+       sodipodi:cy="129.98544"
+       sodipodi:rx="0"
+       sodipodi:ry="7.2791853"
+       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/icons/led_green_off.svg	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="278.25241"
+   height="278.25241"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
+   sodipodi:docname="led_green_off.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient4117">
+      <stop
+         style="stop-color:#acacac;stop-opacity:0.68783069;"
+         offset="0"
+         id="stop4119" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4121" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3136">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3138" />
+      <stop
+         style="stop-color:#00ff00;stop-opacity:0;"
+         offset="1"
+         id="stop3140" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4129"
+       gradientUnits="userSpaceOnUse"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.48082306"
+     inkscape:cx="372.04724"
+     inkscape:cy="-64.793696"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="996"
+     inkscape:window-height="714"
+     inkscape:window-x="22"
+     inkscape:window-y="21" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-175.95852,-171.79899)">
+    <rect
+       style="opacity:1;fill:#009900;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="259.97089"
+       height="259.97089"
+       x="185.09927"
+       y="180.93974" />
+    <rect
+       y="176.38744"
+       x="180.54697"
+       height="269.0755"
+       width="269.0755"
+       id="rect2162"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#008304;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <path
+       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
+       id="path3144" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3146"
+       sodipodi:cx="303.646"
+       sodipodi:cy="129.98544"
+       sodipodi:rx="0"
+       sodipodi:ry="7.2791853"
+       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/icons/led_red.svg	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="278.25241"
+   height="278.25241"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
+   sodipodi:docname="led_red.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4117">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop4119" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4121" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3136">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3138" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:0;"
+         offset="1"
+         id="stop3140" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3136"
+       id="radialGradient3142"
+       cx="327.41925"
+       cy="34.101982"
+       fx="327.41925"
+       fy="34.101982"
+       r="130.1324"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4123"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4129"
+       gradientUnits="userSpaceOnUse"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.96164611"
+     inkscape:cx="326.38382"
+     inkscape:cy="89.862869"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="996"
+     inkscape:window-height="714"
+     inkscape:window-x="11"
+     inkscape:window-y="13" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-175.95852,-171.79899)">
+    <rect
+       style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="259.97089"
+       height="259.97089"
+       x="185.09927"
+       y="180.93974" />
+    <rect
+       y="176.38744"
+       x="180.54697"
+       height="269.0755"
+       width="269.0755"
+       id="rect2162"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:9.17689896;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <path
+       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
+       id="path3144" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3146"
+       sodipodi:cx="303.646"
+       sodipodi:cy="129.98544"
+       sodipodi:rx="0"
+       sodipodi:ry="7.2791853"
+       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
+    <rect
+       y="180.93974"
+       x="185.09927"
+       height="259.97089"
+       width="259.97089"
+       id="rect3134"
+       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/icons/led_red_off.svg	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="278.2525"
+   height="278.2525"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   sodipodi:docbase="/home/david/Electronic/HP3562/icons"
+   sodipodi:docname="led_red_off.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4117">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop4119" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4121" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3136">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3138" />
+      <stop
+         style="stop-color:#aa0000;stop-opacity:0;"
+         offset="1"
+         id="stop3140" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3136"
+       id="radialGradient3142"
+       cx="327.41925"
+       cy="34.101982"
+       fx="327.41925"
+       fy="34.101982"
+       r="130.1324"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.5695707e-7,-3.2469858,2.296245,6.8708969e-6,366.91049,1504.183)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4123"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4117"
+       id="linearGradient4129"
+       gradientUnits="userSpaceOnUse"
+       x1="260.95242"
+       y1="121.18842"
+       x2="488.65955"
+       y2="351.48065"
+       gradientTransform="matrix(1.2457226,0,0,1.2615854,-176.7768,-90.496508)" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.96164611"
+     inkscape:cx="326.38382"
+     inkscape:cy="69.71549"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:window-width="996"
+     inkscape:window-height="714"
+     inkscape:window-x="11"
+     inkscape:window-y="13" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-175.95847,-171.79894)">
+    <rect
+       y="180.93974"
+       x="185.09927"
+       height="259.97089"
+       width="259.97089"
+       id="rect3134"
+       style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       style="opacity:1;fill:#a20000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.29390666;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:0.29390666, 0.29390666;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2160"
+       width="259.97089"
+       height="259.97089"
+       x="185.09927"
+       y="180.93974" />
+    <rect
+       y="176.38744"
+       x="180.54697"
+       height="269.0755"
+       width="269.0755"
+       id="rect2162"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#950000;stroke-width:9.17700005;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <path
+       style="fill:url(#linearGradient4129);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       d="M 185.09375,180.9375 L 185.09375,352.5625 C 190.93752,352.79982 196.83856,352.9375 202.78125,352.9375 C 312.80014,352.9375 406.95049,311.61044 445.0625,253.25 L 445.0625,180.9375 L 185.09375,180.9375 z "
+       id="path3144" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3146"
+       sodipodi:cx="303.646"
+       sodipodi:cy="129.98544"
+       sodipodi:rx="0"
+       sodipodi:ry="7.2791853"
+       d="M 303.646 129.98544 A 0 7.2791853 0 1 1  303.646,129.98544 A 0 7.2791853 0 1 1  303.646 129.98544 z" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/qpreferences.py	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,150 @@
+import os
+from PyQt4 import QtCore, QtGui, uic
+from tools import AbstractRegister 
+
+def fromVariant(v):
+    _cvrts = {0: lambda x:None,
+              1: lambda x:x.toBool(),
+              2: lambda x:x.toInt()[0],
+              6: lambda x:x.toDouble()[0],
+              10: lambda x:unicode(x.toString()),
+              12: lambda x:x.toByteArray(),
+              21: lambda x:x.toSize(),
+              22: lambda x:x.toSizeF(),
+              25: lambda x:x.toPoint(),
+              26: lambda x:x.toPointF(),
+              64: lambda x:QtGui.QFont(x),
+              67: lambda x:QtGui.QColor(x),
+              }
+    t = v.userType()
+    return _cvrts[t](v)
+
+class PreferenceMetaclass(type):
+    _widgets = {}
+    def __init__(cls, name, bases, dct):
+        # called at class creation
+        super(type, cls).__init__(name, bases, dct)
+        if name != "BaseItem":
+            ItemRegister().add(cls)
+
+class BaseItem(object):
+    #__metaclass__ = PreferenceMetaclass
+    _id = 0
+    def __init__(self, default=None, name=None, description=None, group=None):
+        self._default = default
+        self._id = BaseItem._id
+        self._name = name
+        self._description = description
+        self._group = group
+        BaseItem._id += 1
+
+    def validate(self, value):
+        return True
+    
+    def __get__(self, obj, cls):
+        if obj is None: #when called from the class, return the Item itself
+            return self
+        try:
+            return obj.getPref(self._id)
+        except Exception, e:
+            return None
+
+    def __set__(self, obj, value):
+        obj.setPref(self._id, value)
+
+class ItemRegister(AbstractRegister):
+    _registered_type = BaseItem
+    getItem = AbstractRegister.get_class
+
+class PointItem(BaseItem):
+    _type = QtCore.QPoint
+
+class SizeItem(BaseItem):
+    _type = QtCore.QSize
+
+class ByteArrayItem(BaseItem):
+    _type = QtCore.QByteArray
+    
+class UnicodeItem(BaseItem):
+    _type = unicode
+    def validate(self, value):
+        return isinstance(value, basestring)
+        
+class IntItem(BaseItem):
+    _type = int
+    def __init__(self, default=None, name=None, description=None, group=None, min=None, max=None):
+        BaseItem.__init__(self, default, name, description, group)
+        self._min = min
+        self._max = max
+
+    def validate(self, value):
+        try:
+            value = self._type(value)
+        except:
+            return False
+        if self._min is not None and value<self._min:
+            return False
+        if self._max is not None and value>self._max:
+            return False
+        return True
+
+class ColorItem(BaseItem):
+    _type = QtGui.QColor
+
+    def validate(self, value):
+        try:
+            self._type(value)
+            return True
+        except:
+            return False
+    
+class AbstractPreferences(QtCore.QObject):
+    def __init__(self):
+        QtCore.QObject.__init__(self)
+        self._settings = QtCore.QSettings(QtCore.QSettings.UserScope,
+                                          self.ORGANISATION, self.APPLICATION)
+        self._prefs = {}
+        self.groups = []
+        keys = []
+        for k in dir(self.__class__):
+            item = self.getItem(k)
+            if isinstance(item, BaseItem):
+                keys.append((k,item))
+        keys.sort(key=lambda x: x[1]._id)
+        for k, item in keys:
+            self._prefs[item._id] = k
+            if item._group not in self.groups:
+                self.groups.append(item._group)
+
+    def getItem(self, key):
+        return getattr(self.__class__, key)
+        #return self._prefs.get(key, None)
+    
+    def getPref(self, key):
+        key = self._prefs.get(key, key)
+        default = getattr(self.__class__, key)._default
+        if default is not None:
+            default = QtCore.QVariant(default)
+        else:
+            default = QtCore.QVariant()
+        val = fromVariant(self._settings.value(key, default))
+        return val
+    
+    def setPref(self, key, value):
+        key = self._prefs.get(key, key)
+        self._settings.setValue(key, QtCore.QVariant(value))
+
+    def keys(self, group=None):
+        return [k for k in self._prefs.values() if not k.startswith('_') and self.getItem(k)._group == group]
+
+    def getName(self, key):
+        item = getattr(self.__class__, key)
+        return item._name
+
+    def getDescription(self, key):
+        item = getattr(self.__class__, key)
+        return item._description
+
+    def __getitem__(self, key):
+        return getattr(self, key)
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/qpreferences_dialog.ui	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,75 @@
+<ui version="4.0" >
+ <class>PreferencesDialog</class>
+ <widget class="QDialog" name="PreferencesDialog" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" >
+   <item>
+    <widget class="QTabWidget" name="centralTab" >
+     <property name="currentIndex" >
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="tab" >
+      <attribute name="title" >
+       <string>Tab 1</string>
+      </attribute>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox" >
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons" >
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PreferencesDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PreferencesDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt4/resources.qrc	Mon Feb 04 19:49:48 2008 +0100
@@ -0,0 +1,8 @@
+<RCC>
+    <qresource prefix="/" >
+        <file>icons/led_green.svg</file>
+        <file>icons/led_green_off.svg</file>
+        <file>icons/led_red.svg</file>
+        <file>icons/led_red_off.svg</file>
+    </qresource>
+</RCC>

mercurial