Пример #1
0
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")
Пример #2
0
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)
Пример #3
0
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")
Пример #4
0
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)
Пример #5
0
class XCommandWindow(QtGui.QMainWindow):
    """The QMainWindow version of :class:`XCommandWidget`.

    Example::

        from qarbon.external.qt import QtGui
        from qarbon.qt.gui.application import Application
        from qarbon.qt.gui.x11 import XCommandWindow

        app = Application()
        w = XCommandWindow()
        w.command = 'xterm'
        w.winIdParam = '-into'
        w.start()
        w.show()
        app.exec_()"""

    Widget = XCommandWidget

    def __init__(self, **kwargs):
        parent = kwargs.pop('parent', None)
        flags = kwargs.pop('flags', QtCore.Qt.WindowFlags())
        super(XCommandWindow, self).__init__(parent=parent, flags=flags)
        x11 = self.Widget(parent=self, **kwargs)
        self.setCentralWidget(x11)
        toolBar = self.addToolBar("Actions")
        self.__actionsToolBar = weakref.ref(toolBar)
        self.__restartAction = Action("Restart", parent=self,
                                      icon=Icon("view-refresh"),
                                      tooltip="restart the current command",
                                      triggered=self.restart)
        toolBar.addAction(self.__restartAction)

    def XWidget(self):
        return self.centralWidget()

    def start(self, wait=0):
        self.XWidget().start(wait=wait)

    def restart(self, wait=0):
        self.XWidget().restart(wait=wait)

    def terminate(self, wait=0):
        self.XWidget().terminate(wait=wait)

    def getCommand(self):
        return self.XWidget().command

    def setCommand(self, command):
        self.XWidget().command = command

    def resetCommand(self):
        self.XWidget().resetCommand()

    def getWinIdParam(self):
        return self.XWidget().winIdParam

    def setWinIdParam(self, winIdParam):
        self.XWidget().winIdParam = winIdParam

    def resetWinIdParam(self):
        self.XWidget().resetWinIdParam()

    def setExtraParams(self, params):
        self.XWidget().extraParams = params

    def getExtraParams(self):
        return self.XWidget().extraParams

    def resetExtraParams(self):
        self.XWidget().resetExtraParams()

    def setAutoRestart(self, yesno):
        self.XWidget().autoRestart = yesno

    def getAutoRestart(self):
        return self.XWidget().autoRestart

    def resetAutoRestart(self):
        self.XWidget().resetAutoRestart()

    def setWorkingDirectory(self, wd):
        self.XWidget().workingDirectory = wd

    def getWorkingDirectory(self):
        return self.XWidget().workingDirectory

    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)
