Esempio n. 1
0
class QSignalingMainWindow(QtGui.QMainWindow):

	closed = qt_compat.Signal()
	hidden = qt_compat.Signal()
	shown = qt_compat.Signal()
	resized = qt_compat.Signal()

	def __init__(self, *args, **kwd):
		QtGui.QMainWindow.__init__(*((self, )+args), **kwd)

	def closeEvent(self, event):
		val = QtGui.QMainWindow.closeEvent(self, event)
		self.closed.emit()
		return val

	def hideEvent(self, event):
		val = QtGui.QMainWindow.hideEvent(self, event)
		self.hidden.emit()
		return val

	def showEvent(self, event):
		val = QtGui.QMainWindow.showEvent(self, event)
		self.shown.emit()
		return val

	def resizeEvent(self, event):
		val = QtGui.QMainWindow.resizeEvent(self, event)
		self.resized.emit()
		return val
Esempio n. 2
0
class _WorkerThread(QtCore.QObject):

	_taskComplete  = qt_compat.Signal(object)

	def __init__(self, futureThread):
		QtCore.QObject.__init__(self)
		self._futureThread = futureThread
		self._futureThread._addTask.connect(self._on_task_added)
		self._taskComplete.connect(self._futureThread._on_task_complete)

	@qt_compat.Slot(object)
	@misc.log_exception(_moduleLogger)
	def _on_task_added(self, task):
		self.__on_task_added(task)

	@misc.log_exception(_moduleLogger)
	def __on_task_added(self, task):
		if not self._futureThread._isRunning:
			_moduleLogger.error("Dropping task")

		func, args, kwds, on_success, on_error = task

		try:
			result = func(*args, **kwds)
			isError = False
		except Exception, e:
			_moduleLogger.error("Error, passing it back to the main thread")
			result = e
			isError = True

		taskResult = on_success, on_error, isError, result
		self._taskComplete.emit(taskResult)
Esempio n. 3
0
class QErrorMessage(QtCore.QObject):

	LEVEL_ERROR = logging.ERROR
	LEVEL_WARNING = logging.WARNING
	LEVEL_INFO = logging.INFO
	LEVEL_BUSY = -1

	def __init__(self, message, level):
		QtCore.QObject.__init__(self)
		self._message = message
		self._level = level

	changed = qt_compat.Signal()
	level = qt_compat.Property(int, lambda self: self._level, notify=changed)
	message = qt_compat.Property(unicode, lambda self: self._message, notify=changed)

	def __repr__(self):
		return "%s.%s(%r, %r)" % (__name__, self.__class__.__name__, self._message, self._level)
Esempio n. 4
0
class FutureThread(QtCore.QObject):

	_addTask = qt_compat.Signal(object)

	def __init__(self):
		QtCore.QObject.__init__(self)
		self._thread = QThread44()
		self._isRunning = False
		self._worker = _WorkerThread(self)
		self._worker.moveToThread(self._thread)

	def start(self):
		self._thread.start()
		self._isRunning = True

	def stop(self):
		self._isRunning = False
		self._thread.quit()
		self._thread.wait()

	def add_task(self, func, args, kwds, on_success, on_error):
		assert self._isRunning, "Task queue not started"
		task = func, args, kwds, on_success, on_error
		self._addTask.emit(task)

	@qt_compat.Slot(object)
	@misc.log_exception(_moduleLogger)
	def _on_task_complete(self, taskResult):
		self.__on_task_complete(taskResult)

	@misc.log_exception(_moduleLogger)
	def __on_task_complete(self, taskResult):
		on_success, on_error, isError, result = taskResult
		if not self._isRunning:
			if isError:
				_moduleLogger.error("Masking: %s" % (result, ))
			isError = True
			result = StopIteration("Cancelling all callbacks")
		callback = on_success if not isError else on_error
		try:
			callback(result)
		except Exception:
			_moduleLogger.exception("Callback errored")
Esempio n. 5
0
	class AutoQObject(QtCore.QObject):

		def __init__(self, **initKwargs):
			QtCore.QObject.__init__(self)

		def __repr__(self):
			return '<%s (wrapping %r)>' % (
				kwargs.get('name', self.__class__.__name__),
				obj,
			)

		changed = qt_compat.Signal()

		for key, value in members:
			qTypeName = obj_to_qtype(value)

			def _get(key):
				def _get(self):
					return getattr(obj, key)
				return _get

			def _set(key):
				if key == key.upper():
					def _set_constant(self, v):
						raise NotImplementedError()
					return _set_constant
				else:
					def _set_mutable(self, v):
						setattr(obj, key, v)
						getattr(self, "changed").emit()
					return _set_mutable

			setter = locals()['_set_'+key] = _set(key)
			getter = locals()['_get_'+key] = _get(key)

			locals()[key] = qt_compat.Property(qTypeName, getter, setter, notify=changed)
		del _get, _set, getter, setter, qTypeName
