--- author: '' category: '' date: 2008/08/06 17:12 description: '' link: '' priority: '' slug: BB728 tags: programming, python, urssus title: 'uRSSus: now with configuration dialog goodness!' type: text updated: 2008/08/06 17:12 url_type: '' --- I felt that a "user-friendly" configuration dialog for uRSSus was not a good way to spend effort, because I expect options to change often for a while, and I didn't want an outdated dialog, either. The solution? Autogenerate a mediocre configuration dialog! First, define what options uRSSus supports (Update: suggestion by Alejandro Cura, using tuples works much better!): .. code-block:: python options = ( ('ui', ( ('alwaysShowFeed', ('bool', False, "Always show a link to the post's feed when diplaying a post")), ('hideOnTrayClick', ('bool', True, "Hide the main window when clicking on the tray icon")), ) ), ('options', ( ('defaultRefresh' , ('int', 1800, "How often feeds should be refreshed by default (in seconds).", 300, None )), ('maxPostsDisplayed' , ('int', 1000, "Limit the display to this many posts. If set too high, opening 'All Feeds' may take forever", 0, None)), ('defaultExpiration' , ('int', 7, "How long should articles be kept by default. (In days)", 0, 9999)), ) ), ('twitter', ( ('username', ('string', None, 'Your Twitter user name.' )), ('password', ('password', None, 'Your Twitter password.' )), ) ) ) Then a little magic, and this comes out: .. raw:: html urssus13 How magic? This magic: .. code-block:: python class ConfigDialog(QtGui.QDialog): def __init__(self, parent): QtGui.QDialog.__init__(self, parent) # Set up the UI from designer self.ui=UI_ConfigDialog() self.ui.setupUi(self) pages=[] sections=[] self.values={} for sectionName, options in config.options: # Create a page widget/layout for this section: page=QtGui.QScrollArea() layout=QtGui.QGridLayout() row=-2 for optionName, definition in options: row+=2 if definition[0]=='bool': cb=QtGui.QCheckBox(optionName) cb.setChecked(config.getValue(sectionName, optionName, definition[1])) layout.addWidget(cb, row, 0, 1, 2) self.values[sectionName+'/'+optionName]=[cb, lambda(cb): cb.isChecked()] elif definition[0]=='int': label=QtGui.QLabel(optionName+":") label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) spin=QtGui.QSpinBox() if definition[3] is not None: spin.setMinimum(definition[3]) else: spin.setMinimum(-99999) if definition[4] is not None: spin.setMaximum(definition[4]) else: spin.setMaximum(99999) spin.setValue(config.getValue(sectionName, optionName, definition[1])) layout.addWidget(label, row, 0, 1, 1) layout.addWidget(spin, row, 1, 1, 1) self.values[sectionName+'/'+optionName]=[spin, lambda(spin): spin.value()] elif definition[0]=='string': label=QtGui.QLabel(optionName+":") label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) text=QtGui.QLineEdit() text.setText(config.getValue(sectionName, optionName, definition[1])) layout.addWidget(label, row, 0, 1, 1) layout.addWidget(text, row, 1, 1, 1) self.values[sectionName+'/'+optionName]=[text, lambda(text): unicode(text.text())] elif definition[0]=='password': label=QtGui.QLabel(optionName+":") label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) text=QtGui.QLineEdit() text.setEchoMode(QtGui.QLineEdit.Password) text.setText(config.getValue(sectionName, optionName, definition[1])) layout.addWidget(label, row, 0, 1, 1) layout.addWidget(text, row, 1, 1, 1) self.values[sectionName+'/'+optionName]=[text, lambda(text): unicode(text.text())] help=QtGui.QLabel(definition[2]) help.setWordWrap(True) layout.addWidget(help, row, 2, 1, 1) separator=QtGui.QFrame() separator.setFrameStyle(QtGui.QFrame.HLine|QtGui.QFrame.Plain) layout.addWidget(separator, row+1, 0, 1, 3) page.setLayout(layout) pages.append(page) sections.append(sectionName) for page, name in zip(pages,sections) : # Make a tab out of it self.ui.tabs.addTab(page, name) self.ui.tabs.setCurrentIndex(1) self.ui.tabs.removeTab(0) My first ever thing that I just don't see how it would work without a lambda ;-)