Пример #6
0
class AxesWidget(GroupBox):
    """A multiple axis widget."""
    DefaultUpdateStatusBar = True

    def __init__(self, title=None, axes=None, parent=None):
        super(AxesWidget, self).__init__(parent)
        self._axes = {}
        contentWidget = QtGui.QWidget()
        layout = QtGui.QGridLayout()
        layout.setColumnStretch(Column.Position.value, 1)
        layout.setContentsMargins(2, 2, 2, 2)
        layout.setSpacing(2)
        contentWidget.setLayout(layout)
        self.setContent(contentWidget)
        self.setTitle(title)
        self.setTitleIcon(Icon(":/objects/motor.png"))
        self.setAxes(axes)
        self.resetUpdateStatusBar()

    def axes(self):
        return self._axes

    def setAxes(self, axes):
        for axis_id in self._axes:
            self.removeAxisID(axis_id)

        if axes is None:
            return

        for axis in axes:
            self.addAxis(axis)

    def addAxis(self, axis):
        self._axes[axis.name] = axis
        self.__buildAxisGUI(axis)
        axis.positionChanged.connect(self.onAxisPositionChanged)
        axis.stateChanged.connect(self.onAxisStateChanged)
        axis.labelChanged.connect(self.onAxisLabelChanged)
        axis.stepsChanged.connect(self.onAxisStepsChanged)
        axis.currentStepChanged.connect(self.onAxisCurrentStepChanged)
        axis.limitsChanged.connect(self.onAxisLimitsChanged)
        axis.unitChanged.connect(self.onAxisUnitChanged)

    def removeAxisID(self, axis_id):
        self.removeAxis(self.getAxis(axis_id))

    def removeAxis(self, axis):
        axis.positionChanged.disconnect(self.onAxisPositionChanged)
        axis.stateChanged.disconnect(self.onAxisStateChanged)
        axis.labelChanged.disconnect(self.onAxisLabelChanged)
        axis.stepsChanged.disconnect(self.onAxisStepsChanged)
        axis.currentStepChanged.disconnect(self.onAxisCurrentStepChanged)
        axis.limitsChanged.disconnect(self.onAxisLimitsChanged)
        axis.unitChanged.disconnect(self.onAxisUnitChanged)

        layout = self.content().layout()
        for role in Column:
            w = self.axisColumnWidget(axis, role)
            layout.removeWidget(w)
            w.setParent(None)
        self._axes.pop(axis.id)

    def getAxis(self, name):
        return self._axes[name]

    def getAxisByRole(self, role):
        for axis in self._axes.values():
            if axis.role == role:
                return axis
        raise KeyError(role)

    def __buildAxisGUI(self, axis):
        row = axis.index
        layout = self.content().layout()

        # create widgets
        label_widget = DisplayLabel(axis)
        position_widget = ValueSpinBox(axis)
        icon_widget = QtGui.QLabel()
        steps_widget = StepSize(axis)
        step_left_widget = StepLeftButton(axis)
        step_right_widget = StepRightButton(axis)
        stop_widget = StopButton(axis)

        # add widgets to container
        layout.addWidget(label_widget, row, Column.Label.value)
        layout.addWidget(position_widget, row, Column.Position.value)
        layout.addWidget(icon_widget, row, Column.Icon.value)
        layout.addWidget(steps_widget, row, Column.Steps.value)
        layout.addWidget(step_left_widget, row, Column.StepLeft.value)
        layout.addWidget(step_right_widget, row, Column.StepRight.value)
        layout.addWidget(stop_widget, row, Column.Stop.value)

        # initialize values
        label_widget.setValue(axis.label)

        position_widget.setValue(axis.position)
        position_widget.setState(axis.state)
        position_widget.setRange(*axis.limits)
        position_widget.setSingleStep(axis.currentStep)
        position_widget.setUnit(axis.unit)

        steps_widget.setSteps(axis.steps)
        steps_widget.setCurrentStep(axis.currentStep)

        # set buddy
        label_widget.setBuddy(position_widget)

        icon_widget.hide()

        # connect signals
        steps_widget.activated.connect(self.onUserCurrentStepsChanged)
        position_widget.valueApplied.connect(self.onUserPositionApplied)
        position_widget.valueChanged.connect(self.onUserPositionChanged)
        step_left_widget.clicked.connect(self.onUserStepLeft)
        step_right_widget.clicked.connect(self.onUserStepRight)
        stop_widget.clicked.connect(self.onUserStop)

        # initialize enable/disable and tooltips
        self.__updateAxis(axis)

    def axisColumnWidget(self, axis, role):
        layout = self.content().layout()
        return layout.itemAtPosition(axis.index, role.value).widget()

    def axisIDColumnWidget(self, name, role):
        return self.axisColumnWidget(self.getAxis(name), role)

    def setAxisColumnVisible(self, axis, role, show=True):
        self.axisColumnWidget(axis, role).setVisible(show)

    def setAxisIDColumnVisible(self, name, role, show=True):
        self.setAxisColumnVisible(self.getAxis(name), role, show=show)

    def setColumnVisible(self, role, show=True):
        for axis in self._axes.values():
            self.setAxisColumnVisible(axis, role, show=show)

    def __updateAxis(self, axis):
        state = axis.state
        position = axis.position
        step = axis.currentStep
        min_value, max_value = axis.limits

        label_widget = self.axisColumnWidget(axis, Column.Label)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        steps_widget = self.axisColumnWidget(axis, Column.Steps)
        step_left_widget = self.axisColumnWidget(axis, Column.StepLeft)
        step_right_widget = self.axisColumnWidget(axis, Column.StepRight)
        stop_widget = self.axisColumnWidget(axis, Column.Stop)

        if state is State.Moving:
            position_widget.setEnabled(False)
            step_left_widget.setEnabled(False)
            step_right_widget.setEnabled(False)
            label_widget.setModified(False)
        else:
            position_widget.setEnabled(True)
            step_left_widget.setEnabled((position - step) >= min_value)
            step_right_widget.setEnabled((position + step) <= max_value)
            label_widget.setModified(position_widget.value() != position)

        toolTip = axis.toolTip()
        label_widget.setToolTip(toolTip)
        position_widget.setToolTip(toolTip)
        steps_widget.setToolTip(toolTip)
        step_left_widget.setToolTip(toolTip)
        step_right_widget.setToolTip(toolTip)
        stop_widget.setToolTip(toolTip)

    def refreshAxes(self):
        for axis in self.axes().values():
            axis.refresh()

    #
    # slots to react on user interaction
    #

    def onUserPositionApplied(self):
        widget = self.sender()
        axis = widget.axis
        position = widget.value()
        label = self.axisColumnWidget(axis, Column.Label)
        label.setModified(False)
        axis.move(position)

    def onUserPositionChanged(self, value):
        widget = self.sender()
        axis = widget.axis
        label_w = self.axisColumnWidget(axis, Column.Label)
        label_w.setModified(widget.value() != axis.position)

    def onUserCurrentStepsChanged(self, index):
        widget = self.sender()
        step = widget.itemData(index)
        axis = widget.axis
        axis.currentStep = step

        position_widget = self.axisColumnWidget(axis, Column.Position)
        position_widget.setSingleStep(step)

        self.__updateAxis(axis)

    def onUserStepLeft(self):
        widget = self.sender()
        axis = widget.axis
        axis.stepDown()

    def onUserStepRight(self):
        widget = self.sender()
        axis = widget.axis
        axis.stepUp()

    def onUserStop(self):
        widget = self.sender()
        axis = widget.axis
        axis.stop()

    #
    # axis has changed programatically through a signal coming from the model
    #

    def onAxisPositionChanged(self, name, position):
        axis = self.getAxis(name)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        position_widget.setValue(position, emit=False)
        self.__updateAxis(axis)

    def onAxisStateChanged(self, name, old_state, state):
        axis = self.getAxis(name)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        position_widget.setState(state)
        if self.updateStatusBar and old_state != state:
            icon = Icon(state)
            message = axis.label + " "
            if state == State.Moving:
                message += "started to move..."
            elif old_state == State.Moving:
                message += "stopped!"
            else:
                message += "changed from {0} to {1}".format(
                    old_state.name, state.name)
            self.__setStatus(message, icon)
        self.__updateAxis(axis)

    def onAxisLabelChanged(self, name, label):
        axis = self.getAxis(name)
        label_widget = self.axisColumnWidget(axis, Column.Label)
        label_widget.setValue(label)

    def onAxisStepsChanged(self, name, steps):
        axis = self.getAxis(name)
        steps_widget = self.axisColumnWidget(axis, Column.Steps)
        steps_widget.setSteps(steps)
        self.__updateAxis(axis)

    def onAxisCurrentStepChanged(self, name, step):
        """Steps changed from the Axis model:

        - change the current step value on the combo box
        - change the step size on the position spin box
        - update (enable/disable the stepLeft and stepRight buttons according
          to the current axis limits)
        """
        axis = self.getAxis(name)
        steps_widget = self.axisColumnWidget(axis, Column.Steps)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        steps_widget.setCurrentStep(step)
        position_widget.setSingleStep(step)
        self.__updateAxis(axis)

    def onAxisLimitsChanged(self, name, limits):
        axis = self.getAxis(name)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        if limits is None:
            limits = [float("-inf"), float("+inf")]
        position_widget.setRange(*limits)
        self.__updateAxis(axis)

    def onAxisUnitChanged(self, name, unit):
        axis = self.getAxis(name)
        position_widget = self.axisColumnWidget(axis, Column.Position)
        position_widget.setUnit(unit)
        self.__updateAxis(axis)

    def __setStatus(self, message, icon=QtGui.QStyle.SP_MessageBoxInformation):
        if not self.updateStatusBar:
            return
        statusBar = getStatusBar(self)
        if statusBar is None:
            return
        if hasattr(statusBar, 'setStatus'):
            statusBar.setStatus(message, icon)
        else:
            statusBar.showMessage(message)

    def setUpdateStatusBar(self, update):
        self.__updateStatusBar = update

    def getUdpateStatusBar(self):
        return self.__updateStatusBar

    def resetUpdateStatusBar(self):
        self.setUpdateStatusBar(self.DefaultUpdateStatusBar)

    @classmethod
    def getQtDesignerPluginInfo(cls):
        return dict(icon=":/designer/motor.png",
                    tooltip="a multiple axis (axes) widget")

    #: This property sets if the widget should update stauts bar with messages
    #:
    #: **Access functions:**
    #:
    #: * :meth:`AxesWidget.getUdpateStatusBar`
    #: * :meth:`AxesWidget.setUpdateStatusBar`
    #: * :meth:`AxesWidget.resetUpdateStatusBar`
    updateStatusBar = QtCore.Property(bool, getUdpateStatusBar,
                                      setUpdateStatusBar, resetUpdateStatusBar)