Esempio n. 6
0
	class AutoQObject(QtCore.QObject):

		def __init__(self, **initKwargs):
			QtCore.QObject.__init__(self)
			for key, val in classDef:
				setattr(self, '_'+key, initKwargs.get(key, val()))

		def __repr__(self):
			qTypeNames = (
				'%s=%r' % (key, getattr(self, '_'+key))
				for key, qTypeName in classDef
			)
			return '<%s (%s)>' % (
				kwargs.get('name', self.__class__.__name__),
				', '.join(qTypeNames),
			)

		for key, qTypeName in classDef:
			nfy = locals()['_nfy_'+key] = qt_compat.Signal()

			def _get(key):
				def f(self):
					return self.__dict__['_'+key]
				return f

			def _set(key):
				def f(self, qTypeName):
					setattr(self, '_'+key, qTypeName)
					getattr(self, '_nfy_'+key).emit()
				return f

			setter = locals()['_set_'+key] = _set(key)
			getter = locals()['_get_'+key] = _get(key)

			locals()[key] = qt_compat.Property(qTypeName, getter, setter, notify=nfy)
		del nfy, _get, _set, getter, setter
Esempio n. 7
0
class Buffer(QtCore.QObject):
    """A WeeChat buffer."""

    bufferInput = qt_compat.Signal(str, str)

    def __init__(self, data={}):
        QtCore.QObject.__init__(self)
        self.data = data
        self.nicklist = {}
        self.widget = BufferWidget(
            display_nicklist=self.data.get('nicklist', 0))
        self.update_title()
        self.update_prompt()
        self.widget.input.textSent.connect(self.input_text_sent)

    def pointer(self):
        """Return pointer on buffer."""
        return self.data.get('__path', [''])[0]

    def update_title(self):
        """Update title."""
        try:
            self.widget.set_title(
                color.remove(self.data['title'].decode('utf-8')))
        except:  # noqa: E722
            self.widget.set_title(None)

    def update_prompt(self):
        """Update prompt."""
        try:
            self.widget.set_prompt(self.data['local_variables']['nick'])
        except:  # noqa: E722
            self.widget.set_prompt(None)

    def input_text_sent(self, text):
        """Called when text has to be sent to buffer."""
        if self.data:
            self.bufferInput.emit(self.data['full_name'], text)

    def nicklist_add_item(self, parent, group, prefix, name, visible):
        """Add a group/nick in nicklist."""
        if group:
            self.nicklist[name] = {'visible': visible, 'nicks': []}
        else:
            self.nicklist[parent]['nicks'].append({
                'prefix': prefix,
                'name': name,
                'visible': visible,
            })

    def nicklist_remove_item(self, parent, group, name):
        """Remove a group/nick from nicklist."""
        if group:
            if name in self.nicklist:
                del self.nicklist[name]
        else:
            if parent in self.nicklist:
                self.nicklist[parent]['nicks'] = [
                    nick for nick in self.nicklist[parent]['nicks']
                    if nick['name'] != name
                ]

    def nicklist_update_item(self, parent, group, prefix, name, visible):
        """Update a group/nick in nicklist."""
        if group:
            if name in self.nicklist:
                self.nicklist[name]['visible'] = visible
        else:
            if parent in self.nicklist:
                for nick in self.nicklist[parent]['nicks']:
                    if nick['name'] == name:
                        nick['prefix'] = prefix
                        nick['visible'] = visible
                        break

    def nicklist_refresh(self):
        """Refresh nicklist."""
        self.widget.nicklist.clear()
        for group in sorted(self.nicklist):
            for nick in sorted(self.nicklist[group]['nicks'],
                               key=lambda n: n['name']):
                prefix_color = {
                    '': '',
                    ' ': '',
                    '+': 'yellow',
                }
                color = prefix_color.get(nick['prefix'], 'green')
                if color:
                    icon = QtGui.QIcon(
                        resource_filename(
                            __name__, 'data/icons/bullet_%s_8x8.png' % color))
                else:
                    pixmap = QtGui.QPixmap(8, 8)
                    pixmap.fill()
                    icon = QtGui.QIcon(pixmap)
                item = QtGui.QListWidgetItem(icon, nick['name'])
                self.widget.nicklist.addItem(item)
                self.widget.nicklist.setVisible(True)
