class SelectionToolBar(BaseToolBar): selectAllTriggered = QtCore.Signal() clearSelectionTriggered = QtCore.Signal() def __init__(self, view=None, parent=None, designMode=False): BaseToolBar.__init__(self, name="Selection toolbar", view=view, parent=parent, designMode=designMode) self._selectAllAction = Action("Select All", parent=self, icon=getIcon("edit-select-all"), tooltip="Select all items", triggered=self.onSelectAll) self._clearSelectionAction = Action("Clear selection", parent=self, icon=getIcon("edit-clear"), tooltip="Clears current selection", triggered=self.onclearSelection) self.addAction(self._selectAllAction) self.addAction(self._clearSelectionAction) def onSelectAll(self): self.selectAllTriggered.emit() def onclearSelection(self): self.clearSelectionTriggered.emit()
class ExpansionBar(BaseToolBar): expandTriggered = QtCore.Signal() collapseTriggered = QtCore.Signal() expandSelectionTriggered = QtCore.Signal() collapseSelectionTriggered = QtCore.Signal() def __init__(self, view=None, parent=None): BaseToolBar.__init__(self, name="Taurus selection toolbar", view=view, parent=parent) self._expandAllAction = getAction( "Expand All", parent=self, icon=getIcon(":/controls/expand.png"), tooltip="Expand all items", triggered=self.onExpandAll) self._collapseAllAction = getAction( "Collapse All", parent=self, icon=getIcon(":/controls/collapse.png"), tooltip="Collapse all items", triggered=self.onCollapseAll) self._expandSelectionAction = getAction( "Expand selection", parent=self, icon=getIcon(":/controls/expand-selection.png"), tooltip="Expand selection", triggered=self.onExpandSelection) self._collapseSelectionAction = getAction( "Collapse All", parent=self, icon=getIcon(":/controls/collapse-selection.png"), tooltip="Collapse selection", triggered=self.onCollapseSelection) self.addAction(self._expandAllAction) self.addAction(self._collapseAllAction) self.addAction(self._expandSelectionAction) self.addAction(self._collapseSelectionAction) def onExpandAll(self): self.expandTriggered.emit() def onCollapseAll(self): self.collapseTriggered.emit() def onExpandSelection(self): self.expandSelectionTriggered.emit() def onCollapseSelection(self): self.collapseSelectionTriggered.emit()
class NavigationToolBar(BaseToolBar): goIntoTriggered = QtCore.Signal() goUpTriggered = QtCore.Signal() goTopTriggered = QtCore.Signal() def __init__(self, view=None, parent=None): BaseToolBar.__init__(self, name="Taurus selection toolbar", view=view, parent=parent) self._goIntoAction = getAction("Go Into", parent=self, icon=getIcon("go-down"), tooltip="Go into the selected item", triggered=self.goInto) self._goUpAction = getAction("Go Up", parent=self, icon=getIcon("go-up"), tooltip="Go up one level", triggered=self.goUp) self._goTopAction = getAction("Go Top", parent=self, icon=getIcon("go-top"), tooltip="Go to top level", triggered=self.goTop) self.addAction(self._goIntoAction) self.addAction(self._goUpAction) self.addAction(self._goTopAction) self._navigationWidget = _NavigationWidget(view, self, parent=self) self._navigationAction = self.addWidget(self._navigationWidget) def goIntoAction(self): return self._goIntoAction def goTopAction(self): return self._goTopAction def goUpAction(self): return self._goUpAction def goInto(self): self.goIntoTriggered.emit() def goUp(self): self.goUpTriggered.emit() def goTop(self): self.goTopTriggered.emit()
class FilterToolBar(BaseToolBar): """Internal widget providing quick filter to be placed in a _QToolArea""" clearFilterTriggered = QtCore.Signal() filterChanged = QtCore.Signal(str) filterEdited = QtCore.Signal(str) def __init__(self, view=None, parent=None, designMode=False): BaseToolBar.__init__(self, name="Filter toolbar", view=view, parent=parent, designMode=designMode) filterLineEdit = self._filterLineEdit = QtGui.QLineEdit(self) filterLineEdit.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)) filterLineEdit.setToolTip("Quick filter") filterLineEdit.textChanged.connect(self.onFilterChanged) filterLineEdit.textEdited.connect(self.onFilterEdited) self.addWidget(filterLineEdit) self._clearFilterAction = Action("Clear", parent=self, icon=getIcon("edit-clear"), tooltip="Clears the filter", triggered=self.onClearFilter) self.addAction(self._clearFilterAction) def getFilterLineEdit(self): return self._filterLineEdit def onClearFilter(self): self.getFilterLineEdit().setText("") self.clearFilterTriggered.emit() def onFilterChanged(self, text=None): text = text or self.getFilterLineEdit().text() self.filterChanged.emit(text) def onFilterEdited(self, text=None): text = text or self.getFilterLineEdit().text() self.filterEdited.emit(text) def setFilterText(self, text): self.getFilterLineEdit().setText(text)
class PerspectiveToolBar(BaseToolBar): perspectiveChanged = QtCore.Signal(str) def __init__(self, perspective, view=None, parent=None, designMode=False): BaseToolBar.__init__(self, name="Perspective toolbar", view=view, parent=parent, designMode=designMode) self._perspective = perspective view = self.viewWidget() b = self._perspective_button = QtGui.QToolButton(self) b.setToolTip("Perspective selection") b.setPopupMode(QtGui.QToolButton.InstantPopup) b.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) menu = QtGui.QMenu("Perspective", b) b.setMenu(menu) for persp, persp_data in view.KnownPerspectives.items(): label = persp_data["label"] icon = QtGui.QIcon(persp_data["icon"]) tooltip = persp_data["tooltip"] action = Action(label, parent=self, icon=icon, tooltip=tooltip, triggered=self.onSwitchPerspective) action.perspective = persp menu.addAction(action) if persp == perspective: b.setDefaultAction(action) self._perspectiveAction = self.addWidget(b) def switchPerspectiveButton(self): """Returns the QToolButton that handles the switch perspective. :return: (PyQt4.QtGui.QToolButton) the switch perspective tool button """ return self._perspective_button def onSwitchPerspective(self): action = self.sender() self._perspective = action.perspective self._perspective_button.setDefaultAction(action) self.perspectiveChanged.emit(action.perspective) def perspective(self): return self._perspective
class __Grabber(QtCore.QObject): grab = QtCore.Signal() def __init__(self, widget, fileName): QtCore.QObject.__init__(self) self.__widget = widget self.__fileName = fileName self.grab.connect(self.__onGrab) def grabTrigger(self): self.grab.emit() def __onGrab(self): grabWidget(self._widget, self._fileName)
class RefreshToolBar(BaseToolBar): refreshTriggered = QtCore.Signal() def __init__(self, view=None, parent=None, designMode=False): BaseToolBar.__init__(self, name="Refresh toolbar", view=view, parent=parent, designMode=designMode) self._refreshAction = Action("Refresh", parent=self, icon=getIcon("view-refresh"), tooltip="Refresh view", triggered=self.onRefresh) self.addAction(self._refreshAction) def onRefresh(self): self.refreshTriggered.emit()
class PixmapWidget(QtGui.QWidget): """This widget displays an image (pixmap). By default the pixmap is scaled to the widget size and the aspect ratio is kept. The default alignment of the pixmap inside the widget space is horizontal left, vertical center.""" DefaultAlignment = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter DefaultAspectRatioMode = QtCore.Qt.KeepAspectRatio DefaultTransformationMode = QtCore.Qt.SmoothTransformation #: Signal emited when pixmap source changes pixmapChanged = QtCore.Signal() def __init__(self, parent=None): self._pixmap = QtGui.QPixmap() self._pixmapDrawn = None self._alignment = self.DefaultAlignment self._pixmapAspectRatioMode = self.DefaultAspectRatioMode self._pixmapTransformationMode = self.DefaultTransformationMode QtGui.QWidget.__init__(self, parent) def _getPixmap(self): if self._pixmapDrawn is None: self._pixmapDrawn = self.recalculatePixmap() return self._pixmapDrawn def recalculatePixmap(self): origPixmap = self._pixmap if origPixmap.isNull(): return origPixmap return origPixmap.scaled(self.size(), self._pixmapAspectRatioMode, self._pixmapTransformationMode) def _setDirty(self): self._pixmapDrawn = None def paintEvent(self, paintEvent): """Overwrite the paintEvent from QWidget to draw the pixmap""" pixmap = self._getPixmap() w, h = self.width(), self.height() painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.Antialiasing) pw, ph = pixmap.width(), pixmap.height() align = self._alignment hAlign = align & QtCore.Qt.AlignHorizontal_Mask vAlign = align & QtCore.Qt.AlignVertical_Mask x, y = 0, 0 if hAlign & QtCore.Qt.AlignHCenter: x = (w - pw) / 2 elif hAlign & QtCore.Qt.AlignRight: x = w - pw if vAlign & QtCore.Qt.AlignVCenter: y = (h - ph) / 2 elif vAlign & QtCore.Qt.AlignBottom: y = h - ph x, y = max(0, x), max(0, y) painter.drawPixmap(x, y, pixmap) def resizeEvent(self, event): self._setDirty() return QtGui.QWidget.resizeEvent(self, event) def sizeHint(self): return self._pixmap.size() #-------------------------------------------------------------------------- # QT property definition #-------------------------------------------------------------------------- def getPixmap(self): """Returns the pixmap.Returns None if no pixmap is set. :return: the current pixmap :rtype: QtGui.QPixmap""" return self._pixmap def setPixmap(self, pixmap): """Sets the pixmap for this widget. Setting it to None disables pixmap :param pixmap: the new pixmap :type pixmap: QtGui.QPixmap""" # make sure to make a copy because of bug in PyQt 4.4. This is actually # not copying the internal bitmap, just the qpixmap, so there is no # performance penalty here self._pixmap = QtGui.QPixmap(pixmap) self._setDirty() self.update() self.pixmapChanged.emit() def resetPixmap(self): """Resets the pixmap for this widget.""" self.setPixmap(QtGui.QPixmap()) def getAspectRatioMode(self): """Returns the aspect ratio to apply when drawing the pixmap. :return: the current aspect ratio :rtype: QtCore.Qt.AspectRatioMode""" return self._pixmapAspectRatioMode def setAspectRatioMode(self, aspect): """Sets the aspect ratio mode to apply when drawing the pixmap. :param pixmap: the new aspect ratio mode :type pixmap: QtCore.Qt.AspectRatioMode""" self._pixmapAspectRatioMode = aspect self._setDirty() self.update() def resetAspectRatioMode(self): """Resets the aspect ratio mode to KeepAspectRatio""" self.setAspectRatioMode(self.DefaultAspectRatioMode) def getTransformationMode(self): """Returns the transformation mode to apply when drawing the pixmap. :return: the current transformation mode :rtype: QtCore.Qt.TransformationMode""" return self._pixmapTransformationMode def setTransformationMode(self, transformation): """Sets the transformation mode to apply when drawing the pixmap. :param pixmap: the new transformation mode :type pixmap: QtCore.Qt.TransformationMode""" self._pixmapTransformationMode = transformation self._setDirty() self.update() def resetTransformationMode(self): """Resets the transformation mode to SmoothTransformation""" self.setTransformationMode(self.DefaultTransformationMode) def getAlignment(self): """Returns the alignment to apply when drawing the pixmap. :return: the current alignment :rtype: QtCore.Qt.Alignment""" return self._alignment def setAlignment(self, alignment): """Sets the alignment to apply when drawing the pixmap. :param pixmap: the new alignment :type pixmap: QtCore.Qt.Alignment""" self._alignment = alignment self.update() def resetAlignment(self): """Resets the transformation mode to QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter""" self.setAlignment(self.DefaultAlignment) #: This property holds the widget's pixmap #: #: **Access functions:** #: #: * :meth:`PixmapWidget.getPixmap` #: * :meth:`PixmapWidget.setPixmap` #: * :meth:`PixmapWidget.resetPixmap` pixmap = QtCore.Property("QPixmap", getPixmap, setPixmap, resetPixmap, doc="the widget's pixmap") #: This property holds the widget's pixmap aspect ratio mode #: #: **Access functions:** #: #: * :meth:`PixmapWidget.getAspectRatioMode` #: * :meth:`PixmapWidget.setAspectRatioMode` #: * :meth:`PixmapWidget.resetAspectRatioMode` aspectRatioMode = QtCore.Property("Qt::AspectRatioMode", getAspectRatioMode, setAspectRatioMode, resetAspectRatioMode, doc="the widget's pixmap aspect ratio "\ "mode") #: This property holds the widget's pixmap transformation mode #: #: **Access functions:** #: #: * :meth:`PixmapWidget.getTransformationMode` #: * :meth:`PixmapWidget.setTransformationMode` #: * :meth:`PixmapWidget.resetTransformationMode` transformationMode = QtCore.Property("Qt::TransformationMode", getTransformationMode, setTransformationMode, resetTransformationMode, doc="the widget's pixmap "\ "transformation mode") #: This property holds the widget's pixmap alignment #: #: **Access functions:** #: #: * :meth:`PixmapWidget.getAlignment` #: * :meth:`PixmapWidget.setAlignment` #: * :meth:`PixmapWidget.resetAlignment` alignment = QtCore.Property("Qt::Alignment", getAlignment, setAlignment, resetAlignment, doc="the widget's pixmap alignment")
class EditorToolBar(BaseToolBar): """Internal widget to be placed in a _QToolArea providing buttons for moving, adding and removing items from a view based widget""" addTriggered = QtCore.Signal() removeTriggered = QtCore.Signal() moveTopTriggered = QtCore.Signal() moveUpTriggered = QtCore.Signal() moveDownTriggered = QtCore.Signal() moveBottomTriggered = QtCore.Signal() def __init__(self, view=None, parent=None, designMode=False): BaseToolBar.__init__(self, name="Editor toolbar", view=view, parent=parent, designMode=designMode) self._addAction = Action("New item", parent=self, icon=getIcon("list-add"), tooltip="Add new item", triggered=self.onAdd) self._removeAction = Action("Remove item", parent=self, icon=getIcon("list-remove"), tooltip="Remove item", triggered=self.onRemove) self._moveTopAction = Action("To top", parent=self, icon=getIcon("go-top"), tooltip="Move selected item to top", triggered=self.onMoveTop) self._moveUpAction = Action("Move up", parent=self, icon=getIcon("go-up"), tooltip="Move selected item up one level", triggered=self.onMoveUp) self._moveDownAction = Action( "Move down", parent=self, icon=getIcon("go-down"), tooltip="Move selected item down one level", triggered=self.onMoveDown) self._moveBottomAction = Action("To bottom", parent=self, icon=getIcon("go-bottom"), tooltip="Move selected item to bottom", triggered=self.onMoveBottom) self.addAction(self._addAction) self.addAction(self._removeAction) self.addAction(self._moveTopAction) self.addAction(self._moveUpAction) self.addAction(self._moveDownAction) self.addAction(self._moveBottomAction) def onAdd(self): self.addTriggered.emit() def onRemove(self): self.removeTriggered.emit() def onMoveTop(self): self.moveTopTriggered.emit() def onMoveUp(self): self.moveUpTriggered.emit() def onMoveDown(self): self.moveDownTriggered.emit() def onMoveBottom(self): self.moveBottomTriggered.emit()
class BaseModelWidget(QtGui.QMainWindow): """A pure Qt widget designed to display a Qt view widget (QTreeView for example), envolved by optional toolbar and statusbar. The Qt model associated with the internal Qt view widget should be a :class:`Framework4.GUI.Qt.Model.BaseModel`""" KnownPerspectives = {} DftPerspective = None itemClicked = QtCore.Signal(object, int) itemDoubleClicked = QtCore.Signal(object, int) itemSelectionChanged = QtCore.Signal() currentItemChanged = QtCore.Signal(object, object) def __init__(self, parent=None, designMode=False, with_filter_widget=True, with_selection_widget=True, with_refresh_widget=True, perspective=None, proxy=None): QtGui.QMainWindow.__init__(self, parent) self.setWindowFlags(QtCore.Qt.Widget) self._baseQModel = None self._toolBars = [] if with_filter_widget: if isinstance(with_filter_widget, (bool, int)): self._with_filter_widget = FilterToolBar else: self._with_filter_widget = with_filter_widget else: self._with_filter_widget = None if with_selection_widget: if isinstance(with_selection_widget, (bool, int)): self._with_selection_widget = SelectionToolBar else: self._with_selection_widget = with_selection_widget else: self._with_selection_widget = None if with_refresh_widget: if isinstance(with_refresh_widget, (bool, int)): self._with_refresh_widget = RefreshToolBar else: self._with_refresh_widget = with_refresh_widget else: self._with_refresh_widget = None self._proxyModel = proxy toolBars = self.createToolArea() self._viewWidget = self.createViewWidget() statusbar = self.createStatusBar() for toolBar in toolBars: #toolBar.addSeparator() self.addToolBar(toolBar) self.setContentsMargins(0, 0, 0, 0) self.setCentralWidget(self._viewWidget) self.setStatusBar(statusbar) if perspective is None: perspective = self.DftPerspective if len(self.KnownPerspectives) > 1: p_bar = self._perspectiveBar = PerspectiveToolBar(perspective, view=self, parent=self) p_bar.perspectiveChanged.connect(self.onSwitchPerspective) self.addToolBar(p_bar) else: self._perspectiveBar = None self._setPerspective(perspective) def createViewWidget(self, klass=None): raise NotImplementedError def createStatusBar(self): sb = QtGui.QStatusBar() sb.setSizeGripEnabled(False) return sb def createToolArea(self): tb = [] # tb = self._toolArea = QToolArea(self) if self._with_filter_widget: f_bar = self._filterBar = self._with_filter_widget(view=self, parent=self) f_bar.filterChanged.connect(self.onFilterChanged) tb.append(f_bar) else: self._filterBar = None if self._with_selection_widget: s_bar = self._selectionBar = self._with_selection_widget( view=self, parent=self) s_bar.selectAllTriggered.connect(self.onSelectAll) s_bar.clearSelectionTriggered.connect(self.onClearSelection) tb.append(s_bar) else: self._selectionBar = None if self._with_refresh_widget: r_bar = self._refreshBar = self._with_refresh_widget(view=self, parent=self) r_bar.refreshTriggered.connect(self.onRefreshModel) tb.append(r_bar) else: self._refreshBar = None return tb def getPerspectiveBar(self): return self._perspectiveBar def getFilterBar(self): return self._filterBar def getSelectionBar(self): return self._selectionBar def getRefreshBar(self): return self._refreshBar def onRefreshModel(self): self.getQModel().refresh() def onSelectAll(self): view = self.viewWidget() view.selectAll() def onClearSelection(self): view = self.viewWidget() view.clearSelection() def _onClicked(self, index): '''Emits an "itemClicked" signal with with the clicked item and column as arguments''' item = self._mapToSource(index).internalPointer() self.itemClicked.emit(item, index.column()) def _onDoubleClicked(self, index): '''Emits an "itemDoubleClicked" signal with the clicked item and column as arguments''' item = self._mapToSource(index).internalPointer() self.itemDoubleClicked.emit(item, index.column()) def viewWidget(self): return self._viewWidget def getQModel(self): return self.viewWidget().model() def getBaseQModel(self): return self._baseQModel def usesProxyQModel(self): return isinstance(self.getQModel(), QtGui.QAbstractProxyModel) def _mapToSource(self, index): if not self.usesProxyQModel(): return index model = self.getQModel() while isinstance(model, QtGui.QAbstractProxyModel): index = model.mapToSource(index) model = model.sourceModel() return index def setQModel(self, qmodel): self._baseQModel = qmodel while isinstance(self._baseQModel, QtGui.QAbstractProxyModel): self._baseQModel = self._baseQModel.sourceModel() view = self.viewWidget() old_smodel = view.selectionModel() if old_smodel is not None: old_smodel.currentChanged.disconnect(self.viewCurrentIndexChanged) old_smodel.selectionChanged.disconnect(self.viewSelectionChanged) view.setModel(qmodel) new_smodel = view.selectionModel() if new_smodel is not None: new_smodel.currentChanged.connect(self.viewCurrentIndexChanged) new_smodel.selectionChanged.connect(self.viewSelectionChanged) view.setCurrentIndex(view.rootIndex()) self._updateToolBar() def viewSelectionChanged(self, selected, deselected): self.itemSelectionChanged.emit() def viewCurrentIndexChanged(self, current, previous): # if there is a proxy model we have to translate the selection base_current = self._mapToSource(current) base_previous = self._mapToSource(previous) self._updateToolBar(current) if base_current.isValid(): currentTreeItem = base_current.internalPointer() else: currentTreeItem = None if base_previous.isValid(): previousTreeItem = base_previous.internalPointer() else: previousTreeItem = None self.currentItemChanged.emit(currentTreeItem, previousTreeItem) def _updateToolBar(self, current=None, previous=None): pass def selectedItems(self): """Returns a list of all selected non-hidden items :return: (list<BaseTreeItem>) """ view = self.viewWidget() return [ self._mapToSource(index).internalPointer() for index in view.selectedIndexes() ] def onFilterChanged(self, new_filter): if not self.usesProxyQModel(): return proxy_model = self.getQModel() if len(new_filter) > 0 and new_filter[0] != '^': new_filter = '^' + filter proxy_model.setFilterRegExp(new_filter) #proxy_model.setFilterFixedString(filter) #proxy_model.setFilterWildcard(filter) #self.update() def refresh(self): self.getQModel().refresh() #-------------------------------------------------------------------------- # Perspective handling #-------------------------------------------------------------------------- def perspective(self): return self._perspectiveBar.perspective() def onSwitchPerspective(self, perspective): old_qmodel = self.getQModel() self._setPerspective(perspective) #set the selectables as they where in the previous model if hasattr(old_qmodel, "selectables"): self.getQModel().setSelectables(old_qmodel.selectables()) #set the taurus model (if any) to the qmodel if hasattr(self, 'getModelObj'): taurusModel = self.getModelObj() if taurusModel is not None: self.getQModel().setDataSource(taurusModel) def _setPerspective(self, perspective): qmodel_classes = self.KnownPerspectives[perspective]["model"] qmodel_class = qmodel_classes[-1] qmodel_proxy_classes = qmodel_classes[-2::-1] # reversed qmodel = qmodel_class(self) qmodel_source = qmodel if self._proxyModel is None: # applies the chain of proxies for qmodel_proxy_class in qmodel_proxy_classes: qproxy = qmodel_proxy_class(self) qproxy.setSourceModel(qmodel_source) qmodel_source = qproxy else: self._proxyModel.setSourceModel(qmodel_source) qmodel_source = self._proxyModel self.setQModel(qmodel_source) #-------------------------------------------------------------------------- # QMainWindow overwriting #-------------------------------------------------------------------------- def addToolBar(self, toolbar): QtGui.QMainWindow.addToolBar(self, toolbar) self._toolBars.append(toolbar) def insertToolBar(self, before, toolbar): if isinstance(before, QtGui.QToolBar): index = self._toolBars.index(before) else: index = before before = self._toolBars[before] QtGui.QMainWindow.insertToolBar(self, before, toolbar) self._toolBars.insert(index, toolbar)
class ErrorWidget(QtGui.QWidget): """A panel intended to display an error. Example:: l = [1, 2, 3] try: print(l[3]) except IndexError: msgbox = ErrorWidget() msgbox.show() You can show the error outside the exception handling code. If you do this, you should keep a record of the exception information as given by :func:`sys.exc_info`:: l = [1, 2, 3] exc_info = None try: print(l[3]) except IndexError: exc_info = sys.exc_info() if exc_info: msgbox = ErrorWidget(*exc_info) msgbox.show()""" toggledDetails = QtCore.Signal(bool) def __init__(self, err_type=None, err_value=None, err_traceback=None, parent=None): QtGui.QWidget.__init__(self, parent) if err_type is None and err_value is None and err_traceback is None: err_type, err_value, err_traceback = sys.exc_info()[:3] self._exc_info = err_type, err_value, err_traceback ui_file_name = os.path.join(os.path.dirname(__file__), "ui", "errorpanel.ui") uic.loadUi(ui_file_name, baseinstance=self) self.detailsWidget.setVisible(False) self.checkBox.setVisible(False) self.checkBox.setCheckState(QtCore.Qt.Unchecked) self._initReportCombo() self.showDetailsButton.toggled.connect(self._onShowDetails) self.reportComboBox.activated.connect(self._onReportTriggered) self.setIcon(Icon("emblem-important")) if err_value is not None: self.setError(*self._exc_info) self.adjustSize() def _initReportCombo(self): report_handlers = get_report_handlers() combo = self.reportComboBox for name, report_handler in report_handlers.items(): combo.addItem(report_handler.Label, name) def _onReportTriggered(self, index): report_handlers = get_report_handlers() combo = self.reportComboBox name = combo.itemData(index) report_handler = report_handlers[name] report = report_handler(self) app = Application() txt = _REPORT.format(appName=app.applicationName(), appVersion=app.applicationVersion(), time=datetime.datetime.now().ctime(), text=self.getText(), detail=self.getDetailedText(), origin=self.getOriginText()) report.report(txt) def _onShowDetails(self, show): self.detailsWidget.setVisible(show) if show: text = "Hide details..." else: text = "Show details..." self.showDetailsButton.setText(text) self.adjustSize() self.toggledDetails.emit(show) def checkBoxState(self): """Returns the check box state :return: the check box state :rtype: PyQt4.Qt.CheckState""" return self.checkBox.checkState() def checkBoxText(self): """Returns the check box text :return: the check box text :rtype: str""" return str(self.checkBox.text()) def setCheckBoxText(self, text): """Sets the checkbox text. :param text: new checkbox text :type text: str""" self.checkBox.setText(text) def setCheckBoxState(self, state): """Sets the checkbox state. :param text: new checkbox state :type text: PyQt4.Qt.CheckState""" self.checkBox.setCheckState(state) def setCheckBoxVisible(self, visible): """Sets the checkbox visibility. :param visible: True makes checkbox visible, False hides it :type visible: bool""" self.checkBox.setVisible(visible) def addButton(self, button, role=QtGui.QDialogButtonBox.ActionRole): """Adds the given button with the given to the button box :param button: the button to be added :type button: PyQt4.QtGui.QPushButton :param role: button role :type role: PyQt4.Qt.QDialogButtonBox.ButtonRole""" self.buttonBox.addButton(button, role) def setIcon(self, icon, size=64): """Sets the icon to the dialog :param icon: the icon :type icon: PyQt4.QtGui.QIcon""" pixmap = icon.pixmap(size) self.iconLabel.setPixmap(pixmap) def setText(self, text): """Sets the text of this panel :param text: the new text :type text: str""" self.textLabel.setText(text) def getText(self): """Returns the current text of this panel :return: the text for this panel :rtype: str""" return self.textLabel.text() def setDetailedText(self, text): """Sets the detailed text of the dialog :param text: the new text :type text: str""" self.detailsTextEdit.setPlainText(text) def setDetailedHtml(self, html): """Sets the detailed HTML of the dialog :param html: the new HTML text :type html: str""" self.detailsTextEdit.setHtml(html) def getDetailedText(self): """Returns the current detailed text of this panel :return: the detailed text for this panel :rtype: str""" return self.detailsTextEdit.toPlainText() def getDetailedHtml(self): """Returns the current detailed HTML of this panel :return: the detailed HTML for this panel :rtype: str""" return self.detailsTextEdit.toHtml() def setOriginText(self, text): """Sets the origin text of the dialog :param text: the new text :type text: str""" self.originTextEdit.setPlainText(text) def setOriginHtml(self, html): """Sets the origin HTML of the dialog :param html: the new HTML text :type html: str""" self.originTextEdit.setHtml(html) def getOriginText(self): """Returns the current origin text of this panel :return: the origin text for this panel :rtype: str""" return self.originTextEdit.toPlainText() def getOriginHtml(self): """Returns the current origin HTML of this panel :return: the origin HTML for this panel :rtype: str""" return self.originTextEdit.toHtml() def setError(self, err_type=None, err_value=None, err_traceback=None): """Sets the exception object. Example usage:: l = [1, 2, 3] exc_info = None try: print(l[3]) except IndexError: exc_info = sys.exc_info() if exc_info: msgbox = ErrorWidget() msgbox.setError(*exc_info) msgbox.show() :param err_type: the exception type of the exception being handled (a class object) :type error: class object :param err_value: exception object :type err_value: object :param err_traceback: a traceback object which encapsulates the call stack at the point where the exception originally occurred :type err_traceback: traceback""" i = sys.exc_info() self._exc_info = [ err_type or i[0], err_value or i[1], err_traceback or i[2] ] formatter_klass = self.findErrorFormatter(self._exc_info[0]) formatter = formatter_klass() error_data = formatter.translateError(*self.getError()) title, error, detailed_error, origin = error_data self.setWindowTitle(title) self.setText(error) self.setDetailedHtml(detailed_error) self.setOriginHtml(origin) def getError(self): """Returns the current exception information of this panel :return: the current exception information (same as type as returned by :func:`sys.exc_info`) :rtype: tuple<type, value, traceback>""" return self._exc_info @staticmethod def getErrorFormatters(): result = {} try: import PyTango result[PyTango.DevFailed] = TangoErrorFormatterPlugin except ImportError: pass return result @classmethod def registerErrorHandler(klass, err_type, err_handler): klass.getErrorFormatters()[err_type] = err_handler @classmethod def findErrorFormatter(klass, err_type): """Finds the proper error handler class for the given error :param err_type: error class :type err_type: class object :return: a message box error handler :rtype: TaurusMessageBoxErrorHandler class object""" for exc, h_klass in klass.getErrorFormatters().items(): if issubclass(err_type, exc): return h_klass return BaseErrorFormatterPlugin
class Axis(QtCore.QObject): # : position changed signal # : # : emitted when the axis position has changed # : the signal is emitted with the axis name and position value positionChanged = QtCore.Signal(str, float) # : position changed signal # : # : emitted when the axis minimum allowed position has changed # : the signal is emitted with the axis name and minimum position value limitsChanged = QtCore.Signal(str, list) # : step sizes changed signal # : # : emitted when the allowed axis step sizes has changed # : the signal is emitted with the axis name and step sizes stepsChanged = QtCore.Signal(str, object) # : current step changed signal # : # : emitted when the current step size has changed # : the signal is emitted with the axis name and current step size currentStepChanged = QtCore.Signal(str, float) # : state changed signal # : # : emitted when the axis state has changed # : the signal is emitted with the axis name, old state and new state stateChanged = QtCore.Signal(str, object, object) # : label changed signal # : # : emitted when the axis label has changed # : the signal is emitted with the axis name and label value labelChanged = QtCore.Signal(str, str) # : units changed signal # : # : emitted when the axis units has changed # : the signal is emitted with the axis name and units value unitChanged = QtCore.Signal(str, str) def __init__(self, axis_info, axes, parent=None): super(Axis, self).__init__(parent) self._axes = weakref.ref(axes) self.name = axis_info['name'] self.index = axis_info['index'] self.role = axis_info.get('role', str(self.index)) self._label = axis_info.get('username', self.name) self._position = None # float('nan') self._limits = None # float('-inf'), float('+inf') self._state = None self._steps = None self._current_step = None self._unit = None @property def axes(self): return self._axes() def refresh(self): self.state = self.getState(cache=False) self.limits = self.getLimits(cache=False) self.position = self.getPosition(cache=False) def getPosition(self, cache=True): if cache and self._position is not None: result = self._position else: self._position = result = self.axes.position(self.name) return result def setPosition(self, position, emit=True): self._position = position if emit: self.positionChanged.emit(self.name, position) #: This property contains the axis position #: #: **Access functions:** #: #: * :meth:`Axis.getPosition` #: * :meth:`Axis.setPosition` position = QtCore.Property(str, getPosition, setPosition) def getLimits(self, cache=True): if cache and self._limits is not None: result = self._limits else: self._limits = result = list(self.axes.limits(self.name)) return result def setLimits(self, limits, emit=True): self._limits = list(limits) if emit: self.limitsChanged.emit(self.name, limits) #: This property contains the axis limits #: #: **Access functions:** #: #: * :meth:`Axis.getLimits` #: * :meth:`Axis.setLimits` limits = QtCore.Property(list, getLimits, setLimits) def getState(self, cache=True): if cache and self._state is not None: result = self._state else: self._state = result = self.axes.state(self.name) return result def setState(self, state, emit=True): old_state = self._state if state is None: state = State._Invalid self._state = state if emit: self.stateChanged.emit(self.name, old_state, state) #: This property contains the axis state #: #: **Access functions:** #: #: * :meth:`Axis.getState` #: * :meth:`Axis.setState` state = QtCore.Property(object, getState, setState) def getLabel(self): return self._label def setLabel(self, label, emit=True): if label is None: label = "" self._label = label if emit: self.labelChanged.emit(self.name, label) #: This property contains the axis label #: #: **Access functions:** #: #: * :meth:`Axis.getLabel` #: * :meth:`Axis.setLabel` label = QtCore.Property(str, getLabel, setLabel) def getSteps(self): return self._steps def setSteps(self, steps, emit=True): if steps is None: steps = [] self._steps = steps if emit: self.stepsChanged.emit(self.name, steps) #: This property contains the axis steps #: #: **Access functions:** #: #: * :meth:`Axis.getSteps` #: * :meth:`Axis.setSteps` steps = QtCore.Property(str, getSteps, setSteps) def getCurrentStep(self): return self._current_step def setCurrentStep(self, current_step, emit=True): self._current_step = current_step if emit: self.currentStepChanged.emit(self.name, current_step) #: This property contains the axis current step size #: #: **Access functions:** #: #: * :meth:`Axis.getCurrentStep` #: * :meth:`Axis.setCurrentStep` currentStep = QtCore.Property(float, getCurrentStep, setCurrentStep) def getUnit(self): return self._unit def setUnit(self, unit, emit=True): if unit is None: unit = "" self._unit = unit if emit: self.unitChanged.emit(self.name, unit) #: This property contains the axis unit #: #: **Access functions:** #: #: * :meth:`Axis.getUnit` #: * :meth:`Axis.setUnit` unit = QtCore.Property(float, getUnit, setUnit) def move(self, absolute_position): self.axes.move(self.name, absolute_position) def moveRelative(self, relative_position): self.move(self.position + relative_position) def moveUp(self): self.moveRelative(+self.currentStep) def moveDown(self): self.moveRelative(-self.currentStep) stepUp = moveUp stepDown = moveDown def stop(self): self.axes.abort(self.name) ToolTipTemplate = """<html>axis <u>{axis.label}</u> is in \ <b>{axis.state.name}</b> state, at position <b>{axis.position}</b><br/> Limits set to <b>[{axis.limits[0]}, {axis.limits[1]}]</b><br/> (the hardware name for this axis is: <i>{axis.name}</i>)""" def toolTip(self): return self.ToolTipTemplate.format(axis=self)
class ValueSpinBox(QtGui.QDoubleSpinBox): SpinStyleT = 'ValueSpinBox {font-family: "Monospace"; %s}' # : value applied signal # : # : emitted when the spinbox enter/return key is pressed valueApplied = QtCore.Signal() def __init__(self, axis, parent=None): super(ValueSpinBox, self).__init__(parent) self.axis = axis self.setAccelerated(True) # self.setButtonSymbols(self.PlusMinus) # self.setFrame(False) self.setDecimals(3) self.setMinimum(float("-inf")) self.setMaximum(float("+inf")) self.setAlignment(QtCore.Qt.AlignLeft) self.setStyleSheet(self.SpinStyleT % "") def setValue(self, value, emit=True): if value is None: value = float('nan') if emit: return super(ValueSpinBox, self).setValue(value) blocked = self.signalsBlocked() try: self.blockSignals(True) result = super(ValueSpinBox, self).setValue(value) finally: self.blockSignals(blocked) return result def setUnit(self, unit): if unit is None or not len(unit): unit = "" elif not unit.startswith(" "): unit = " " + unit self.setSuffix(unit) def setState(self, state): if state is None: state = State._Invalid styleSheet = getCSSColorFromState(state) self.setStyleSheet(self.SpinStyleT % styleSheet) def setSingleStep(self, value): if value is None: return return super(ValueSpinBox, self).setSingleStep(value) def setMinimum(self, value): if value is None: value = float('-inf') return super(ValueSpinBox, self).setMinimum(value) def setMaximum(self, value): if value is None: value = float('+inf') return super(ValueSpinBox, self).setMaximum(value) def sizeHint(self): size = super(ValueSpinBox, self).sizeHint() size.setHeight(get_height_hint()) return size def minimumSizeHint(self): size = super(ValueSpinBox, self).minimumSizeHint() size = QtCore.QSize(size.width(), get_minimum_height_hint()) return size def keyPressEvent(self, event): key = event.key() if key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): self.valueApplied.emit() elif key == QtCore.Qt.Key_Escape: self.axis.refresh() elif key == QtCore.Qt.Key_F5: self.axis.refresh() else: return super(ValueSpinBox, self).keyPressEvent(event)