Пример #7
0
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)
Пример #8
0
class XEmbedCommandWidget(QtGui.QX11EmbedContainer):
    """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 XEmbedCommandWidget
        
        app = Application()
        w = QtGui.QMainWindow()
        cmdWidget = XEmbedCommandWidget(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(XEmbedCommandWidget, self).__init__(parent)
        self.error.connect(self.__onError)
        self.__process = process = QtCore.QProcess(self)
        self.resetCommand()
        self.resetAutoRestart()
        self.resetWinIdParam()
        self.resetExtraParams()

    def __onError(self, error):
        logging.error("XEmbedContainer: Error")

    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 __convert_wait(self, wait):
        if wait:
            if wait < 0:
                wait = -1
            else:
                wait = int(wait * 1000)
        return wait

    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.winId())] + 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 __finish(self, finish_func, wait=0):
        process = self.__process
        wait = self.__convert_wait(wait)
        finish_func()
        if wait:
            return process.waitForFinished(msecs=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 event(self, event):
        ret = super(XEmbedCommandWidget, self).event(event)
        etype = event.type()
        if etype == QtCore.QEvent.ParentAboutToChange:
            if self.__process.state() != QtCore.QProcess.NotRunning:
                self.terminate()
        elif etype == QtCore.QEvent.ParentChange:
            if self.autoRestart:
                logging.info("restarting...")
                self.restart(wait=3)
        return ret

    def destroy(self, *args, **kwargs):
        print("Destroying embeded widget")
        logging.warning("Destroying embeded widget")
        self.terminate(wait=-1)
        return super(XEmbedCommandWidget, self).destroy(*args, **kwargs)

    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)