Esempio n. 8
0
class InputLineEdit(QtGui.QLineEdit):
    """Input line."""

    bufferSwitchPrev = qt_compat.Signal()
    bufferSwitchNext = qt_compat.Signal()
    textSent = qt_compat.Signal(str)

    def __init__(self, scroll_widget):
        QtGui.QLineEdit.__init__(self)
        self.scroll_widget = scroll_widget
        self._history = []
        self._history_index = -1
        self.returnPressed.connect(self._input_return_pressed)

    def keyPressEvent(self, event):
        key = event.key()
        modifiers = event.modifiers()
        bar = self.scroll_widget.verticalScrollBar()
        if modifiers == QtCore.Qt.ControlModifier:
            if key == QtCore.Qt.Key_PageUp:
                self.bufferSwitchPrev.emit()
            elif key == QtCore.Qt.Key_PageDown:
                self.bufferSwitchNext.emit()
            else:
                QtGui.QLineEdit.keyPressEvent(self, event)
        elif modifiers == QtCore.Qt.AltModifier:
            if key in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Up):
                self.bufferSwitchPrev.emit()
            elif key in (QtCore.Qt.Key_Right, QtCore.Qt.Key_Down):
                self.bufferSwitchNext.emit()
            elif key == QtCore.Qt.Key_PageUp:
                bar.setValue(bar.value() - (bar.pageStep() / 10))
            elif key == QtCore.Qt.Key_PageDown:
                bar.setValue(bar.value() + (bar.pageStep() / 10))
            elif key == QtCore.Qt.Key_Home:
                bar.setValue(bar.minimum())
            elif key == QtCore.Qt.Key_End:
                bar.setValue(bar.maximum())
            else:
                QtGui.QLineEdit.keyPressEvent(self, event)
        elif key == QtCore.Qt.Key_PageUp:
            bar.setValue(bar.value() - bar.pageStep())
        elif key == QtCore.Qt.Key_PageDown:
            bar.setValue(bar.value() + bar.pageStep())
        elif key == QtCore.Qt.Key_Up:
            self._history_navigate(-1)
        elif key == QtCore.Qt.Key_Down:
            self._history_navigate(1)
        else:
            QtGui.QLineEdit.keyPressEvent(self, event)

    def _input_return_pressed(self):
        self._history.append(self.text().encode('utf-8'))
        self._history_index = len(self._history)
        self.textSent.emit(self.text())
        self.clear()

    def _history_navigate(self, direction):
        if self._history:
            self._history_index += direction
            if self._history_index < 0:
                self._history_index = 0
                return
            if self._history_index > len(self._history) - 1:
                self._history_index = len(self._history)
                self.clear()
                return
            self.setText(self._history[self._history_index])
