class TaskTypeTreeEditor(QDialog): def __init__(self, parent=None): super().__init__(parent) self._view = QTreeView() self._view.setItemDelegate(TaskTypeNameDelegate()) self._view.setContextMenuPolicy(Qt.CustomContextMenu) self._view.customContextMenuRequested.connect(self._open_menu) self._refresh() layout = QVBoxLayout() layout.addWidget(self._view) self.setLayout(layout) self.setWindowTitle(_("Admin.editTaskType")) def _open_menu(self, position): indexes = self._view.selectedIndexes() ids = [index.internalPointer().type_id for index in indexes] menu = QMenu() if len(indexes) == 0: newAction = NewTypeAction("0", self._refresh, self) menu.addAction(newAction) if len(indexes) == 1: newAction = NewTypeAction(ids[0], self._refresh, self) menu.addAction(newAction) deleteAction = DeleteTypeAction(ids, self._refresh, self) menu.addAction(deleteAction) menu.exec_(self._view.viewport().mapToGlobal(position)) def _refresh(self): model = TaskTypeTreeModel() self._view.setModel(model) self._view.expandAll()
class TaskTypeTreeEditor(QDialog): def __init__(self, parent=None): super().__init__(parent) self._view = QTreeView() self._view.setItemDelegate(TaskTypeNameDelegate()) self._view.setContextMenuPolicy(Qt.CustomContextMenu) self._view.customContextMenuRequested.connect(self._open_menu) self._refresh() layout = QVBoxLayout() layout.addWidget(self._view) self.setLayout(layout) self.setWindowTitle(_('Admin.editTaskType')) def _open_menu(self, position): indexes = self._view.selectedIndexes() ids = [index.internalPointer().type_id for index in indexes] menu = QMenu() if len(indexes) == 0: newAction = NewTypeAction('0', self._refresh, self) menu.addAction(newAction) if len(indexes) == 1: newAction = NewTypeAction(ids[0], self._refresh, self) menu.addAction(newAction) deleteAction = DeleteTypeAction(ids, self._refresh, self) menu.addAction(deleteAction) menu.exec_(self._view.viewport().mapToGlobal(position)) def _refresh(self): model = TaskTypeTreeModel() self._view.setModel(model) self._view.expandAll()
class NetCDF3Browser(QWidget): """netCDF-Browser""" def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('NetCDF3', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('NetCDF3', 'Open a netCDF3 file')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadFile) self.dropButton = QToolButton(self.toolBar) self.dropButton.setText(QCoreApplication.translate('NetCDF3', 'Close All')) self.dropButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.clear))) self.dropButton.setToolTip(QCoreApplication.translate('NetCDF3', 'Drop all open netCDF3 files')) self.toolBarLayout.addWidget(self.dropButton) self.connect(self.dropButton, SIGNAL('pressed()'), self.dropFiles) self.dropButton.setEnabled(False) self.toolBarLayout.addStretch(100) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 90) self.splitter.setStretchFactor(1, 10) self.model = NetCDF3Model() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) ftActions = SimuVis4.Globals.fileTypeActions ftActions.addAction(self.loadFile, ('application/x-netcdf',), QCoreApplication.translate('NetCDF3', 'Open in netCDF3 browser'), 10) def loadFile(self, fn=None): if not fn: fn = QFileDialog.getOpenFileName(self, QCoreApplication.translate('NetCDF3', "Select netCDF3 file to open"), SimuVis4.Globals.defaultFolder) if not fn.isEmpty(): fn = unicode(fn) SimuVis4.Globals.defaultFolder, tmp = os.path.split(fn) else: return self.model.addNcFile(fn) SimuVis4.Globals.dataBrowser.toolBox.setCurrentWidget(self) def dropFiles(self): # FIXME: ... pass def itemAction(self, mi,): # FIXME: use a MIME-Handler here i = self.model.itemFromIndex(mi) t, nc = i.ncItem QMessageBox.information(self, QCoreApplication.translate('NetCDF3', 'netCDF3: Item clicked'), QCoreApplication.translate('NetCDF3', 'You clicked an item in the netCDF3-browser')) def showItem(self, mi, pr): i = self.model.itemFromIndex(mi) t, nc = i.ncItem txt = "" name = str(i.data().toString()) if t == 'F': p, f = os.path.split(name) txt = "<i>File </i><b>%s</b><br> in %s" % (f, p) elif t == 'A': txt = "<i>Attribute </i><b>%s:</b><br>%s" % (name, escape(unicode(nc))) elif t == 'D': txt = "<i>Dimension </i><b>%s:</b><br>%s" % (name, str(nc)) elif t == 'V': txt = "<i>Variable </i><b>%s:</b><br>Typecode: %s<br>Dimensions: %s<br>Shape: %s" % \ (name, nc.typecode(), '*'.join(d for d in nc.dimensions), nc.shape) else: return self.textBrowser.setText(txt)
class MobileWidget(QWidget): """ Mobile widget """ RefreshScreen = pyqtSignal() RefreshAutomatic = pyqtSignal(bool) TapOn = pyqtSignal(int, int) def __init__(self, parent=None): """ Constructor """ super(MobileWidget, self).__init__(parent) self.origWidth = 0 self.origHeight = 0 self.imagePath = None self.createActions() self.createWidget() self.createToolbar() self.center() def createActions(self): """ Create qt actions """ self.refreshAction = QtHelper.createAction(self, self.tr("&Refresh"), self.refreshScreen, icon=None) self.refreshAction.setEnabled(False) self.copyAction = QtHelper.createAction(self, self.tr("&Copy"), self.copyItem, icon=None) def createWidget(self): """ Create qt widget """ self.screenResolutionLabel = QLabel(self) self.screenTapLabel = QLabel(self) mobileLayout = QVBoxLayout() self.mobileDockToolbar = QToolBar(self) self.mobileDockToolbar.setStyleSheet("QToolBar { border: 0px }") self.mobileDockToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.mobileImageLabel = QLabel(self) self.mobileImageLabel.setMouseTracking(True) self.mobileImageLabel.installEventFilter(self) self.mobileImageLabel.setScaledContents(True) self.mobileImageLabel.mousePressEvent = self.pixelSelect self.refreshCheckbox = QCheckBox("Automatic Refresh", self) self.refreshCheckbox.setEnabled(False) self.refreshCheckbox.stateChanged.connect(self.onRefreshChanged) self.clickCheckbox = QCheckBox("Enable Tap", self) self.clickCheckbox.setEnabled(False) self.model = DomModel(QDomDocument(), self) self.mobileTreeView = QTreeView(self) self.mobileTreeView.setMinimumWidth(300) self.mobileTreeView.setModel(self.model) self.mobileTreeView.clicked.connect(self.onTreeViewClicked) header = ["Attribute", "Value"] self.tableModel = MyTableModel(self, [], header) self.mobileTableView = QTableView(self) self.mobileTableView.setSelectionMode( QAbstractItemView.SingleSelection) self.mobileTableView.setModel(self.tableModel) self.mobileTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.mobileTableView.customContextMenuRequested.connect( self.onContextMenuEvent) self.mobileTableView.setMinimumWidth(300) mobileViewLayout = QHBoxLayout() mobileViewLayout.addWidget(self.mobileImageLabel) mobileViewLayout.addWidget(self.mobileTreeView) mobileViewLayout.addWidget(self.mobileTableView) mobileLayout.addWidget(self.mobileDockToolbar) mobileLayout.addLayout(mobileViewLayout) self.setLayout(mobileLayout) def createToolbar(self): """ Create qt toolbar """ self.mobileDockToolbar.setObjectName("Toolbar") self.mobileDockToolbar.addWidget(self.refreshCheckbox) self.mobileDockToolbar.addWidget(self.clickCheckbox) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addAction(self.refreshAction) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addWidget(self.screenResolutionLabel) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addWidget(self.screenTapLabel) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.setIconSize(QSize(16, 16)) def center(self): """ Center the dialog """ qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def eventFilter(self, srcEvent, event): """ On event filtering """ if srcEvent == self.mobileImageLabel: if event.type() == QEvent.MouseMove: x = event.pos().x() y = event.pos().y() pixmap = self.mobileImageLabel.pixmap() if pixmap is not None: x_scaled = int((self.origWidth * x) / pixmap.width()) y_scaled = int((self.origHeight * y) / pixmap.height()) self.mobileImageLabel.setToolTip("%sx%s" % (x_scaled, y_scaled)) return False def onContextMenuEvent(self, event): """ On context menu event """ menu = QMenu(self) menu.addAction(self.copyAction) menu.popup(QCursor.pos()) def copyItem(self): """ Copy the item """ indexes = self.mobileTableView.selectedIndexes() if len(indexes): data = self.tableModel.mylist[indexes[0].row()][ indexes[0].column()] clipboard = QApplication.clipboard() clipboard.setText(data) def onTreeViewClicked(self, qindex): """ On click in the treeview """ item = qindex.internalPointer() attributes = [] node = item.node() attributeMap = node.attributes() nodeName = node.nodeName() bounds_str = None for i in range(0, attributeMap.count()): attribute = attributeMap.item(i) attributes.append((attribute.nodeName(), attribute.nodeValue())) if attribute.nodeName() == 'bounds': bounds_str = attribute.nodeValue() self.tableModel.mylist = attributes if sys.version_info > (3, ): self.tableModel.beginResetModel() self.tableModel.endResetModel() else: self.tableModel.reset() self.mobileTableView.resizeColumnsToContents() self.mobileTableView.resizeRowsToContents() # redraw image with rectangle if bounds_str is not None: xy = bounds_str.split('][')[0].split('[')[1] wh = bounds_str.split('][')[1].split(']')[0] x, y = xy.split(',') w, h = wh.split(',') # get label size pixmap = self.mobileImageLabel.pixmap() xlabel = pixmap.width() ylabel = pixmap.height() # resize the rectangle y_scaled = (pixmap.height() * int(y)) / self.origHeight x_scaled = (pixmap.width() * int(x)) / self.origWidth h_scaled = (pixmap.height() * (int(h) - int(y))) / self.origHeight w_scaled = (pixmap.width() * (int(w) - int(x))) / self.origWidth # finally reload self.reloadScreen(x=int(x_scaled), y=int(y_scaled), w=int(w_scaled), h=int(h_scaled)) def onDeviceReady(self): """ On device ready """ self.refreshAction.setEnabled(True) self.refreshCheckbox.setEnabled(True) self.clickCheckbox.setEnabled(True) def refreshScreen(self): """ Refresh the screen """ self.RefreshScreen.emit() def onRefreshChanged(self, state): """ On refresh changed """ if state == Qt.Checked: self.RefreshAutomatic.emit(True) else: self.RefreshAutomatic.emit(False) def pixelSelect(self, event): """ Select pixel to click """ position = QPoint(event.pos().x(), event.pos().y()) x = event.pos().x() y = event.pos().y() pixmap = self.mobileImageLabel.pixmap() x_scaled = int((self.origWidth * x) / pixmap.width()) y_scaled = int((self.origHeight * y) / pixmap.height()) self.screenTapLabel.setText("Tap on (%s,%s)" % (x_scaled, y_scaled)) if self.clickCheckbox.isChecked(): self.TapOn.emit(x_scaled, y_scaled) def drawRectangle(self, x=0, y=0, w=0, h=0): """ Draw a rectangle """ self.mobileImageLabel.update() pixmap = self.mobileImageLabel.pixmap() if pixmap is not None: p = QPainter(pixmap) pen = QPen(Qt.red, 2, Qt.SolidLine) p.setPen(pen) p.drawRect(x, y, w, h) p.end() def reloadScreen(self, x, y, w, h): """ Reload the screen """ if self.imagePath is not None: self.updateScreen(filename=self.imagePath, xmlPath='', x=x, y=y, w=w, h=h, reloadMode=True) def updateScreen(self, filename, xmlPath, x=0, y=0, w=0, h=0, reloadMode=False): """ Update the screen """ self.imagePath = filename if not reloadMode: self.tableModel.mylist = [] self.tableModel.beginResetModel() self.tableModel.endResetModel() pixmap = QPixmap(filename) if pixmap is not None: self.origWidth = pixmap.width() self.origHeight = pixmap.height() self.screenResolutionLabel.setText( "Resolution=%sx%s" % (self.origWidth, self.origHeight)) #portrait if self.origWidth < self.origHeight: pixmap = pixmap.scaledToHeight(Settings.getInt( 'MobileAndroid', 'resolution-screen-height'), mode=Qt.SmoothTransformation) self.mobileImageLabel.setPixmap(pixmap) else: pixmap = pixmap.scaledToWidth(Settings.getInt( 'MobileAndroid', 'resolution-screen-width'), mode=Qt.SmoothTransformation) self.mobileImageLabel.setPixmap(pixmap) self.drawRectangle(x=x, y=y, w=w, h=h) self.resize(pixmap.width(), pixmap.height()) # convert xml to dict if len(xmlPath): f = QFile(xmlPath) if f.open(QIODevice.ReadOnly): document = QDomDocument() if document.setContent(f): newModel = DomModel(document, self) self.mobileTreeView.setModel(newModel) self.mobileTreeView.expandAll() self.mobileTreeView.resizeColumnToContents(0) f.close()
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate("DataStorageBrowser", "Open...")) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Open a datastorage database")) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL("pressed()"), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText("Expand/Collapse") self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip( QCoreApplication.translate("DataStorageBrowser", "Expand or collapse the whole tree") ) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL("pressed()"), self.expandCollapseAll) self.searchInput = MyLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate("DataStorageBrowser", "Enter search text here")) self.searchInput.setToolTip( QCoreApplication.translate( "DataStorageBrowser", "Enter search text using wildcards here, press ENTER again to go to next match!" ) ) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL("returnPressed()"), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate("DataStorageBrowser", "Help")) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Show help for DataStorageBrowser")) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL("pressed()"), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = "" self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() self.statusBar = SimuVis4.Globals.mainWin.statusBar() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory( self, QCoreApplication.translate("DataStorageBrowser", "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder, ) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.collapseAll() self.treeView.expandToDepth(SimuVis4.Globals.config.getint("datastoragebrowser", "expand_tree_depth")) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp("/plugin/DataStorageBrowser/index.html") def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == "R": txt = rootInfo.substitute( name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n) ) + formatMetaData(n) elif t == "P": txt = projectInfo.substitute( name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n) ) + formatMetaData(n) elif t == "G": txt = groupInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.getCharts()), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "S": txt = sensorInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, length=n.datalen(), timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "C": txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) msg = ": ".join(str(self.model.itemFromIndex(mi).data().toString()).split("|")[1:]) self.statusBar.showMessage(msg, 5000) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems( txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive ) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information( self, QCoreApplication.translate("DataStorageBrowser", "No (more) matches!"), QCoreApplication.translate( "DataStorageBrowser", "No (more) matches found! Change you search text and try again!" ), ) self.searchText = "" def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == "S": if qwtPlotWindowActive(): self.addToQwtPlot(n) else: self.showQwtPlot(n) elif t == "C": self.showChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == "R": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Close"), self.closeDatabase) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Reload"), self.reloadDatabase) elif t == "P": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New sensorgroup"), self.newSensorGroup) elif t == "G": nCharts = len(n.getCharts()) if nCharts > 0: txt = str(QCoreApplication.translate("DataStorageBrowser", "Show all charts (%d)")) % nCharts m.addAction(txt, self.showAllCharts) m.addAction( QCoreApplication.translate("DataStorageBrowser", "Save all charts as images"), self.saveAllChartImages, ) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add chart"), self.newChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add/update data"), self.importFiles) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Export data"), self.exportSensors) elif t == "S": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New plot (Qwt)"), self.showQwtPlot) if qwtPlotWindowActive(): m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add to plot (Qwt)"), self.addToQwtPlot) elif t == "C": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Show"), self.showChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Delete"), self.deleteItem) if t in "RPGS": m.addSeparator() m.addAction(QCoreApplication.translate("DataStorageBrowser", "Edit metadata"), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def newSensorGroup(self, mi=None): if mi is None: mi = self.selectedMI newSensorGroup(self.model, mi) def showChart(self, ch=None): if ch is None: ch = self.selectedNode showChartWindow(ch, maximized=showChartMaximized) def importFiles(self, mi=None): if mi is None: mi = self.selectedMI importFiles(self.model, mi) def showAllCharts(self, sg=None): if sg is None: sg = self.selectedNode showAllChartWindows(sg, maximized=showChartMaximized) def saveAllChartImages(self, sg=None): if sg is None: sg = self.selectedNode saveAllChartImages(sg) def exportSensors(self, sg=None): if sg is None: sg = self.selectedNode exportSensors(sg) def showQwtPlot(self, se=None): if se is None: se = self.selectedNode showQwtPlotWindow(se, maximized=showChartMaximized) def addToQwtPlot(self, se=None): if se is None: se = self.selectedNode addToQwtPlotWindow(se) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def reloadDatabase(self, mi=None): if mi is None: mi = self.selectedMI dbPath = self.model.dsFolder(mi) self.model.closeDatabase(mi) self.loadDatabase(dbPath) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi, self) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class SilverTaskWidget(QWidget): ''' ''' def __init__(self,session): QWidget.__init__(self) self.session = session self.setWindowTitle('Silver Gui') self.setMinimumWidth(400) self.layout = QHBoxLayout() self.right_side_layout = QVBoxLayout() self.left_side_layout = QVBoxLayout() # Create an in-process kernel # >>> print_process_id() # will print the same process ID as the main process self.view = Browser() html = '''<html> <head> <title>A Sample Page</title> </head> <body> <h1>Hello, World!</h1> <hr /> I have nothing to say. </body> </html>''' self.view.setHtml(html) self.right_side_layout.addWidget(self.view) self.progressbar = QtGui.QProgressBar() self.progressbar.setMinimum(1) self.progressbar.setMaximum(100) self.left_side_layout.addWidget(self.progressbar) self.taskTreeView = QTreeView() self.taskTreeView.setMinimumWidth(400) self.model = QtGui.QStandardItemModel() self.taskTreeView.setModel(self.model) if self.session is not None: self.progressbar.setMinimum(self.session.root_task.pending()) self.progressbar.setMaximum(self.session.root_task.count()) silver_session.guess_total_time() def recAddTasks(task): me = QtGui.QStandardItem('{}'.format(task.name)) me.setData(task) if task.subtasks: for s in task.subtasks: me.appendRow(recAddTasks( s)) return me self.model.appendRow(recAddTasks(self.session.root_task)) self.taskTreeView.expandAll() #QtCore.QObject.connect(self.taskTreeView.selectionModel(), QtCore.SIGNAL('selectionChanged()'), self.test) self.left_side_layout.addWidget(self.taskTreeView) self.taskTreeView.clicked.connect(self.test) self.layout.addLayout(self.left_side_layout) self.layout.addStretch(1) self.layout.addLayout(self.right_side_layout) self.setLayout(self.layout) self.show() def test(self, index): ind = self.model.itemFromIndex(index) #print(ind.text()) task = ind.data() self.view.setHtml(task.to_html()) def run(self): # Show the form self.show() # Run the qt application qt_app.exec_()
class PrivacyGUI(QWidget): def __init__(self, parent, logger): super(PrivacyGUI, self).__init__(parent) self.logger = logger self._actionModel = PeerActionsModel(self, self.logger) self._initActionList() self._initSettingsWidget() mainWidget = self._initMainWidget() layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(mainWidget) get_notification_center().connectPeerActionsAdded(self._peerActionsAdded) get_notification_center().connectPeerActionsRemoved(self._peerActionsRemoved) def finish(self): get_notification_center().disconnectPeerActionsAdded(self._peerActionsAdded) get_notification_center().disconnectPeerActionsRemoved(self._peerActionsRemoved) self._clearSettingsWidget() @loggingSlot(object) def _peerActionsAdded(self, added): self._actionModel.addPeerActions(added) @loggingSlot(object) def _peerActionsRemoved(self, removed): self._actionModel.removePeerActions(removed) def _initActionList(self): self._actionList = QTreeView(self) self._actionList.setAlternatingRowColors(True) self._actionList.setHeaderHidden(False) self._actionList.setItemsExpandable(True) self._actionList.setIndentation(15) self._actionList.setModel(self._actionModel) self._actionList.expandAll() self._actionList.setSelectionMode(QTreeView.SingleSelection) self._actionList.selectionModel().selectionChanged.connect(self._displaySettings) self._actionList.setObjectName(u"__action_list") self._actionList.setFrameShape(QFrame.StyledPanel) def _initSettingsWidget(self): self._settingsWidget = QWidget(self) settingsLayout = QVBoxLayout(self._settingsWidget) settingsLayout.setContentsMargins(0, 0, 0, 0) def _initMainWidget(self): split = QSplitter(Qt.Horizontal, self) split.addWidget(self._actionList) split.addWidget(self._settingsWidget) split.setStretchFactor(0, 0) split.setStretchFactor(1, 1) return split def hideEvent(self, event): self._clearSettingsWidget() return QWidget.hideEvent(self, event) def showEvent(self, event): self._displaySettings(self._actionList.selectionModel().selection()) return QWidget.showEvent(self, event) def _clearSettingsWidget(self): layout = self._settingsWidget.layout() child = layout.takeAt(0) while child != None: child.widget().finish() child.widget().deleteLater() child = layout.takeAt(0) @loggingSlot(QItemSelection, QItemSelection) def _displaySettings(self, newSelection, _oldSelection=None): self._clearSettingsWidget() if len(newSelection.indexes()) > 0: index = iter(newSelection.indexes()).next() action = index.data(PeerActionsModel.ACTION_ROLE).toPyObject() if action is None: return # root item if action.hasCategories(): self._settingsWidget.layout().addWidget(MultipleCategoriesView(action, self._settingsWidget, self.logger)) else: self._settingsWidget.layout().addWidget(SingleCategoryView(action, self._settingsWidget, self.logger))
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon(QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Open a datastorage database')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadDatabase) self.dropButton = QToolButton(self.toolBar) self.dropButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Close All')) self.dropButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.clear))) self.dropButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Drop all open databases')) self.toolBarLayout.addWidget(self.dropButton) self.connect(self.dropButton, SIGNAL('pressed()'), self.dropDatabases) self.dropButton.setEnabled(False) self.toolBarLayout.addStretch(100) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory(self, QCoreApplication.translate('DataStorageBrowser', "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.expandToDepth(1) def dropDatabases(self): # FIXME: implement it pass def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == 'R': # FIXME: no metadata? txt = rootInfo.substitute(name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n)) # + formatMetaData(n) elif t == 'P': txt = projectInfo.substitute(name=n.name, title=escape(n.title), groups=len(n)) + formatMetaData(n) elif t == 'G': txt = groupInfo.substitute(name=n.name, title=escape(n.title), sensors=len(n), charts=len(n.charts)) + formatMetaData(n) elif t == 'S': txt = sensorInfo.substitute(name=n.name, title=escape(n.title), start=n.timegrid.start, stop=n.timegrid.stop, step=n.timegrid.step, length=n.datalen()) + formatMetaData(n) elif t == 'C': txt = chartInfo.substitute(name=n.name) self.textBrowser.setText(txt) def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == 'R': pass elif t == 'P': pass elif t == 'G': pass elif t == 'S': print n self.showQwtPlot(n) elif t == 'C': self.showMplChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t in 'RPGS': p = m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Edit metadata'), self.editMetadata) if t == 'R': pass elif t == 'P': pass elif t == 'G': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Add Chart'), self.newChart) elif t == 'S': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Plot (Qwt)'), self.showQwtPlot) elif t == 'C': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Show'), self.showMplChart) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Delete'), self.deleteItem) a = m.exec_(self.treeView.mapToGlobal(pos)) def showMplChart(self, node=None): if node is None: node = self.selectedNode showChartMplWindow(node, maximized=showChartMaximized) def showQwtPlot(self, node=None): if node is None: node = self.selectedNode showQwtPlotWindow(node, maximized=showChartMaximized) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Open a datastorage database')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText('Expand/Collapse') self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Expand or collapse the whole tree')) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL('pressed()'), self.expandCollapseAll) self.searchInput = QLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate('DataStorageBrowser', 'Enter search text here')) self.searchInput.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Enter search text using wildcards here, press ENTER again to go to next match!')) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL('returnPressed()'), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Help')) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Show help for DataStorageBrowser')) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL('pressed()'), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = '' self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory(self, QCoreApplication.translate('DataStorageBrowser', "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.expandToDepth(1) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp('/plugin/DataStorageBrowser/index.html') def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == 'R': # FIXME: no metadata? txt = rootInfo.substitute(name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n)) + formatMetaData(n) elif t == 'P': txt = projectInfo.substitute(name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n)) + formatMetaData(n) elif t == 'G': txt = groupInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.charts)) + formatMetaData(n) elif t == 'S': txt = sensorInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), start=n.timegrid.start, stop=n.timegrid.stop, step=n.timegrid.step, length=n.datalen()) + formatMetaData(n) elif t == 'C': txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems(txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information(self, QCoreApplication.translate('DataStorageBrowser', 'No (more) matches!'), QCoreApplication.translate('DataStorageBrowser', 'No (more) matches found! Change you search criteria and try again!')) self.searchText = '' def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == 'R': pass elif t == 'P': pass elif t == 'G': pass elif t == 'S': self.showQwtPlot(n) elif t == 'C': self.showMplChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == 'R': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Close'), self.closeDatabase) elif t == 'P': pass elif t == 'G': nCharts = len(n.charts) if nCharts > 0: txt = str(QCoreApplication.translate('DataStorageBrowser', 'Show all Charts (%d)')) % nCharts m.addAction(txt, self.showAllCharts) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Add Chart'), self.newChart) elif t == 'S': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Plot (Qwt)'), self.showQwtPlot) elif t == 'C': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Show'), self.showMplChart) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Delete'), self.deleteItem) if t in 'RPGS': m.addSeparator() m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Edit metadata'), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def showMplChart(self, node=None): if node is None: node = self.selectedNode showChartMplWindow(node, maximized=showChartMaximized) def showAllCharts(self, node=None): if node is None: node = self.selectedNode for chart in node.charts.values(): showChartMplWindow(chart, maximized=showChartMaximized) def showQwtPlot(self, node=None): if node is None: node = self.selectedNode showQwtPlotWindow(node, maximized=showChartMaximized) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon( QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class SilverTaskWidget(QWidget): ''' ''' def __init__(self, session): QWidget.__init__(self) self.session = session self.setWindowTitle('Silver Gui') self.setMinimumWidth(400) self.layout = QHBoxLayout() self.right_side_layout = QVBoxLayout() self.left_side_layout = QVBoxLayout() # Create an in-process kernel # >>> print_process_id() # will print the same process ID as the main process self.view = Browser() html = '''<html> <head> <title>A Sample Page</title> </head> <body> <h1>Hello, World!</h1> <hr /> I have nothing to say. </body> </html>''' self.view.setHtml(html) self.right_side_layout.addWidget(self.view) self.progressbar = QtGui.QProgressBar() self.progressbar.setMinimum(1) self.progressbar.setMaximum(100) self.left_side_layout.addWidget(self.progressbar) self.taskTreeView = QTreeView() self.taskTreeView.setMinimumWidth(400) self.model = QtGui.QStandardItemModel() self.taskTreeView.setModel(self.model) if self.session is not None: self.progressbar.setMinimum(self.session.root_task.pending()) self.progressbar.setMaximum(self.session.root_task.count()) silver_session.guess_total_time() def recAddTasks(task): me = QtGui.QStandardItem('{}'.format(task.name)) me.setData(task) if task.subtasks: for s in task.subtasks: me.appendRow(recAddTasks(s)) return me self.model.appendRow(recAddTasks(self.session.root_task)) self.taskTreeView.expandAll() #QtCore.QObject.connect(self.taskTreeView.selectionModel(), QtCore.SIGNAL('selectionChanged()'), self.test) self.left_side_layout.addWidget(self.taskTreeView) self.taskTreeView.clicked.connect(self.test) self.layout.addLayout(self.left_side_layout) self.layout.addStretch(1) self.layout.addLayout(self.right_side_layout) self.setLayout(self.layout) self.show() def test(self, index): ind = self.model.itemFromIndex(index) #print(ind.text()) task = ind.data() self.view.setHtml(task.to_html()) def run(self): # Show the form self.show() # Run the qt application qt_app.exec_()
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) finder.message.connect(self.message) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # create categories in special order and count activated ones for finder in self.finders.values(): if finder.activated(): self.resultModel.addResult(finder.name) bbox = self.mapCanvas.fullExtent() for finder in self.finders.values(): if finder.activated(): finder.start(toFind, bbox=bbox) def stop(self): for finder in self.finders.values(): if finder.isRunning(): finder.stop() def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def message(self, finder, message, level): self.iface.messageBar().pushMessage("Quick Finder", message, level, 3) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() return def transformGeom(self, item): geometry = item.geometry src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = item.geometry geom.transform( QgsCoordinateTransform(src_crs, dest_crs) ) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class DrEditWidget(QtGui.QWidget): """行情数据记录引擎管理组件""" signal = QtCore.pyqtSignal(type(Event())) def __init__(self, drWidget, mainEngine, eventEngine, parent=None): """Constructor""" super(DrEditWidget, self).__init__(parent) self.drWidget = drWidget self.mainEngine = mainEngine self.eventEngine = eventEngine self.hasChanged = False # 保存合约详细信息的字典 self.contractDict = {} self.initUi() self.updateSetting() self.loadData() self.registerEvent() def closeEvent(self, QCloseEvent): if self.hasChanged: self.drWidget.restart() def initUi(self): vbox = QtGui.QVBoxLayout() vline = QtGui.QHBoxLayout() vline.setSpacing(2) btnTickAll = QtGui.QPushButton(u"全部记录Tick", self) btnBarAll = QtGui.QPushButton(u'全部记录Bar', self) btnSaveAll = QtGui.QPushButton(u'保存设置(重启后生效)', self) btnTickAll.clicked.connect(self.selectAllTick) btnBarAll.clicked.connect(self.selectAllBar) btnSaveAll.clicked.connect(self.saveSetting) vline.addWidget(btnTickAll) vline.addWidget(btnBarAll) vline.addWidget(btnSaveAll) vbox.addLayout(vline) self.qTreeView = QTreeView() self.model = TreeModel() self.qTreeView.setModel(self.model) self.qTreeView.setSelectionMode(QtGui.QAbstractItemView.NoSelection) self.qTreeView.setItemDelegateForColumn(1, CheckBoxDelegate(self)) self.qTreeView.setItemDelegateForColumn(2, CheckBoxDelegate(self)) self.qTreeView.setItemDelegateForColumn(3, CheckBoxDelegate(self)) self.qTreeView.setItemDelegateForColumn(5, ComboDelegate(self, ["CTP", "LTS", "XTP", "FEMAS", "XSPEED", "QDP", "KSOTP", "KSGOLD", "SGIT"])) vbox.addWidget(self.qTreeView) self.setLayout(vbox) def getContractChineseName(self, str): line = str.strip().decode('utf-8', 'ignore') # 处理前进行相关的处理,包括转换成Unicode等 p2 = re.compile(ur'[^\u4e00-\u9fa5]') # 中文的编码范围是:\u4e00到\u9fa5 zh = " ".join(p2.split(line)).strip() zh = ",".join(zh.split()) outStr = zh # 经过相关处理后得到中文的文本 return outStr def loadData(self): child = [] tick = {} bar = {} active = [] with open(self.mainEngine.drEngine.settingFileName) as f: drSetting = json.load(f) if 'tick' in drSetting: l = drSetting['tick'] for setting in l: tick[setting[0]] = setting[1] if 'bar' in drSetting: l = drSetting['bar'] for setting in l: bar[setting[0]] = setting[1] if 'active' in drSetting: d = drSetting['active'] for activeSymbol, symbol in d.items(): active.append(symbol) contractDict = {} contracts = self.mainEngine.getAllContracts() for contract in contracts: contractName = self.getContractChineseName(contract.name) gateWayName = u"CTP" hasTick = tick.has_key(contract.symbol) hasBar = bar.has_key(contract.symbol) hasActive = contract.symbol in active if hasTick: gateWayName = tick[contract.symbol] elif hasBar: gateWayName = bar[contract.symbol] if contractDict.has_key(contractName): parentItem = contractDict[contractName] item = TreeItem([contract.symbol, hasTick, hasBar, hasActive, contract.exchange, gateWayName], parentItem) parentItem.appendChild(item) else: item = TreeItem([contractName, False, False, False, contract.exchange, gateWayName], self.model.rootItem) contractDict[contractName] = item child.append(item) subItem = TreeItem([contract.symbol, hasTick, hasBar, hasActive, contract.exchange, gateWayName], item) item.appendChild(subItem) # yumi = TreeItem([u"玉米", False, False, False, "SH", "CTP"], self.model.rootItem) # yumi.appendChild(TreeItem([u"c1705", False, False, False, "SH", "CTP"], yumi)) # yumi.appendChild(TreeItem([u"c1703", False, False, False, "SH", "CTP"], yumi)) # yumi.appendChild(TreeItem([u"c1707", False, False, False, "SH", "CTP"], yumi)) # yumi.appendChild(TreeItem([u"c1709", False, False, False, "SH", "CTP"], yumi)) # dianfen = TreeItem([u"淀粉", False, False, False, "SH", "CTP"], self.model.rootItem) # dianfen.appendChild(TreeItem([u"d1705", False, False, False, "SH", "CTP"], dianfen)) # dianfen.appendChild(TreeItem([u"d1703", False, False, False, "SH", "CTP"], dianfen)) # dianfen.appendChild(TreeItem([u"d1707", False, False, False, "SH", "CTP"], dianfen)) # dianfen.appendChild(TreeItem([u"d1709", False, False, False, "SH", "CTP"], dianfen)) # # child.append(yumi) # child.append(dianfen) self.model.setDataSource(child) self.qTreeView.expandAll() def saveSetting(self): setting = {} setting["tick"] = [] setting["bar"] = [] setting["active"] = {} queue = Queue() queue.put(self.model.rootItem) while queue.qsize() > 0: item = queue.get() for child in item.childItems: queue.put(child) if item.parentItem is not None and item.parentItem != self.model.rootItem: name = item.data(0) interface = item.data(5) if item.data(1): setting["tick"].append([name, interface]) if item.data(2): setting["bar"].append([name, interface]) if item.data(3): setting["active"][item.parentItem.data(0)] = name if self.mainEngine.drEngine.saveSetting(setting): self.hasChanged = True self.close() def selectAllTick(self): self.selectAll(True, False, True) def selectAllBar(self): self.selectAll(False, True, True) def selectAll(self, tick=False, bar=False, select=False): column = None if tick: column = 1 if bar: column = 2 for row in range(self.model.rootItem.childCount()): childIndex = self.model.index(row, column, None) self.model.setData(childIndex, QtCore.Qt.Unchecked if select == False else QtCore.Qt.Checked, QtCore.Qt.CheckStateRole) def updateSetting(self): pass def updateContract(self, event): """更新合约数据""" contract = event.dict_['data'] self.contractDict[contract.vtSymbol] = contract self.contractDict[contract.symbol] = contract # 使用常规代码(不包括交易所)可能导致重复 # ---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" self.signal.connect(self.updateContract) self.eventEngine.register(EVENT_CONTRACT, self.signal.emit)
class NavigatorDock(DockWidget): def __init__(self): DockWidget.__init__(self, core.mainWindow(), '&Navigator', QIcon(':/enkiicons/goto.png'), "Alt+N") self._tags = [] self._tree = QTreeView(self) self._tree.installEventFilter(self) self._tree.setHeaderHidden(True) self.setFocusProxy(self._tree) self._filterEdit = LineEdit(self) self._filterEdit.setClearButtonVisible(True) self._filterEdit.textEdited.connect(self._applyFilter) self._filterEdit.clearButtonClicked.connect(self._applyFilter) self._filterEdit.clearButtonClicked.connect(self._tree.setFocus) self._filterEdit.clearButtonClicked.connect(self._hideFilter) self._filterEdit.installEventFilter(self) self._displayWidget = QWidget(self) layout = QVBoxLayout(self._displayWidget) layout.addWidget(self._tree) layout.addWidget(self._filterEdit) layout.setContentsMargins(0, 0, 0, 0) self.setWidget(self._displayWidget) self._tagModel = _TagModel(self._tree) self._tagModel.jumpToTagDone.connect(self._hideFilter) self._tree.setModel(self._tagModel) self._tree.activated.connect(self._tagModel.onActivated) self._tree.clicked.connect(self._tagModel.onActivated) self._tagModel.modelAboutToBeReset.connect(self._onModelAboutToBeReset) self._tagModel.modelReset.connect(self._onModelReset) self._currentTagPath = None self._errorLabel = None self._installed = False def install(self): if not self._installed: core.mainWindow().addDockWidget(Qt.RightDockWidgetArea, self) core.actionManager().addAction("mView/aNavigator", self.showAction()) self._installed = True def remove(self): if self._installed: core.mainWindow().removeDockWidget(self) core.actionManager().removeAction("mView/aNavigator") self.hide() self._installed = False def setTags(self, tags): self._tags = tags self._setFilteredTags(tags) self._hideFilter() if self.widget() is not self._displayWidget: self.setWidget(self._displayWidget) self._displayWidget.show() if self._errorLabel is not None: self._errorLabel.hide() def _setFilteredTags(self, tags): self._tagModel.setTags(tags) def onError(self, error): self._displayWidget.hide() if self._errorLabel is None: self._errorLabel = QLabel(self) self._errorLabel.setWordWrap(True) self._errorLabel.setText(error) if not self.widget() is self._errorLabel: self.setWidget(self._errorLabel) self._errorLabel.show() self._displayWidget.hide() def _onModelAboutToBeReset(self): currIndex = self._tree.currentIndex() self._currentTagPath = self._tagModel.tagPathForIndex( currIndex) if currIndex.isValid() else None def _onModelReset(self): self._tree.expandAll() # restore current item if self._currentTagPath is not None: index = self._tagModel.indexForTagPath(self._currentTagPath) if index.isValid(): self._tree.setCurrentIndex(index) def eventFilter(self, object_, event): if object_ is self._tree: if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Backspace: if event.modifiers() == Qt.ControlModifier: self._onTreeCtrlBackspace() else: self._onTreeBackspace() return True elif event.text() and \ (event.text().isalnum() or event.text() == '_'): self._onTreeTextTyped(event.text()) return True elif object_ is self._filterEdit: if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Up, Qt.Key_Down): self._tree.setFocus() self._tree.event(event) return True elif event.key() in (Qt.Key_Enter, Qt.Key_Return): currIndex = self._tree.currentIndex() if currIndex.isValid(): self._tagModel.onActivated(currIndex) return DockWidget.eventFilter(self, object_, event) def _hideFilter(self): hadText = self._filterEdit.text() != '' self._filterEdit.clear() self._filterEdit.hide() if hadText: self._applyFilter() def _applyFilter(self): text = self._filterEdit.text() if text: if not text.startswith('*'): text = '*' + text if not text.endswith('*'): text = text + '*' wildcard = text.lower() filteredTags = _filterTags(wildcard, self._tags) self._setFilteredTags(filteredTags) self._tree.expandAll() if filteredTags: firstMatchingTag = _findFirstMatching(wildcard, filteredTags) path = _tagPath(firstMatchingTag) index = self._tagModel.indexForTagPath(path) self._tree.setCurrentIndex(index) else: self._setFilteredTags(self._tags) if text: self._filterEdit.show() elif not self._filterEdit.hasFocus(): self._hideFilter() def _onTreeTextTyped(self, text): self._filterEdit.setText(self._filterEdit.text() + text) self._applyFilter() def _onTreeBackspace(self): text = self._filterEdit.text() if text: self._filterEdit.setText(text[:-1]) self._applyFilter() def _onTreeCtrlBackspace(self): self._hideFilter() self._applyFilter()
class Lectern(QMainWindow): def __init__(self, parent=None): super(Lectern, self).__init__(parent) self.anchor = None self.initMainMenu() self.initToolbar() splitter = QSplitter() self.tocView = QTreeView() self.tocView.clicked.connect(self.navTo) self.tocModel = TableOfContents() self.tocModel.isEmpty.connect(self.handleTOCLoad) self.tocView.setModel(self.tocModel) self.tocView.expandAll() self.tocView.hide() splitter.addWidget(self.tocView) self.webView = QGraphicsWebView() frame = self.webView.page().mainFrame() scene = QGraphicsScene() scene.addItem(self.webView) self.graphicsView = GraphicsView(scene) self.graphicsView.setFrameShape(QFrame.NoFrame) glWidget = QGLWidget(self) self.graphicsView.setViewport(glWidget) self.webView.loadFinished.connect(self.handleLoad) splitter.addWidget(self.graphicsView) self.setCentralWidget(splitter) self.ebook_info = {} self.setWindowTitle('Lectern') try: self.ebook_info = self.openBook(QApplication.arguments()[1]) except IndexError: pass def initMainMenu(self): menuBar = self.menuBar() menuBar.setNativeMenuBar(True) # TODO: add CROSS-PLATFORM shortcut keys. (e.g. For Quit, use ⌘Q on Mac OS X, ALT-F4 elsewhere) fileMenu = QMenu('File', menuBar) navMenu = QMenu('Navigate', menuBar) # File Menu openAction = QAction('Open', fileMenu) openAction.triggered.connect(self.chooseEbook) fileMenu.addAction(openAction) quitAction = QAction('Quit', fileMenu) quitAction.triggered.connect(self.closeEvent) fileMenu.addAction(quitAction) # Nav Menu prevChatperAction = QAction('Previous Chapter', navMenu) prevChatperAction.triggered.connect(self.prevChapter) navMenu.addAction(prevChatperAction) nextChatperAction = QAction('Next Chapter', navMenu) nextChatperAction.triggered.connect(self.nextChapter) navMenu.addAction(nextChatperAction) menuBar.addMenu(fileMenu) menuBar.addMenu(navMenu) def initToolbar(self): toolBar = QToolBar(self) chooseAction = QAction(self.style().standardIcon( QStyle.SP_DialogOpenButton), 'Open', toolBar) chooseAction.triggered.connect(self.chooseEbook) toolBar.addAction(chooseAction) self.prevAction = QAction(self.style().standardIcon( QStyle.SP_ArrowBack), 'Go back', toolBar) self.prevAction.setEnabled(False) self.prevAction.triggered.connect(self.prevChapter) toolBar.addAction(self.prevAction) self.nextAction = QAction(self.style().standardIcon( QStyle.SP_ArrowForward), 'Go forward', toolBar) self.nextAction.setEnabled(False) self.nextAction.triggered.connect(self.nextChapter) toolBar.addAction(self.nextAction) self.addToolBar(toolBar) def chooseEbook(self): path = QFileDialog.getOpenFileName(self, 'Open eBook', QDesktopServices.storageLocation( QDesktopServices.DocumentsLocation),'EPUBs (*.epub)') if not isfile(path): return if self.ebook_info is not None and 'temp_path' in self.ebook_info: if exists(self.ebook_info['temp_path']): rmtree(self.ebook_info['temp_path']) path = QDir.toNativeSeparators(path) self.ebook_info = self.openBook(path) def openBook(self, path): ebook_info = {} path = realpath(path) if not isfile(path): QMessageBox.critical(self, 'File not found', 'File not found') mimetype, _ = guess_type(path) if mimetype != 'application/epub+zip': QMessageBox.critical(self, 'Not an EPUB', 'Not an EPUB') return None ebook = ZipFile(path) names = ebook.namelist() if not 'META-INF/container.xml' in names: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'container.xml not '\ 'found') return None container_tree = etree.parse(ebook.open('META-INF/container.xml')) rootfile = container_tree.xpath("//*[local-name() = 'rootfile']") if len(rootfile) == 0: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'root not found in '\ 'manifest') return None content_opf = rootfile[0].get('full-path') if content_opf is None: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'content.opf not found') return None ebook_info['opf_root'] = posixpath.dirname(content_opf) tree = etree.parse(ebook.open(content_opf)) manifest = tree.xpath("*[local-name() = 'manifest']") if len(manifest) == 0: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Manifest not found') return None manifest = manifest[0] items = {} for item in manifest: item_id = item.get('id') if item_id is None: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Item has no id') return None href = item.get('href') if href is None: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Item has no href') return None items[item_id] = href spine = tree.xpath("*[local-name() = 'spine']") if len(spine) == 0: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Spine not found') return None spine = spine[0] ebook_info['chapters'] = [] for itemref in spine: idref = itemref.get('idref') if not idref in items: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Item in spine '\ 'not found in manifest') return None ebook_info['chapters'].append(items[idref]) if len(ebook_info['chapters']) == 0: ebook.close() QMessageBox.critical(self, 'Invalid EPUB', 'Content not found') return None # Table of contents toc = tree.find("//*[@href='toc.ncx']") if toc is not None: toc_path = posixpath.join(ebook_info['opf_root'], 'toc.ncx') if toc_path in names: toc_tree = etree.parse(ebook.open(toc_path)) navMap = toc_tree.xpath("//*[local-name() = 'navMap']") if len(navMap) > 0: self.tocModel.importNavMap(navMap[0]) temp = QDir.toNativeSeparators(QDesktopServices.storageLocation( QDesktopServices.TempLocation)) # In case we have two copies of Lectern opening the same book. filename = '{0}-{1}'.format(splitext(basename(path))[0], uuid4()) ebook_info['temp_path'] = join(temp, filename) if exists(ebook_info['temp_path']): rmtree(ebook_info['temp_path']) ebook.extractall(ebook_info['temp_path']) ebook.close() ebook_info['index'] = 0 url = join(ebook_info['temp_path'], ebook_info['opf_root'], ebook_info['chapters'][0]) self.webView.setUrl(QUrl(url)) if len(ebook_info['chapters']) > 1: self.nextAction.setEnabled(True) return ebook_info def prevChapter(self): index = self.ebook_info['index'] chapters = self.ebook_info['chapters'] if index > 0: index -= 1 if index == 0: self.prevAction.setEnabled(False) url = join(self.ebook_info['temp_path'], self.ebook_info['opf_root'], chapters[index]) self.webView.setUrl(QUrl(url)) self.ebook_info['index'] = index self.nextAction.setEnabled(True) def nextChapter(self): index = self.ebook_info['index'] chapters = self.ebook_info['chapters'] if index < len(chapters) - 1: index += 1 if index == len(chapters) - 1: self.nextAction.setEnabled(False) url = join(self.ebook_info['temp_path'], self.ebook_info['opf_root'], chapters[index]) self.webView.setUrl(QUrl(url)) self.ebook_info['index'] = index self.prevAction.setEnabled(True) def closeBook(self): if self.ebook_info is not None and 'temp_path' in self.ebook_info: if exists(self.ebook_info['temp_path']): rmtree(self.ebook_info['temp_path']) self.ebook_info = None self.tocView.hide() self.prevAction.setEnabled(False) self.nextAction.setEnabled(False) def closeEvent(self, event = 0): if(event == 0): event = PyQt4.QtGui.QCloseEvent() self.closeBook() super(Lectern, self).closeEvent(event) # Suppress "cannot make invalid context current" warnings sys.exit(0) def navTo(self, index): navPoint = index.internalPointer() href = posixpath.join(self.ebook_info['temp_path'], self.ebook_info['opf_root'], navPoint.src) try: path, anchor = href.split('#') if path == self.webView.url().path(): self.webView.page().mainFrame().scrollToAnchor(anchor) return else: self.anchor = anchor except ValueError: pass url = QUrl.fromEncoded(href) self.webView.setUrl(url) def handleLoad(self, ok): if self.anchor is not None: self.webView.page().mainFrame().addToJavaScriptWindowObject("app", self); self.webView.page().mainFrame().scrollToAnchor(self.anchor) def handleTOCLoad(self, isEmpty): if isEmpty: self.tocView.hide() else: self.tocView.show()