Wed, 16 Jan 2008 01:20:02 +0100
make qplotter a working app: can new load several hpgl files à display them; have a preference system
hpgl_plotter.qrc | file | annotate | diff | comparison | revisions | |
hpgl_qt.py | file | annotate | diff | comparison | revisions | |
icons/led_green.png | file | annotate | diff | comparison | revisions | |
icons/led_green.svg | file | annotate | diff | comparison | revisions | |
icons/led_green_off.png | file | annotate | diff | comparison | revisions | |
icons/led_green_off.svg | file | annotate | diff | comparison | revisions | |
qgpib_plotter.py | file | annotate | diff | comparison | revisions | |
qhpgl_plotter.ui | file | annotate | diff | comparison | revisions | |
qpreferences.py | file | annotate | diff | comparison | revisions | |
qpreferences_dialog.ui | file | annotate | diff | comparison | revisions |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hpgl_plotter.qrc Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/" > + <file>icons/led_green.png</file> + <file>icons/led_green.svg</file> + <file>icons/led_green_off.png</file> + <file>icons/led_green_off.svg</file> + </qresource> +</RCC>
--- a/hpgl_qt.py Fri Jan 11 18:50:46 2008 +0100 +++ b/hpgl_qt.py Wed Jan 16 01:20:02 2008 +0100 @@ -21,22 +21,31 @@ def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) + l = QtGui.QVBoxLayout(self) + l.setMargin(1) + self.qview = QtGui.QGraphicsView(self) + self.qview.scale(0.5,-0.5) + l = self.layout() + l.addWidget(self.qview) + self.setBackgroundRole(QtGui.QPalette.Base) + self.setSizePolicy(QtGui.QSizePolicy.Expanding, + QtGui.QSizePolicy.Expanding) + self.clear() + HPGLParser.__init__(self) + def parse(self, data): + HPGLParser.parse(self, data) + self.resize(self.size()) + + def clear(self): self.qpen = QtGui.QPen(QtCore.Qt.blue) self.qbrush = QtGui.QBrush(QtCore.Qt.blue) self.qfont = QtGui.QFont('Courier') self.qantialiased = False self.qtransformed = False self.qscene = QtGui.QGraphicsScene() - self.qview = QtGui.QGraphicsView(self.qscene, self) - self.qview.scale(0.5,-0.5) - l = QtGui.QVBoxLayout(self) - l.addWidget(self.qview) - self.setBackgroundRole(QtGui.QPalette.Base) - self.setSizePolicy(QtGui.QSizePolicy.Expanding, - QtGui.QSizePolicy.Expanding) - HPGLParser.__init__(self) - + self.qview.setScene(self.qscene) + def _get_PW(self): return self._pen_width def _set_PW(self, value):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/icons/led_green.svg Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,142 @@ +<?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="210mm" + height="297mm" + 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"> + <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="586.3824" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="996" + inkscape:window-height="714" + inkscape:window-x="0" + inkscape:window-y="0" /> + <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"> + <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.0;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/icons/led_green_off.svg Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,114 @@ +<?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="210mm" + height="297mm" + 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"> + <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="586.3824" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="996" + inkscape:window-height="714" + inkscape:window-x="0" + inkscape:window-y="0" /> + <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"> + <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/qgpib_plotter.py Fri Jan 11 18:50:46 2008 +0100 +++ b/qgpib_plotter.py Wed Jan 16 01:20:02 2008 +0100 @@ -1,34 +1,152 @@ # -from PyQt4 import QtGui, QtCore +import os, sys + +from PyQt4 import QtGui, QtCore, uic from PyQt4.QtCore import SIGNAL, Qt -from gppib_plotter import GPIBplotter +from gpib_plotter import GPIBplotter from hpgl_qt import QHPGLPlotterWidget -ORGANISATION="Logilab" -APPLICATION="qgpib_plotter" -def variant(v): - _cvrts = {1: lambda x:x.toInt(), - 10: lambda x:unicode(x.toString()), - } - t = v.userType() +form_class, base_class = uic.loadUiType(os.path.join(os.path.dirname(__file__), "qhpgl_plotter.ui")) + +from qpreferences import PreferenceItem, AbstractPreferences, PreferencesEditor + +class Preferences(AbstractPreferences): + ORGANISATION="Logilab" + APPLICATION="qgpib_plotter" -class Preferences(object): - _defaults = {'device': '/dev/ttyUSB0', - 'address': 0, - } - def __init__(self): - self._settings = qc.QSettings(qc.QSettings.UserScope, - ORGANISATION, APPLICATION) - - def getPref(self, key): - val = self._settings.value(key, QtCore.QVariant(self._defaults[key])) - - -class QtHPGLPlotter(QtGui.QMainWindow): + device = PreferenceItem('/dev/ttyUSB0', name=u'device', description=u'GPIB device') + address = PreferenceItem(5, name=u'GPIB address') + _pos = PreferenceItem(basetype=QtCore.QPoint) + _size = PreferenceItem(basetype=QtCore.QSize) + _appState = PreferenceItem(basetype=QtCore.QByteArray) + +class QtHPGLPlotter(QtGui.QMainWindow, form_class): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) - self.gpib_plotter = GPIBplotter( + 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) + + 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.connect(self.actionOpen, SIGNAL('triggered(bool)'), + self.openTriggered) + self.connect(self.actionSave, SIGNAL('triggered(bool)'), + self.saveTriggered) + 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 = QHPGLPlotterWidget(self) + #self.setCentralWidget(self.plotterWidget) + self.plotterWidget.clear() + self.plotterWidget.parse(self._plots[value]) + + def preferencesTriggered(self, checked=False): + PreferencesEditor(self._prefs, self).exec_() + + 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 (*)') + 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) + #self.plotsView.setCurrentIndex(self.plotsView.model().index(self.plotsView.model().stringList().count(), 0)) + + + + def saveTriggered(self, checked=False): + print "save" + def saveAsTriggered(self, checked=False): + print "saveAs" + + def initializeGPIB(self): + try: + self.gpib_plotter = GPIBplotter(device=self._prefs.device, + address=self._prefs.address, + ) + except: + self.gpib_plotter = None + self._online = False + 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 + else: + # todo + self._online = True + else: + self._online = False + self.setCaptureLed() + + + def setCaptureLed(self): + if self._online: + icn = QtGui.QIcon(':/icons/led_green.png') + else: + icn = QtGui.QIcon(':/icons/led_green_off.png') + self.captureButton.setIcon(icn) + self.captureButton.setChecked(self._online) + +if __name__ == '__main__': + a = QtGui.QApplication([]) + w = QtHPGLPlotter() + w.show() + a.exec_() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qhpgl_plotter.ui Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,130 @@ +<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>&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>2</number> + </property> + <property name="topMargin" > + <number>2</number> + </property> + <property name="rightMargin" > + <number>2</number> + </property> + <property name="bottomMargin" > + <number>2</number> + </property> + <item> + <widget class="QToolButton" name="captureButton" > + <property name="minimumSize" > + <size> + <width>0</width> + <height>29</height> + </size> + </property> + <property name="text" > + <string>on line</string> + </property> + <property name="icon" > + <iconset resource="hpgl_plotter.qrc" >:/icons/led_green.png</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="QListView" name="plotsView" /> + </item> + </layout> + </widget> + </widget> + <action name="actionOpen" > + <property name="text" > + <string>&Open</string> + </property> + </action> + <action name="actionSave" > + <property name="text" > + <string>&Save</string> + </property> + </action> + <action name="actionSaveAs" > + <property name="text" > + <string>Save as...</string> + </property> + </action> + <action name="actionQuit" > + <property name="text" > + <string>&Quit</string> + </property> + </action> + <action name="actionPreferences" > + <property name="text" > + <string>Preferences</string> + </property> + </action> + </widget> + <resources> + <include location="hpgl_plotter.qrc" /> + </resources> + <connections/> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qpreferences.py Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,141 @@ +import os +from PyQt4 import QtCore, QtGui, uic + +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(), + + } + t = v.userType() + return _cvrts[t](v) + +class PreferenceItem(object): + _id = 0 + def __init__(self, default=None, basetype=None, name=None, description=None): + self._default = default + self._basetype = basetype + if self._basetype is None: + self._basetype = self._default.__class__ + self._id = "_pref%X"%self.__class__._id + self._name = name + self._description = description + self.__class__._id += 1 + + def __get__(self, obj, cls): + if obj is None: + return self + try: + return obj.getPref(self._id) + except Exception, e: + #print "humm", e + return None + + def __set__(self, obj, value): + obj.setPref(self._id, value) + +class AbstractPreferences(QtCore.QObject): + def __init__(self): + QtCore.QObject.__init__(self) + self._settings = QtCore.QSettings(QtCore.QSettings.UserScope, + self.ORGANISATION, self.APPLICATION) + self._prefs = {} + for k in dir(self.__class__): + item = getattr(self.__class__, k) + if isinstance(item, PreferenceItem): + self._prefs[item._id] = k + + 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 = self._settings.value(key, default) + return fromVariant(val) + + def setPref(self, key, value): + key = self._prefs.get(key, key) + self._settings.setValue(key, QtCore.QVariant(value)) + + def keys(self): + return [k for k in self._prefs.values() if not k.startswith('_')] + + def getName(self, key): + item = getattr(self.__class__, key) + return item._name + + def getDescription(self, key): + item = getattr(self.__class__, key) + return item._description + +form_class, base_class = uic.loadUiType(os.path.join(os.path.dirname(__file__), "qpreferences_dialog.ui")) + +class PreferencesEditor(QtGui.QDialog, form_class): + def __init__(self, preferences, parent=None): + QtGui.QDialog.__init__(self, parent) + self.setupUi(self) + self._prefs = preferences + self.buildUI() + + def buildUI(self): + w = self.centralFrame + g = QtGui.QGridLayout(w) + p = self._prefs + eds = {} + self._editors = eds + for i, k in enumerate(p.keys()): + name = p.getName(k) + if not name: + name = k + l = QtGui.QLabel(name, w) + g.addWidget(l, i, 0) + if p.getDescription(k): + l.setToolTip(p.getDescription(k)) + + e = QtGui.QLineEdit(w) + eds[k] = e + g.addWidget(e, i, 1) + val = p.getPref(k) + if val is None: + val = '' + if not isinstance(val, basestring): + val = unicode(val) + e.setText(val) + + g.addWidget(QtGui.QWidget(w), i+1, 0) + g.setRowStretch(i+1,1) + g.setColumnStretch(1,1) + + def accept(self): + p=self._prefs + for k in p.keys(): + newval = unicode(self._editors[k].text()) + p.setPref(k, newval) + return QtGui.QDialog.accept(self) + +if __name__ == '__main__': + class TestPreferences(AbstractPreferences): + ORGANISATION="Logilab" + APPLICATION="test_qpref_editor" + + device = PreferenceItem('/dev/ttyUSB0', name="the device") + address = PreferenceItem(5, description="GPIB address of the plotter") + _pos = PreferenceItem(None) + _size = PreferenceItem(None) + _appState = PreferenceItem(None) + + a = QtGui.QApplication([]) + + prefs = TestPreferences() + w = PreferencesEditor(prefs) + w.show() + a.exec_()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qpreferences_dialog.ui Wed Jan 16 01:20:02 2008 +0100 @@ -0,0 +1,73 @@ +<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="QFrame" name="centralFrame" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + </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>