Esempio n. 9
0
class Network(QtCore.QObject):
    """I/O with WeeChat/relay."""

    statusChanged = qt_compat.Signal(str, str)
    messageFromWeechat = qt_compat.Signal(QtCore.QByteArray)

    def __init__(self, *args):
        QtCore.QObject.__init__(*(self, ) + args)
        self.status_disconnected = 'disconnected'
        self.status_connecting = 'connecting...'
        self.status_connected = 'connected'
        self._server = None
        self._port = None
        self._ssl = None
        self._password = None
        self._lines = config.CONFIG_DEFAULT_RELAY_LINES
        self._buffer = QtCore.QByteArray()
        self._socket = QtNetwork.QSslSocket()
        self._socket.connected.connect(self._socket_connected)
        self._socket.error.connect(self._socket_error)
        self._socket.readyRead.connect(self._socket_read)
        self._socket.disconnected.connect(self._socket_disconnected)

    def _socket_connected(self):
        """Slot: socket connected."""
        self.statusChanged.emit(self.status_connected, None)
        if self._password:
            self.send_to_weechat(
                '\n'.join(_PROTO_INIT_CMD + _PROTO_SYNC_CMDS) % {
                    'password': str(self._password),
                    'lines': self._lines
                })

    def _socket_error(self, error):
        """Slot: socket error."""
        self.statusChanged.emit(
            self.status_disconnected,
            'Failed, error: %s' % self._socket.errorString())

    def _socket_read(self):
        """Slot: data available on socket."""
        data = self._socket.readAll()
        self._buffer.append(data)
        while len(self._buffer) >= 4:
            remainder = None
            length = struct.unpack('>i', self._buffer[0:4])[0]
            if len(self._buffer) < length:
                # partial message, just wait for end of message
                break
            # more than one message?
            if length < len(self._buffer):
                # save beginning of another message
                remainder = self._buffer[length:]
                self._buffer = self._buffer[0:length]
            self.messageFromWeechat.emit(self._buffer)
            if not self.is_connected():
                return
            self._buffer.clear()
            if remainder:
                self._buffer.append(remainder)

    def _socket_disconnected(self):
        """Slot: socket disconnected."""
        self._server = None
        self._port = None
        self._ssl = None
        self._password = None
        self.statusChanged.emit(self.status_disconnected, None)

    def is_connected(self):
        """Return True if the socket is connected, False otherwise."""
        return self._socket.state() == QtNetwork.QAbstractSocket.ConnectedState

    def is_ssl(self):
        """Return True if SSL is used, False otherwise."""
        return self._ssl

    def connect_weechat(self, server, port, ssl, password, lines):
        """Connect to WeeChat."""
        self._server = server
        try:
            self._port = int(port)
        except ValueError:
            self._port = 0
        self._ssl = ssl
        self._password = password
        try:
            self._lines = int(lines)
        except ValueError:
            self._lines = config.CONFIG_DEFAULT_RELAY_LINES
        if self._socket.state() == QtNetwork.QAbstractSocket.ConnectedState:
            return
        if self._socket.state() != QtNetwork.QAbstractSocket.UnconnectedState:
            self._socket.abort()
        self._socket.connectToHost(self._server, self._port)
        if self._ssl:
            self._socket.ignoreSslErrors()
            self._socket.startClientEncryption()
        self.statusChanged.emit(self.status_connecting, None)

    def disconnect_weechat(self):
        """Disconnect from WeeChat."""
        if self._socket.state() == QtNetwork.QAbstractSocket.UnconnectedState:
            return
        if self._socket.state() == QtNetwork.QAbstractSocket.ConnectedState:
            self.send_to_weechat('quit\n')
            self._socket.waitForBytesWritten(1000)
        else:
            self.statusChanged.emit(self.status_disconnected, None)
        self._socket.abort()

    def send_to_weechat(self, message):
        """Send a message to WeeChat."""
        self._socket.write(message.encode('utf-8'))

    def desync_weechat(self):
        """Desynchronize from WeeChat."""
        self.send_to_weechat('desync\n')

    def sync_weechat(self):
        """Synchronize with WeeChat."""
        self.send_to_weechat('\n'.join(_PROTO_SYNC_CMDS))

    def status_icon(self, status):
        """Return the name of icon for a given status."""
        icon = {
            self.status_disconnected: 'dialog-close.png',
            self.status_connecting: 'dialog-close.png',
            self.status_connected: 'dialog-ok-apply.png',
        }
        return icon.get(status, '')

    def get_options(self):
        """Get connection options."""
        return {
            'server': self._server,
            'port': self._port,
            'ssl': 'on' if self._ssl else 'off',
            'password': self._password,
            'lines': str(self._lines),
        }
