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()
def index(self, row, column, parent=QtCore.QModelIndex()): if not self.hasIndex(row, column, parent): return QtCore.QModelIndex() if not parent.isValid(): parentItem = self._rootItem else: parentItem = parent.internalPointer() childItem = parentItem.child(row) if childItem: return self.createIndex(row, column, childItem) return QtCore.QModelIndex()
def parent(self, index): if not index.isValid(): return QtCore.QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem is None or parentItem == self._rootItem: return QtCore.QModelIndex() return self.createIndex(parentItem.row(), 0, parentItem)
def grabWidget(widget, fileName, period=None): """Grabs the given widget into the given image filename. If period is None (default) it grabs immediately once and returns. If period is given and >0 means grab the image every period (in seconds). .. warning:: this method **MUST** be called from the same thread which created the widget :param widget: the Qt widget to be grabbed :type widget: QtWidget :param fileName: the name of the image file :type fileName: str :param period: period (seconds) :type period: float """ if period is None: widgetName = widget.objectName() widgetTitle = widget.windowTitle() logging.debug("Grabbing widget '%s' to '%s':", widgetName, fileName) try: pixmap = QtGui.QPixmap.grabWidget(widget) if fileName.endswith('.svg'): import qarbon.external.qt.QtSvg generator = qarbon.external.qt.QtSvg.QSvgGenerator() generator.setFileName(fileName) generator.setSize(pixmap.size()); if hasattr(generator, 'setViewBox'): viewBox = QtCore.QRect(QtCore.QPoint(0, 0), pixmap.size()) generator.setViewBox(viewBox) title = "Qarbon widget" if widgetTitle: title += " - " + widgetTitle elif widgetName: title += " - " + widgetName desc = "An SVG created by the qarbon widget grabber" generator.setTitle(title) generator.setDescription(desc) painter = QtGui.QPainter() painter.begin(generator) try: painter.drawPixmap(0, 0, -1, -1, pixmap) finally: painter.end() else: pixmap.save(fileName, quality=100) except Exception: logging.warning("Could not save file into '%s':", fileName) logging.debug("Details:", exc_info=1) ret = __GrabberThread(widget, fileName, period) ret.start() return ret
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()
def onGotoNode(self, *args): label = self.sender() persistent_index = label.parent().index() index = QtCore.QModelIndex(persistent_index) tree = self.viewWidget() tree.setRootIndex(index) tree.setCurrentIndex(index.child(0, 0))
def __init__(self, parent=None): super(XEmbedCommandWidget, self).__init__(parent) self.error.connect(self.__onError) self.__process = process = QtCore.QProcess(self) self.resetCommand() self.resetAutoRestart() self.resetWinIdParam() self.resetExtraParams()
def setTitleHeight(self, height): """Sets this widget's title height :param height: the new widget title height :type height: int""" s = QtCore.QSize(height, height) self.titleButton().setIconSize(s) self.collapseButton().setIconSize(s)
def __init__(self, name=None, view=None, parent=None, designMode=False): if name is None: name = "Base toolbar" self._viewWidget = view or parent QtGui.QToolBar.__init__(self, name, parent) self.setIconSize(QtCore.QSize(16, 16)) self.setFloatable(False) self.setMovable(False)
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)
def rowCount(self, parent=QtCore.QModelIndex()): if parent.column() > 0: return 0 if not parent.isValid(): parentItem = self._rootItem else: parentItem = parent.internalPointer() if parentItem is None: return 0 return parentItem.childCount()
def hasChildren(self, parent=QtCore.QModelIndex()): if parent.column() > 0: return 0 if not parent.isValid(): parentItem = self._rootItem else: parentItem = parent.internalPointer() if parentItem is None: return False return parentItem.hasChildren()
def qtdesigner_start(args, env=None): # Start Designer. designer_bin = get_qtdesigner_bin() designer = QtCore.QProcess() designer.setProcessChannelMode(QtCore.QProcess.ForwardedChannels) designer.setEnvironment(env) designer.start(designer_bin, args) designer.waitForFinished(-1) return designer.exitCode()
def __init__(self, parent=None): super(XCommandWidget, self).__init__(parent) self.__process = QtCore.QProcess(self) self.__x11_widget = x11_widget = QtGui.QX11EmbedContainer(self) layout = QtGui.QVBoxLayout(self) layout.setMargin(0) layout.setSpacing(0) layout.addWidget(x11_widget) x11_widget.error.connect(self.__onError) self.resetCommand() self.resetAutoRestart() self.resetWinIdParam() self.resetExtraParams()
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)
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): ret = None if orientation == QtCore.Qt.Horizontal: if role == QtCore.Qt.TextAlignmentRole: ret = int(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) elif role == QtCore.Qt.DisplayRole: ret = self.ColumnNames[section] elif role == QtCore.Qt.SizeHintRole: ret = QtCore.QSize(self.columnSize(section)) ret.setHeight(24) elif role == QtCore.Qt.ToolTipRole: ret = self.columnToolTip(section) elif role == QtCore.Qt.DecorationRole: ret = self.columnIcon(section) return ret
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()
def __init__(self, parent=None, qobject=None): super(ObjectInfoWidget, self).__init__(parent) self.setWindowIcon(Icon("applications-development")) self.setWindowTitle("QObject Inspector") layout = QtGui.QHBoxLayout() self.setLayout(layout) layout.setSpacing(0) layout.setMargin(0) self.__splitter = splitter = QtGui.QSplitter(QtCore.Qt.Horizontal, self) layout.addWidget(splitter) self.__form = form = PropertyEditor(parent=splitter, qobject=qobject) self.__tree = tree = TreeQObjectWidget(parent=splitter, qobject=qobject) splitter.addWidget(tree) splitter.addWidget(form) treeSelectionModel = tree.viewWidget().selectionModel() QtCore.QObject.connect( treeSelectionModel, QtCore.SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), self.__onSelectionChanged)
def roleSize(self, taurus_role): return QtCore.QSize(300, 70)
class Led(PixmapWidget): """A LED (light-emitting diode) like widget""" #: constant defining default led image filename pattern DefaultLedPattern = NAMESPACE + ":/led/led_{color}_{status}.png" #: constant defining default led color (green) DefaultLedColor = LedColor.Green #: constant defining default led status (On) DefaultLedStatus = LedStatus.On #: constant defining default led status invertion (False) DefaultLedInverted = False def __init__(self, parent=None): self.__ledStatus = self.DefaultLedStatus self.__ledColor = self.DefaultLedColor self.__ledPatternName = self.DefaultLedPattern self.__ledInverted = self.DefaultLedInverted self.__ledName = self.toLedName() PixmapWidget.__init__(self, parent) self._refresh() def sizeHint(self): return PixmapWidget.sizeHint(self) def minimumSizeHint(self): """Overwrite the default minimum size hint (0,0) to be (8, 8) :return: the minimum size hint 8, 8 :rtype: QSize""" return QtCore.QSize(8, 8) def toLedName(self, status=None, color=None, inverted=None): """Gives the led name for the given status and color. If status or color are not given, the current led status or color are used. :param status: the status :type status: bool :param color: the color :type color: str :return: string containing the led name :rtype: str""" if status is None: status = self.__ledStatus if color is None: color = self.__ledColor if inverted is None: inverted = self.__ledInverted if inverted: if status is LedStatus.On: status = LedStatus.Off else: status = LedStatus.On status = status.name.lower() color = color.name.lower() return self.__ledPatternName.format(color=color, status=status) def isLedColorValid(self, name): """Determines if the given color name is valid. :param color: the color :type color: str :return: True is the given color name is valid or False otherwise :rtype: bool""" return hasattr(LedColor, name) def _refresh(self): """internal usage only""" self.__ledName = self.toLedName() pixmap = QtGui.QPixmap(self.__ledName) self.setPixmap(pixmap) return self.update() #-------------------------------------------------------------------------- # QT property definition #-------------------------------------------------------------------------- def getLedPatternName(self): """Returns the current led pattern name :return: led pattern name :rtype: str""" return self.__ledPatternName def setLedPatternName(self, name): """Sets the led pattern name. Should be a string containing a path to valid images. The string can contain the keywords: 1. {status} - transformed to 'on' of 'off' according to the status 2. {color} - transformed to the current led color Example: **:leds/images256/led_{color}_{status}.png** will be transformed to **:leds/images256/led_red_on.png** when the led status is True and the led color is red. :param name: new pattern :type name: str""" self.__ledPatternName = name self._refresh() def resetLedPatternName(self): """Resets the led pattern to **fwk4:/Leds/led_{color}_{status}.png**. """ self.setLedPatternName(self.DefaultLedPattern) def getLedStatus(self): """Returns the led status :return: led status :rtype: bool""" return self.__ledStatus.value def setLedStatus(self, status): """Sets the led status :param status: the new status :type status: bool""" self.__ledStatus = LedStatus(status) self._refresh() def resetLedStatus(self): """Resets the led status""" self.setLedStatus(self.DefaultLedStatus) def toggleLedStatus(self): """toggles the current status of the led""" if self.__ledStatus is LedStatus.On: self.setLedStatus(LedStatus.Off) else: self.setLedStatus(LedStatus.On) def getLedInverted(self): """Returns if the led is inverted. :return: inverted mode :rtype: bool""" return self.__ledInverted def setLedInverted(self, inverted): """Sets the led inverted mode :param status: the new inverted mode :type status: bool""" self.__ledInverted = bool(inverted) self._refresh() def resetLedInverted(self): """Resets the led inverted mode""" self.setLedInverted(self.DefaultLedInverted) def getLedColor(self): """Returns the led color :return: led color :rtype: LedColor""" return self.__ledColor.value def setLedColor(self, color): """Sets the led color :param status: the new color :type status: LedColor""" self.__ledColor = LedColor(color) self._refresh() def resetLedColor(self): """Resets the led color""" self.setLedColor(self.DefaultLedColor) @classmethod def getQtDesignerPluginInfo(cls): return dict(icon=":/designer/ledred.png",) #: This property holds the led status: False means OFF, True means ON #: #: **Access functions:** #: #: * :meth:`Led.getLedStatus` #: * :meth:`Led.setLedStatus` #: * :meth:`Led.resetLedStatus` ledStatus = QtCore.Property(int, getLedStatus, setLedStatus, resetLedStatus, doc="led status") #: This property holds the led color #: #: **Access functions:** #: #: * :meth:`Led.getLedColor` #: * :meth:`Led.setLedColor` #: * :meth:`Led.resetLedColor` ledColor = QtCore.Property(int, getLedColor, setLedColor, resetLedColor, doc="led color") #: This property holds the led inverted: False means do not invert the #. status, True means invert the status #: #: **Access functions:** #: #: * :meth:`Led.getLedInverted` #: * :meth:`Led.setLedInverted` #: * :meth:`Led.resetLedInverted` ledInverted = QtCore.Property(bool, getLedInverted, setLedInverted, resetLedInverted, doc="led inverted mode") #: This property holds the led pattern name #: #: **Access functions:** #: #: * :meth:`Led.getLedPatternName` #: * :meth:`Led.setLedPatternName` #: * :meth:`Led.resetLedPatternName` ledPattern = QtCore.Property(str, getLedPatternName, setLedPatternName, resetLedPatternName, doc="led pattern name")
def minimumSizeHint(self): """Overwrite the default minimum size hint (0,0) to be (8, 8) :return: the minimum size hint 8, 8 :rtype: QSize""" return QtCore.QSize(8, 8)
class XCommandWidget(QtGui.QWidget): """A widget displaying an X11 window inside from a command. Example:: from qarbon.external.qt import QtGui from qarbon.qt.gui.application import Application from qarbon.qt.gui.x11 import XCommandWidget app = Application() w = QtGui.QMainWindow() cmdWidget = XCommandWidget(parent=w) cmdWidget.command = 'xterm' cmdWidget.winIdParam = '-into' cmdWidget.start() w.setCentralWidget(cmdWidget) w.show() app.exec_()""" DefaultAutoRestart = False DefaultWinIdParam = '-into' def __init__(self, parent=None): super(XCommandWidget, self).__init__(parent) self.__process = QtCore.QProcess(self) self.__x11_widget = x11_widget = QtGui.QX11EmbedContainer(self) layout = QtGui.QVBoxLayout(self) layout.setMargin(0) layout.setSpacing(0) layout.addWidget(x11_widget) x11_widget.error.connect(self.__onError) self.resetCommand() self.resetAutoRestart() self.resetWinIdParam() self.resetExtraParams() def __onError(self, error): log.error("XEmbedContainer: Error") def __convert_wait(self, wait): if wait: if wait < 0: wait = -1 else: wait = int(wait * 1000) return wait def __finish(self, finish_func, wait=0): process = self.__process wait = self.__convert_wait(wait) finish_func() if wait: return process.waitForFinished(msecs=wait) def getX11WinId(self): return self.getX11Widget().winId() def getX11Widget(self): return self.__x11_widget def getProcess(self): return self.__process def getCommand(self): return self.__command def setCommand(self, command): self.__command = command if command is None: self.setWindowTitle("<None>") else: self.setWindowTitle(command) def resetCommand(self): self.setCommand(None) def getWinIdParam(self): return self.__winIdParam def setWinIdParam(self, winIdParam): self.__winIdParam = winIdParam def resetWinIdParam(self): self.setWinIdParam(self.DefaultWinIdParam) def setExtraParams(self, params): if params is None: params = [] self.__extraParams = params def getExtraParams(self): return self.__extraParams def resetExtraParams(self): self.setExtraParams(None) def setAutoRestart(self, yesno): self.__autoRestart = yesno def getAutoRestart(self): return self.__autoRestart def resetAutoRestart(self): return self.setAutoRestart(self.DefaultAutoRestart) def setWorkingDirectory(self, wd): if wd is not None: self.getProcess().setWorkingDirectory(wd) def getWorkingDirectory(self): return self.getProcess().workingDirectory() def start(self, wait=0): """wait < 0 -> wait forever, wait == 0 -> not wait, wait > 0 -> wait amount in seconds""" if self.__command is None: raise Exception("Cannot start: no command") if self.__winIdParam is None: raise Exception("Cannot start: no winIdParam") process = self.__process params = [self.__winIdParam, str(self.getX11WinId())] + \ self.__extraParams process.start(self.__command, params) wait = self.__convert_wait(wait) if wait: return process.waitForStarted(msecs=wait) def restart(self, wait=0): self.terminate(wait=-1) return self.start(wait=wait) def kill(self, wait=0): return self.__finish(self.__process.kill, wait=wait) def terminate(self, wait=0): return self.__finish(self.__process.terminate, wait=wait) def __del__(self): import sip if not sip.isdeleted(self.__process): log.debug("X11CommandWidget: __del__ terminates x11...") self.terminate() else: log.debug("X11CommandWidget: __del__ does nothing...") def deleteLater(self): log.debug("X11CommandWidget: deleteLater...") self.terminate(wait=-1) return super(XCommandWidget, self).deleteLater() @classmethod def getQtDesignerPluginInfo(cls): return dict(icon=":/designer/xorg.png", tooltip="XTerm widget") command = QtCore.Property(str, getCommand, setCommand, resetCommand) winIdParam = QtCore.Property(str, getWinIdParam, setWinIdParam, resetWinIdParam) extraParams = QtCore.Property("QStringList", getExtraParams, setExtraParams, resetExtraParams) autoRestart = QtCore.Property(bool, getAutoRestart, setAutoRestart, resetAutoRestart) workingDirectory = QtCore.Property(str, getWorkingDirectory, setWorkingDirectory)
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 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 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()
def setQObject(self, qobject): """Sets the current QObject whose properties are to been seen by the editor. :param qobject: the new QObject (can be None) """ ui = self.__ui superClassName = "" _class = "" className = "" isWidget = False propCount = 0 if qobject is None: self.__qobject = None else: _class = qobject.__class__.__name__ self.__qobject = weakref.ref(qobject) metaObject = qobject.metaObject() if metaObject is not None: className = metaObject.className() superClass = metaObject.superClass() if superClass is not None: superClassName = superClass.className() isWidget = qobject.isWidgetType() propCount = metaObject.propertyCount() ui.classLineEdit.setText(_class) ui.classNameLineEdit.setText(className) ui.superClassNameLineEdit.setText(superClassName) ui.isWidgetLineEdit.setText(str(isWidget)) ui.focusButton.setEnabled(isWidget) propTree = ui.propertiesTreeWidget QtCore.QObject.disconnect( propTree, QtCore.SIGNAL("itemChanged (QTreeWidgetItem*, int)"), self.__onPropertyTreeChanged) propTree.clear() if propCount == 0: return metaO, props = metaObject, [] while True: first, last = metaO.propertyOffset(), metaO.propertyCount() if first < last: class_props = {} for p_index in range(first, last): metaProp = metaObject.property(p_index) class_props[metaProp.name()] = metaProp props.insert(0, (metaO, class_props)) metaO = metaO.superClass() if metaO is None: break # build tree for metaO, props in props: topItem = QtGui.QTreeWidgetItem(propTree) topItem.setText(0, metaO.className()) for prop_name in sorted(props.keys()): metaProp = props[prop_name] prop_type = metaProp.typeName() value = qobject.property(prop_name) prop_value = getPropertyValueDisplay(metaProp, value) columns = [prop_name, prop_type, prop_value] propItem = QtGui.QTreeWidgetItem(topItem, columns) propItem.setFlags(propItem.flags() | QtCore.Qt.ItemIsEditable) propItem.setData(2, QtCore.Qt.UserRole, prop_name) propItem.setData(2, QtCore.Qt.DisplayRole, value) propItem.setToolTip(2, getPropertyValueToolTip(metaProp, value)) propTree.expandToDepth(1) propTree.headerItem() QtCore.QObject.connect( propTree, QtCore.SIGNAL("itemChanged (QTreeWidgetItem*, int)"), self.__onPropertyTreeChanged)
class GroupBox(QtGui.QWidget): """An expandable/collapsible container widget""" DefaultContentVisible = True DefaultTitleBarVisible = True DefaultTitleBarHeight = 16 DefaultStyle = GROUPBOX_NEBULA_STYLESHEET_MAP def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.__titleVisible = self.DefaultTitleBarVisible self.__contentVisible = self.DefaultContentVisible self.__contentPanel = None self.__content = None self.__style = self.DefaultStyle self.__init() self.resetStyleMap() self.resetContentVisible() self.resetTitleHeight() self.resetTitleVisible() def __init(self): panelLayout = QtGui.QVBoxLayout() panelLayout.setSpacing(0) panelLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(panelLayout) self.__titleBar = titleBar = TitleBar() panelLayout.addWidget(titleBar, 0) l = QtGui.QHBoxLayout() l.setContentsMargins(2, 2, 2, 2) l.setSpacing(2) self.__titleBar.setLayout(l) self.__titleButton = QtGui.QToolButton() self.__titleButton.setStyleSheet("border: 0px") styleOption = QtGui.QStyleOption() styleOption.initFrom(self.__titleButton) style = Application().style() icon = style.standardIcon(QtGui.QStyle.SP_DesktopIcon, styleOption, self.__titleButton) self.__titleButton.setIcon(icon) self.__titleLabel = TitleLabel() self.__upDownButton = QtGui.QToolButton() self.__upDownButton.setStyleSheet("border: 0px") self.__upDownButton.clicked.connect(self.switchContentVisible) l.addWidget(self.__titleButton, 0) l.addWidget(self.__titleLabel, 1) l.addWidget(self.__upDownButton, 0) self.__contentPanel = contentPanel = ContentPanel() panelLayout.addWidget(contentPanel, 1) def _updateStyle(self): """Internal method that updates the style""" style = GROUPBOX_STYLESHEET_TEMPLATE.format(**self.__style) self.setStyleSheet(style) def content(self): """Returns the contents widget :return: the current content widget or None if no content is set :rtype: QWidget""" return self.__contentPanel.content() def setContent(self, qwidget): """Sets the content widget :param qwidget: the content widget or None :type qwidget: QWidget""" self.__contentPanel.setContent(qwidget) def titleBar(self): """Returns the title bar widget :return: the title bar widget :rtype: QFrame""" return self.__titleBar def titleButton(self): """Returns the title button widget :return: the title button widget :rtype: QToolButton""" return self.__titleButton def collapseButton(self): """Returns the collapse button widget :return: the collapse button widget :rtype: QToolButton""" return self.__upDownButton def setTitle(self, title): """Sets this widget's title :param title:the new widget title :type title: str""" self.__titleLabel.setText(title) self.setToolTip("<html>The <b>{0}</b>".format(title)) def getTitle(self): """Returns this widget's title :return: this widget's title :rtype: str""" return self.__titleLabel.text() def setTitleIcon(self, icon): """Sets this widget's title icon :param icon: (Qt.QIcon) the new widget title icon""" self.__titleButton.setIcon(icon) def getTitleIcon(self): """Returns this widget's title icon :return: this widget's title icon :rtype: QIcon""" return self.__titleButton.icon() def switchContentVisible(self): """Switches this widget's contents visibility""" self.setContentVisible(not self.isContentVisible()) def isContentVisible(self): """Returns this widget's contents visibility :return: this widget's contents visibility :rtype: bool""" return self.__contentVisible def resetContentVisible(self): """Resets this widget's contents visibility""" self.setContentVisible(self.DefaultContentVisible) def setContentVisible(self, show): """Sets this widget's contents visibility :param show: the new widget contents visibility :type show: bool""" self.__contentVisible = show if show: icon_name = QtGui.QStyle.SP_TitleBarShadeButton else: icon_name = QtGui.QStyle.SP_TitleBarUnshadeButton icon = self.style().standardIcon(icon_name) self.__upDownButton.setIcon(icon) self.__contentPanel.setVisible(show) self.adjustSize() def isTitleVisible(self): """Returns this widget's title visibility :return: this widget's title visibility :rtype: bool""" return self.__titleVisible def resetTitleVisible(self): """Resets this widget's title visibility""" self.setTitleVisible(self.DefaultTitleBarVisible) def setTitleVisible(self, show): """Sets this widget's title visibility :param show: the new widget title visibility :type show: bool""" self.__titleVisible = show self.__titleBar.setVisible(show) def getTitleHeight(self): """Returns this widget's title height :return: this widget's title height :rtype: int""" return self.titleButton().iconSize().height() def setTitleHeight(self, height): """Sets this widget's title height :param height: the new widget title height :type height: int""" s = QtCore.QSize(height, height) self.titleButton().setIconSize(s) self.collapseButton().setIconSize(s) def resetTitleHeight(self): """Resets this widget's title height""" self.setTitleHeight(self.DefaultTitleBarHeight) def getStyleMap(self): """Returns this widget's style :return: this widget's style :rtype: dict""" return self.__style def setStyleMap(self, style_map): """Sets this widget's title style Used key/values for style_map: - 'title_start_color' : brush (Ex.: '#E0E0E0') - 'title_stop_color' : brush (Ex.: '#E0E0E0') - 'title_font_color' : brush (Ex.: '#E0E0E0') - 'title_border_radius': radius (Ex.: '5px') - 'content_start_color' : brush (Ex.: '#E0E0E0') - 'content_stop_color' : brush (Ex.: '#E0E0E0') - 'content_border_radius': radius (Ex.: '5px') :param style_map: the new widget title style :type style_map: dict""" style = self.DefaultStyle.copy() style.update(style_map) self.__style = style self._updateStyle() def resetStyleMap(self): """Resets this widget's title style""" self.setStyleMap({}) @classmethod def getQtDesignerPluginInfo(cls): from qarbon.qt.designer.plugins.base import \ DesignerBaseSingleContainerExtension return dict(icon=":/designer/groupwidget.png", container=True, container_extension=DesignerBaseSingleContainerExtension) #: This property contains the widget's title #: #: **Access functions:** #: #: * :meth:`getTitle` #: * :meth:`setTitle` title = QtCore.Property(str, getTitle, setTitle) #: This property contains the widget's title icon #: #: **Access functions:** #: #: * :meth:`getTitleIcon` #: * :meth:`setTitleIcon` titleIcon = QtCore.Property("QIcon", getTitleIcon, setTitleIcon) #: This property contains the widget's title height #: #: **Access functions:** #: #: * :meth:`getTitleHeight` #: * :meth:`setTitleHeight` #: * :meth:`resetTitleHeight` titleHeight = QtCore.Property(int, getTitleHeight, setTitleHeight, resetTitleHeight) #: This property contains the widget's title visibility #: #: **Access functions:** #: #: * :meth:`isTitleVisible` #: * :meth:`setTitleVisible` titleVisible = QtCore.Property(bool, isTitleVisible, setTitleVisible) #: This property contains the widget's style map #: #: **Access functions:** #: #: * :meth:`getStyleMap` #: * :meth:`setStyleMap` #: * :meth:`resetStyleMap` styleMap = QtCore.Property(dict, getStyleMap, setStyleMap, resetStyleMap, designable=False) #: This property contains the widget's content's visibility #: #: **Access functions:** #: #: * :meth:`isContentVisible` #: * :meth:`setContentVisible` #: * :meth:`resetContentVisible` contentVisible = QtCore.Property(bool, isContentVisible, setContentVisible, resetContentVisible)
def columnCount(self, parent=QtCore.QModelIndex()): return len(self.ColumnRoles)