#!/usr/bin/env python """ The PyKDE application sampler This module defines the top-level widgets for displaying the sampler application. """ import inspect import os import sys from qt import SIGNAL, SLOT, PYSIGNAL, Qt from qt import QVBoxLayout, QLabel, QPixmap, QSplitter, QFrame, QDialog from qt import QSizePolicy, QHBoxLayout, QSpacerItem, QPushButton from kdecore import i18n, KAboutData, KApplication, KCmdLineArgs, KGlobal from kdecore import KGlobalSettings, KWin, KWinModule, KURL, KIcon from kdeui import KComboBox, KListView, KListViewItem, KTabWidget, KTextEdit from kdeui import KMainWindow, KPushButton, KSplashScreen, KStdAction from kdeui import KKeyDialog, KEditToolbar from kio import KTrader from kparts import createReadOnlyPart, createReadWritePart from khtml import KHTMLPart import about import lib try: __file__ except (NameError, ): __file__ = sys.argv[0] sigDoubleClicked = SIGNAL('doubleClicked(QListViewItem *)') sigViewItemSelected = SIGNAL('selectionChanged(QListViewItem *)') sigSampleSelected = PYSIGNAL('sample selected') blank = KURL('about:blank') def appConfig(group=None): """ appConfig(group=None) -> returns the application KConfig """ config = KGlobal.instance().config() if group is not None: config.setGroup(group) return config def getIcon(name, group=KIcon.NoGroup, size=KIcon.SizeSmall): """ returns a kde icon by name """ return KGlobal.instance().iconLoader().loadIcon(name, group, size) def getIconSet(name, group=KIcon.NoGroup, size=KIcon.SizeSmall): """ returns a kde icon set by name """ return KGlobal.instance().iconLoader().loadIconSet(name, group, size) def buildPart(parent, query, constraint, writable=False): """ builds the first available offered part on the parent """ offers = KTrader.self().query(query, constraint) for ptr in offers: if writable: builder = createReadWritePart else: builder = createReadOnlyPart part = builder(ptr.library(), parent, ptr.name()) if part: break return part class CommonFrame(QFrame): """ provides a modicum of reuse """ def __init__(self, parent): QFrame.__init__(self, parent) layout = QVBoxLayout(self) layout.setAutoAdd(True) layout.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) class SamplerFrame(CommonFrame): """ frame type that swaps out old widgets for new when told to do so """ def __init__(self, parent): CommonFrame.__init__(self, parent) self.widget = None def setWidget(self, widget): self.layout().deleteAllItems() previous = self.widget if previous: previous.close() delattr(self, 'widget') self.widget = widget def showSample(self, item, module): try: frameType = module.builder() except (AttributeError, ): print 'No sample callable defined in %s' % (module.name(), ) else: frame = frameType(self) self.setWidget(frame) frame.show() class SourceFrame(CommonFrame): """ frame with part for displaying python source """ def __init__(self, parent): CommonFrame.__init__(self, parent) query = '' self.part = buildPart(self, 'application/x-python', query, False) def showModuleSource(self, item, module): if not self.part: print 'No part available for displaying python source.' return try: modulefile = inspect.getabsfile(module.module) except: return self.part.openURL(blank) if os.path.splitext(modulefile)[-1] == '.py': self.part.openURL(KURL('file://%s' % modulefile)) class WebFrame(CommonFrame): """ frame with part for viewing web pages """ docBase = 'http://www.riverbankcomputing.com/Docs/PyKDE3/classref/' def __init__(self, parent): CommonFrame.__init__(self, parent) self.part = part = buildPart(self, 'text/html', "Type == 'Service'") #part.connect(part, SIGNAL('khtmlMousePressEvent(a)'), self.onURL) def onURL(self, a): print '****', a def showDocs(self, item, module): try: mod, cls = module.module.docParts except (AttributeError, ): url = blank else: url = KURL(self.docUrl(mod, cls)) self.part.openURL(url) def docUrl(self, module, klass): """ docUrl(name) -> return a doc url given a name from the kde libs """ return '%s/%s/%s.html' % (self.docBase, module, klass, ) class OutputFrame(KTextEdit): """ text widget that acts (just enough) like a file """ def __init__(self, parent, filehandle): KTextEdit.__init__(self, parent) self.filehandle = filehandle self.setReadOnly(True) self.setFont(KGlobalSettings.fixedFont()) def write(self, text): self.insert(text) def clear(self): self.setText('') def __getattr__(self, name): return getattr(self.filehandle, name) class SamplerListView(KListView): """ the main list view of samples """ def __init__(self, parent): KListView.__init__(self, parent) self.addColumn(i18n('Sample')) self.setRootIsDecorated(True) modules = lib.listmodules() modules.sort(lambda a, b: cmp(a[0], b[0])) modmap = dict(modules) modules = [(name.split('.'), name, mod) for name, mod in modules] roots, cache = {}, {} for names, modname, module in modules: topname, subnames = names[0], names[1:] item = roots.get(topname, None) if item is None: roots[topname] = item = KListViewItem(self, module.labelText()) item.module = module item.setPixmap(0, getIcon(module.icon())) bname = '' subitem = item for subname in subnames: bname = '%s.%s' % (bname, subname, ) item = cache.get(bname, None) if item is None: subitem = cache[bname] = \ KListViewItem(subitem, module.labelText()) subitem.module = module subitem.setPixmap(0, getIcon(module.icon())) subitem = item for root in roots.values(): self.setOpen(root, True) class SamplerMainWindow(KMainWindow): """ the main window """ def __init__(self, *args): KMainWindow.__init__(self, *args) self.hSplitter = hSplit = QSplitter(Qt.Horizontal, self) self.samplesList = samplesList = SamplerListView(hSplit) self.vSplitter = vSplit = QSplitter(Qt.Vertical, hSplit) self.setCentralWidget(hSplit) self.setIcon(getIcon('kmail')) hSplit.setOpaqueResize(True) vSplit.setOpaqueResize(True) self.contentTabs = cTabs = KTabWidget(vSplit) self.outputTabs = oTabs = KTabWidget(vSplit) self.sampleFrame = SamplerFrame(cTabs) self.sourceFrame = SourceFrame(cTabs) self.webFrame = WebFrame(cTabs) cTabs.insertTab(self.sampleFrame, getIconSet('exec'), i18n('Sample')) cTabs.insertTab(self.sourceFrame, getIconSet('source'), i18n('Source')) cTabs.insertTab(self.webFrame, getIconSet('help'), i18n('Docs')) sys.stdout = self.stdoutFrame = OutputFrame(oTabs, sys.stdout) sys.stderr = self.stderrFrame = OutputFrame(oTabs, sys.stderr) termIcons = getIconSet('terminal') oTabs.insertTab(self.stdoutFrame, termIcons, i18n('stdout')) oTabs.insertTab(self.stderrFrame, termIcons, i18n('stderr')) self.resize(640, 480) height, width = self.height(), self.width() hSplit.setSizes([width * 0.35, width * 0.65]) vSplit.setSizes([height * 0.80, height * 0.20]) self.xmlRcFileName = os.path.abspath(os.path.join(os.path.dirname(__file__), 'sampler.rc')) self.setXMLFile(self.xmlRcFileName) config = appConfig() actions = self.actionCollection() actions.readShortcutSettings("", config) self.quitAction = KStdAction.quit(self.close, actions) self.toggleMenubarAction = \ KStdAction.showMenubar(self.showMenubar, actions) self.toggleToolbarAction = \ KStdAction.showToolbar(self.showToolbar, actions) self.toggleStatusbarAction = \ KStdAction.showStatusbar(self.showStatusbar, actions) self.configureKeysAction = \ KStdAction.keyBindings(self.showConfigureKeys, actions) self.configureToolbarAction = \ KStdAction.configureToolbars(self.showConfigureToolbars, actions) self.configureAppAction = \ KStdAction.preferences(self.showConfiguration, actions) connect = self.connect connect(samplesList, sigViewItemSelected, self.sampleSelected) connect(self, sigSampleSelected, self.reloadModule) connect(self, sigSampleSelected, self.sourceFrame.showModuleSource) connect(self, sigSampleSelected, self.sampleFrame.showSample) connect(self, sigSampleSelected, self.webFrame.showDocs) self.restoreWindowSize(config) self.createGUI(self.xmlRcFileName, 0) self.sourceFrame.part.openURL(KURL('file://%s' % os.path.abspath(__file__))) def showConfiguration(self): """ showConfiguration() -> display the config dialog """ return ## not yet implemented dlg = configdialog.ConfigurationDialog(self) for obj in (self.stderrFrame, self.stdoutFrame, self.pythonShell): call = getattr(obj, 'configChanged', None) if call: self.connect(dlg, util.sigConfigChanged, call) dlg.show() def senderCheckShow(self, widget): """ senderCheckShow(widget) -> show or hide widget if sender is checked """ if self.sender().isChecked(): widget.show() else: widget.hide() def showMenubar(self): """ showMenuBar() -> toggle the menu bar """ self.senderCheckShow(self.menuBar()) def showToolbar(self): """ showToolbar() -> toggle the tool bar """ self.senderCheckShow(self.toolBar()) def showStatusbar(self): """ showStatusbar() -> toggle the status bar """ self.senderCheckShow(self.statusBar()) def showConfigureKeys(self): """ showConfigureKeys() -> show the shortcut keys dialog """ ret = KKeyDialog.configure(self.actionCollection(), self) print ret if ret == QDialog.Accepted: actions = self.actionCollection() actions.writeShortcutSettings(None, appConfig()) def showConfigureToolbars(self): """ showConfigureToolbars() -> broken """ dlg = KEditToolbar(self.actionCollection(), self.xmlRcFileName) self.connect(dlg, SIGNAL('newToolbarConfig()'), self.rebuildGui) #connect(self, sigSampleSelected, self.sourceFrame.showModuleSource) dlg.exec_loop() def rebuildGui(self): """ rebuildGui() -> recreate the gui and refresh the palette """ self.createGUI(self.xmlRcFileName, 0) for widget in (self.toolBar(), self.menuBar(), ): widget.setPalette(self.palette()) def sampleSelected(self): """ sampleSelected() -> emit the current item and its module """ self.stdoutFrame.clear() self.stderrFrame.clear() item = self.sender().currentItem() self.emit(sigSampleSelected, (item, item.module)) def setSplashPixmap(self, pixmap): """ setSplashPixmap(pixmap) -> assimilate the splash screen pixmap """ target = self.sampleFrame label = QLabel(target) label.setPixmap(pixmap) target.setWidget(label) def reloadModule(self, item, module): print >> sys.__stdout__, 'reload: ', reload(module.module) if __name__ == '__main__': aboutdata = about.about() KCmdLineArgs.init(sys.argv, aboutdata) app = KApplication() splashpix = QPixmap(os.path.join(lib.samplerpath, 'aboutkde.png')) splash = KSplashScreen(splashpix) splash.resize(splashpix.size()) splash.show() mainWindow = SamplerMainWindow() mainWindow.setSplashPixmap(splashpix) mainWindow.show() splash.finish(mainWindow) app.exec_loop()