Esempio n. 10
0
class QPieMenu(QtGui.QWidget):

    activated = qt_compat.Signal(int)
    highlighted = qt_compat.Signal(int)
    canceled = qt_compat.Signal()
    aboutToShow = qt_compat.Signal()
    aboutToHide = qt_compat.Signal()

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self._cachedCenterPosition = self.rect().center()

        self._filing = PieFiling()
        self._artist = PieArtist(self._filing)
        self._selectionIndex = PieFiling.SELECTION_NONE

        self._mousePosition = ()
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

    def popup(self, pos):
        self._update_selection(pos)
        self.show()

    def insertItem(self, item, index=-1):
        self._filing.insertItem(item, index)
        self.update()

    def removeItemAt(self, index):
        self._filing.removeItemAt(index)
        self.update()

    def set_center(self, item):
        self._filing.set_center(item)
        self.update()

    def clear(self):
        self._filing.clear()
        self.update()

    def itemAt(self, index):
        return self._filing.itemAt(index)

    def indexAt(self, point):
        return self._filing.indexAt(self._cachedCenterPosition, point)

    def innerRadius(self):
        return self._filing.innerRadius()

    def setInnerRadius(self, radius):
        self._filing.setInnerRadius(radius)
        self.update()

    def outerRadius(self):
        return self._filing.outerRadius()

    def setOuterRadius(self, radius):
        self._filing.setOuterRadius(radius)
        self.update()

    def sizeHint(self):
        return self._artist.pieSize()

    @misc_utils.log_exception(_moduleLogger)
    def mousePressEvent(self, mouseEvent):
        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        self._update_selection(lastMousePos)
        self._mousePosition = lastMousePos

        if lastSelection != self._selectionIndex:
            self.highlighted.emit(self._selectionIndex)
            self.update()

    @misc_utils.log_exception(_moduleLogger)
    def mouseMoveEvent(self, mouseEvent):
        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        self._update_selection(lastMousePos)

        if lastSelection != self._selectionIndex:
            self.highlighted.emit(self._selectionIndex)
            self.update()

    @misc_utils.log_exception(_moduleLogger)
    def mouseReleaseEvent(self, mouseEvent):
        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        self._update_selection(lastMousePos)
        self._mousePosition = ()

        self._activate_at(self._selectionIndex)
        self.update()

    @misc_utils.log_exception(_moduleLogger)
    def keyPressEvent(self, keyEvent):
        if keyEvent.key() in [
                QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab
        ]:
            if self._selectionIndex != len(self._filing) - 1:
                nextSelection = self._selectionIndex + 1
            else:
                nextSelection = 0
            self._select_at(nextSelection)
            self.update()
        elif keyEvent.key() in [
                QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab
        ]:
            if 0 < self._selectionIndex:
                nextSelection = self._selectionIndex - 1
            else:
                nextSelection = len(self._filing) - 1
            self._select_at(nextSelection)
            self.update()
        elif keyEvent.key() in [
                QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space
        ]:
            self._activate_at(self._selectionIndex)
        elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
            self._activate_at(PieFiling.SELECTION_NONE)
        else:
            QtGui.QWidget.keyPressEvent(self, keyEvent)

    @misc_utils.log_exception(_moduleLogger)
    def showEvent(self, showEvent):
        self.aboutToShow.emit()
        self._cachedCenterPosition = self.rect().center()

        mask = self._artist.show(self.palette())
        self.setMask(mask)

        lastMousePos = self.mapFromGlobal(QtGui.QCursor.pos())
        self._update_selection(lastMousePos)

        QtGui.QWidget.showEvent(self, showEvent)

    @misc_utils.log_exception(_moduleLogger)
    def hideEvent(self, hideEvent):
        self._artist.hide()
        self._selectionIndex = PieFiling.SELECTION_NONE
        QtGui.QWidget.hideEvent(self, hideEvent)

    @misc_utils.log_exception(_moduleLogger)
    def paintEvent(self, paintEvent):
        canvas = self._artist.paint(self._selectionIndex)

        screen = QtGui.QPainter(self)
        screen.drawPixmap(QtCore.QPoint(0, 0), canvas)

        QtGui.QWidget.paintEvent(self, paintEvent)

    def __iter__(self):
        return iter(self._filing)

    def __len__(self):
        return len(self._filing)

    def _select_at(self, index):
        self._selectionIndex = index

    def _update_selection(self, lastMousePos):
        radius = _radius_at(self._cachedCenterPosition, lastMousePos)
        if radius < self._filing.innerRadius():
            self._selectionIndex = PieFiling.SELECTION_CENTER
        elif radius <= self._filing.outerRadius():
            self._select_at(self.indexAt(lastMousePos))
        else:
            self._selectionIndex = PieFiling.SELECTION_NONE

    def _activate_at(self, index):
        if index == PieFiling.SELECTION_NONE:
            self.canceled.emit()
            self.aboutToHide.emit()
            self.hide()
            return
        elif index == PieFiling.SELECTION_CENTER:
            child = self._filing.center()
        else:
            child = self.itemAt(index)

        if child.isEnabled():
            child.action().trigger()
            self.activated.emit(index)
        else:
            self.canceled.emit()
        self.aboutToHide.emit()
        self.hide()
Esempio n. 11
0
class QPieButton(QtGui.QWidget):

    activated = qt_compat.Signal(int)
    highlighted = qt_compat.Signal(int)
    canceled = qt_compat.Signal()
    aboutToShow = qt_compat.Signal()
    aboutToHide = qt_compat.Signal()

    BUTTON_RADIUS = 24
    DELAY = 250

    def __init__(self, buttonSlice, parent=None, buttonSlices=None):
        # @bug Artifacts on Maemo 5 due to window 3D effects, find way to disable them for just these?
        # @bug The pie's are being pushed back on screen on Maemo, leading to coordinate issues
        QtGui.QWidget.__init__(self, parent)
        self._cachedCenterPosition = self.rect().center()

        self._filing = PieFiling()
        self._display = QPieDisplay(self._filing, None, QtCore.Qt.SplashScreen)
        self._selectionIndex = PieFiling.SELECTION_NONE

        self._buttonFiling = PieFiling()
        self._buttonFiling.set_center(buttonSlice)
        if buttonSlices is not None:
            for slice in buttonSlices:
                self._buttonFiling.insertItem(slice)
        self._buttonFiling.setOuterRadius(self.BUTTON_RADIUS)
        self._buttonArtist = PieArtist(self._buttonFiling,
                                       PieArtist.BACKGROUND_NOFILL)
        self._poppedUp = False
        self._pressed = False

        self._delayPopupTimer = QtCore.QTimer()
        self._delayPopupTimer.setInterval(self.DELAY)
        self._delayPopupTimer.setSingleShot(True)
        self._delayPopupTimer.timeout.connect(self._on_delayed_popup)
        self._popupLocation = None

        self._mousePosition = None
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setSizePolicy(
            QtGui.QSizePolicy(
                QtGui.QSizePolicy.MinimumExpanding,
                QtGui.QSizePolicy.MinimumExpanding,
            ))

    def insertItem(self, item, index=-1):
        self._filing.insertItem(item, index)

    def removeItemAt(self, index):
        self._filing.removeItemAt(index)

    def set_center(self, item):
        self._filing.set_center(item)

    def set_button(self, item):
        self.update()

    def clear(self):
        self._filing.clear()

    def itemAt(self, index):
        return self._filing.itemAt(index)

    def indexAt(self, point):
        return self._filing.indexAt(self._cachedCenterPosition, point)

    def innerRadius(self):
        return self._filing.innerRadius()

    def setInnerRadius(self, radius):
        self._filing.setInnerRadius(radius)

    def outerRadius(self):
        return self._filing.outerRadius()

    def setOuterRadius(self, radius):
        self._filing.setOuterRadius(radius)

    def buttonRadius(self):
        return self._buttonFiling.outerRadius()

    def setButtonRadius(self, radius):
        self._buttonFiling.setOuterRadius(radius)
        self._buttonFiling.setInnerRadius(radius / 2)
        self._buttonArtist.show(self.palette())

    def minimumSizeHint(self):
        return self._buttonArtist.centerSize()

    @misc_utils.log_exception(_moduleLogger)
    def mousePressEvent(self, mouseEvent):
        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        self._mousePosition = lastMousePos
        self._update_selection(self._cachedCenterPosition)

        self.highlighted.emit(self._selectionIndex)

        self._display.selectAt(self._selectionIndex)
        self._pressed = True
        self.update()
        self._popupLocation = mouseEvent.globalPos()
        self._delayPopupTimer.start()

    @misc_utils.log_exception(_moduleLogger)
    def _on_delayed_popup(self):
        assert self._popupLocation is not None, "Widget location abuse"
        self._popup_child(self._popupLocation)

    @misc_utils.log_exception(_moduleLogger)
    def mouseMoveEvent(self, mouseEvent):
        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        if self._mousePosition is None:
            # Absolute
            self._update_selection(lastMousePos)
        else:
            # Relative
            self._update_selection(
                self._cachedCenterPosition +
                (lastMousePos - self._mousePosition),
                ignoreOuter=True,
            )

        if lastSelection != self._selectionIndex:
            self.highlighted.emit(self._selectionIndex)
            self._display.selectAt(self._selectionIndex)

        if self._selectionIndex != PieFiling.SELECTION_CENTER and self._delayPopupTimer.isActive(
        ):
            self._on_delayed_popup()

    @misc_utils.log_exception(_moduleLogger)
    def mouseReleaseEvent(self, mouseEvent):
        self._delayPopupTimer.stop()
        self._popupLocation = None

        lastSelection = self._selectionIndex

        lastMousePos = mouseEvent.pos()
        if self._mousePosition is None:
            # Absolute
            self._update_selection(lastMousePos)
        else:
            # Relative
            self._update_selection(
                self._cachedCenterPosition +
                (lastMousePos - self._mousePosition),
                ignoreOuter=True,
            )
        self._mousePosition = None

        self._activate_at(self._selectionIndex)
        self._pressed = False
        self.update()
        self._hide_child()

    @misc_utils.log_exception(_moduleLogger)
    def keyPressEvent(self, keyEvent):
        if keyEvent.key() in [
                QtCore.Qt.Key_Right, QtCore.Qt.Key_Down, QtCore.Qt.Key_Tab
        ]:
            self._popup_child(QtGui.QCursor.pos())
            if self._selectionIndex != len(self._filing) - 1:
                nextSelection = self._selectionIndex + 1
            else:
                nextSelection = 0
            self._select_at(nextSelection)
            self._display.selectAt(self._selectionIndex)
        elif keyEvent.key() in [
                QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Backtab
        ]:
            self._popup_child(QtGui.QCursor.pos())
            if 0 < self._selectionIndex:
                nextSelection = self._selectionIndex - 1
            else:
                nextSelection = len(self._filing) - 1
            self._select_at(nextSelection)
            self._display.selectAt(self._selectionIndex)
        elif keyEvent.key() in [QtCore.Qt.Key_Space]:
            self._popup_child(QtGui.QCursor.pos())
            self._select_at(PieFiling.SELECTION_CENTER)
            self._display.selectAt(self._selectionIndex)
        elif keyEvent.key() in [
                QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Space
        ]:
            self._delayPopupTimer.stop()
            self._popupLocation = None
            self._activate_at(self._selectionIndex)
            self._hide_child()
        elif keyEvent.key() in [QtCore.Qt.Key_Escape, QtCore.Qt.Key_Backspace]:
            self._delayPopupTimer.stop()
            self._popupLocation = None
            self._activate_at(PieFiling.SELECTION_NONE)
            self._hide_child()
        else:
            QtGui.QWidget.keyPressEvent(self, keyEvent)

    @misc_utils.log_exception(_moduleLogger)
    def resizeEvent(self, resizeEvent):
        self.setButtonRadius(
            min(resizeEvent.size().width(),
                resizeEvent.size().height()) / 2 - 1)
        QtGui.QWidget.resizeEvent(self, resizeEvent)

    @misc_utils.log_exception(_moduleLogger)
    def showEvent(self, showEvent):
        self._buttonArtist.show(self.palette())
        self._cachedCenterPosition = self.rect().center()

        QtGui.QWidget.showEvent(self, showEvent)

    @misc_utils.log_exception(_moduleLogger)
    def hideEvent(self, hideEvent):
        self._display.hide()
        self._select_at(PieFiling.SELECTION_NONE)
        QtGui.QWidget.hideEvent(self, hideEvent)

    @misc_utils.log_exception(_moduleLogger)
    def paintEvent(self, paintEvent):
        self.setButtonRadius(
            min(self.rect().width(),
                self.rect().height()) / 2 - 1)
        if self._poppedUp:
            selectionIndex = PieFiling.SELECTION_CENTER
        else:
            selectionIndex = PieFiling.SELECTION_NONE

        screen = QtGui.QStylePainter(self)
        screen.setRenderHint(QtGui.QPainter.Antialiasing, True)
        option = QtGui.QStyleOptionButton()
        option.initFrom(self)
        option.state = QtGui.QStyle.State_Sunken if self._pressed else QtGui.QStyle.State_Raised

        screen.drawControl(QtGui.QStyle.CE_PushButton, option)
        self._buttonArtist.paintPainter(selectionIndex, screen)

        QtGui.QWidget.paintEvent(self, paintEvent)

    def __iter__(self):
        return iter(self._filing)

    def __len__(self):
        return len(self._filing)

    def _popup_child(self, position):
        self._poppedUp = True
        self.aboutToShow.emit()

        self._delayPopupTimer.stop()
        self._popupLocation = None

        position = position - QtCore.QPoint(self._filing.outerRadius(),
                                            self._filing.outerRadius())
        self._display.move(position)
        self._display.show()

        self.update()

    def _hide_child(self):
        self._poppedUp = False
        self.aboutToHide.emit()
        self._display.hide()
        self.update()

    def _select_at(self, index):
        self._selectionIndex = index

    def _update_selection(self, lastMousePos, ignoreOuter=False):
        radius = _radius_at(self._cachedCenterPosition, lastMousePos)
        if radius < self._filing.innerRadius():
            self._select_at(PieFiling.SELECTION_CENTER)
        elif radius <= self._filing.outerRadius() or ignoreOuter:
            self._select_at(self.indexAt(lastMousePos))
        else:
            self._select_at(PieFiling.SELECTION_NONE)

    def _activate_at(self, index):
        if index == PieFiling.SELECTION_NONE:
            self.canceled.emit()
            return
        elif index == PieFiling.SELECTION_CENTER:
            child = self._filing.center()
        else:
            child = self.itemAt(index)

        if child.action().isEnabled():
            child.action().trigger()
            self.activated.emit(index)
        else:
            self.canceled.emit()
Esempio n. 12
0
class FileSystemModel(QtCore.QAbstractListModel):
	"""
	Wrapper around QtGui.QFileSystemModel
	"""

	FILEINFOS = [
		"fileName",
		"isDir",
		"filePath",
		"completeSuffix",
		"baseName",
	]

	EXTINFOS = [
		"type",
	]

	ALLINFOS = FILEINFOS + EXTINFOS

	def __init__(self, model, path):
		QtCore.QAbstractListModel.__init__(self)
		self._path = path

		self._model = model
		self._rootIndex = self._model.index(self._path)

		self._child = None
		self.setRoleNames(dict(enumerate(self.ALLINFOS)))
		self._model.directoryLoaded.connect(self._on_directory_loaded)

	childChanged = qt_compat.Signal(QtCore.QObject)

	def _child(self):
		assert self._child is not None
		return self._child

	child = qt_compat.Property(QtCore.QObject, _child, notify=childChanged)

	backendChanged = qt_compat.Signal()

	def _parent(self):
		finfo = self._model.fileInfo(self._rootIndex)
		return finfo.fileName()

	parent = qt_compat.Property(str, _parent, notify=backendChanged)

	@qt_compat.Slot(str)
	@misc.log_exception(_moduleLogger)
	def browse_to(self, path):
		if self._child is None:
			self._child = FileSystemModel(self._model, path)
		else:
			self._child.switch_to(path)
		self.childChanged.emit()
		return self._child

	@qt_compat.Slot(str)
	@misc.log_exception(_moduleLogger)
	def switch_to(self, path):
		with scoped_model_reset(self):
			self._path = path
			self._rootIndex = self._model.index(self._path)
		self.backendChanged.emit()

	def __len__(self):
		return self._model.rowCount(self._rootIndex)

	def __getitem__(self, key):
		return self._model.index(key, 0, self._rootIndex)

	def __iter__(self):
		return (self[i] for i in xrange(len(self)))

	def rowCount(self, parent=QtCore.QModelIndex()):
		return len(self)

	def data(self, index, role):
		if index.isValid() and 0 <= role and role < len(self.ALLINFOS):
			internalIndex = self._translate_index(index)
			info = self._model.fileInfo(internalIndex)
			if role < len(self.FILEINFOS):
				field = self.FILEINFOS[role]
				value = getattr(info, field)()
			else:
				role -= len(self.FILEINFOS)
				field = self.EXTINFOS[role]
				if field == "type":
					return self._model.type(internalIndex)
				else:
					raise NotImplementedError("Out of range that was already checked")
			return value
		return None

	def _on_directory_loaded(self, path):
		if self._path == path:
			self.backendChanged.emit()
			self.reset()

	def _translate_index(self, externalIndex):
		internalIndex = self._model.index(externalIndex.row(), 0, self._rootIndex)
		return internalIndex
Esempio n. 13
0
class QErrorLog(QtCore.QObject):

	messagePushed = qt_compat.Signal()
	messagePopped = qt_compat.Signal()
	currentMessageChanged = qt_compat.Signal()

	def __init__(self):
		QtCore.QObject.__init__(self)
		self._messages = []
		self._nullMessage = QErrorMessage("", QErrorMessage.LEVEL_INFO)

	@qt_compat.Slot(str)
	def push_busy(self, message):
		_moduleLogger.debug("Entering state: %s" % message)
		self._push_message(message, QErrorMessage.LEVEL_BUSY)

	@qt_compat.Slot(str)
	def push_info(self, message):
		self._push_message(message, QErrorMessage.LEVEL_INFO)

	@qt_compat.Slot(str)
	def push_error(self, message):
		self._push_message(message, QErrorMessage.LEVEL_ERROR)

	@qt_compat.Slot(str, int)
	def push_message(self, message, level):
		self._push_message(message, level)

	def push_exception(self):
		userMessage = str(sys.exc_info()[1])
		_moduleLogger.exception(userMessage)
		self.push_error(userMessage)

	@qt_compat.Slot()
	@qt_compat.Slot(str)
	def pop(self, message = None):
		if message is None:
			del self._messages[0]
		else:
			_moduleLogger.debug("Exiting state: %s" % message)
			messageIndex = [
				i
				for (i, error) in enumerate(self._messages)
				if error.message == message
			]
			# Might be removed out of order
			if messageIndex:
				del self._messages[messageIndex[0]]
		self.messagePopped.emit()
		self.currentMessageChanged.emit()

	def peek_message(self):
		if self._messages:
			return self._messages[0]
		else:
			return self._nullMessage

	currentMessage = qt_compat.Property(QtCore.QObject, lambda self: self.peek_message(), notify=currentMessageChanged)
	hasMessages = qt_compat.Property(bool, lambda self: bool(self._messages), notify=currentMessageChanged)

	def _push_message(self, message, level):
		self._messages.append(QErrorMessage(message, level))
		# Sort is defined as stable, so this should be fine
		self._messages.sort(key=lambda x: x.level)
		self._messages.reverse()
		self.messagePushed.emit()
		self.currentMessageChanged.emit()

	def __len__(self):
		return len(self._messages)