Example #1
0
def _QTest_qWaitForWindowActive(widget, timeout=1000):
    # A Qt5 compatible (probably) QTest.qWaitForWindowActive(QWidget, int)
    # (mostly copied from qtestsystem.h in qt5/qtbase)
    from AnyQt.QtCore import \
        Qt, QCoreApplication, QEventLoop, QElapsedTimer, QEvent
    window = widget.window()
    timer = QElapsedTimer()
    timer.start()

    while not window.isActiveWindow():
        remaining = timeout - timer.elapsed()
        if remaining <= 0:
            break
        QCoreApplication.processEvents(QEventLoop.AllEvents, remaining)
        QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
        QTest.qSleep(10)

    # See the explanation in qtestsystem.h
    if window.isActiveWindow():
        wait_no = 0
        while window.pos().isNull():
            if wait_no > timeout // 10:
                break
            wait_no += 1
            QTest.qWait(10)

    return window.isActiveWindow()
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.__searchline = QLineEdit(self, visible=False, frame=False)
     self.__searchline.setAttribute(Qt.WA_MacShowFocusRect, False)
     self.__searchline.setFocusProxy(self)
     self.__popup = None  # type: Optional[QAbstractItemModel]
     self.__proxy = None  # type: Optional[QSortFilterProxyModel]
     self.__popupTimer = QElapsedTimer()
     self.setFocusPolicy(Qt.ClickFocus | Qt.TabFocus)
Example #3
0
 def __init__(self, parent=None, **kwargs):
     self.__maximumContentsLength = MAXIMUM_CONTENTS_LENGTH
     self.__searchline = QLineEdit(visible=False, frame=False)
     self.__searchline.setAttribute(Qt.WA_MacShowFocusRect, False)
     self.__popup = None  # type: Optional[QAbstractItemModel]
     self.__proxy = None  # type: Optional[QSortFilterProxyModel]
     self.__popupTimer = QElapsedTimer()
     super().__init__(parent, **kwargs)
     self.__searchline.setParent(self)
     self.__searchline.setFocusProxy(self)
     self.setFocusPolicy(Qt.ClickFocus | Qt.TabFocus)
Example #4
0
 def get_output(self, widget, signal_name, timeout=DEFAULT_TIMEOUT):
     if not isinstance(signal_name, str):
         signal_name = signal_name.name
     elapsed = QElapsedTimer()
     if widget.isInvalidated():
         elapsed.start()
         spy = QSignalSpy(widget.invalidatedStateChanged)
         assert spy.wait(timeout)
         timeout = timeout - elapsed.elapsed()
     value = self.outputs.get((widget, signal_name))
     if isinstance(value, _Invalidated) and timeout >= 0:
         spy = QSignalSpy(value.completed)
         assert spy.wait(timeout), "Failed to get output in the specified timeout"
         assert len(spy) == 1
         value = spy[0][0]
     return value
Example #5
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.__searchline = QLineEdit(self, visible=False, frame=False)
     self.__searchline.setAttribute(Qt.WA_MacShowFocusRect, False)
     self.__searchline.setFocusProxy(self)
     self.__popup = None  # type: Optional[QAbstractItemModel]
     self.__proxy = None  # type: Optional[QSortFilterProxyModel]
     self.__popupTimer = QElapsedTimer()
     self.setFocusPolicy(Qt.ClickFocus | Qt.TabFocus)
Example #6
0
def _QTest_qWaitForWindowExposed(widget, timeout=1000):
    # A Qt5 compatible (probably) QTest.qWaitForWindowExposed(QWidget, int)
    # (mostly copied from qtestsystem.h in qt5/qtbase)
    from AnyQt.QtCore import \
        Qt, QCoreApplication, QEventLoop, QElapsedTimer, QEvent
    window = widget.window()
    timer = QElapsedTimer()
    timer.start()

    # Is widget.testAttribute(Qt.WA_Mapped) a suitable replacement for
    # QWindow.isExposed in Qt5??
    # Not exactly. In Qt5
    # window().testAttribute(Qt.WA_Mapped) == window().windowHandle.isExposed()
    # but both are False if a window is fully obscured by other windows,
    # in Qt4 there is no difference if a window is obscured.
    while not window.testAttribute(Qt.WA_Mapped):
        remaining = timeout - timer.elapsed()
        if remaining <= 0:
            break
        QCoreApplication.processEvents(QEventLoop.AllEvents, remaining)
        QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
        QTest.qSleep(10)

    return window.testAttribute(Qt.WA_Mapped)
Example #7
0
class ComboBoxSearch(QComboBox):
    """
    A drop down list combo box with filter/search.

    The popup list view is filtered by text entered in the filter field.

    Note
    ----
    `popup`, `lineEdit` and `completer` from the base QComboBox class are
    unused. Setting/modifying them will have no effect.
    """
    # NOTE: Setting editable + QComboBox.NoInsert policy + ... did not achieve
    # the same results.
    def __init__(self, parent=None, **kwargs):
        self.__maximumContentsLength = MAXIMUM_CONTENTS_LENGTH
        self.__searchline = QLineEdit(visible=False, frame=False)
        self.__searchline.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.__popup = None  # type: Optional[QAbstractItemModel]
        self.__proxy = None  # type: Optional[QSortFilterProxyModel]
        self.__popupTimer = QElapsedTimer()
        super().__init__(parent, **kwargs)
        self.__searchline.setParent(self)
        self.__searchline.setFocusProxy(self)
        self.setFocusPolicy(Qt.ClickFocus | Qt.TabFocus)

    def setMaximumContentsLength(self, length):  # type: (int) -> None
        """
        Set the maximum contents length hint.

        The hint specifies the upper bound on the `sizeHint` and
        `minimumSizeHint` width specified in character length.
        Set to 0 or negative value to disable.

        Note
        ----
        This property does not affect the widget's `maximumSize`.
        The widget can still grow depending on its `sizePolicy`.

        Parameters
        ----------
        length : int
            Maximum contents length hint.
        """
        if self.__maximumContentsLength != length:
            self.__maximumContentsLength = length
            self.updateGeometry()

    def _get_size_hint(self):
        sh = super().sizeHint()
        if self.__maximumContentsLength > 0:
            width = (
                self.fontMetrics().width("X") * self.__maximumContentsLength
                + self.iconSize().width() + 4
            )
            sh = sh.boundedTo(QSize(width, sh.height()))
        return sh

    def sizeHint(self):  # type: () -> QSize
        # reimplemented
        return self._get_size_hint()

    def minimumSizeHint(self):  # type: () -> QSize
        # reimplemented
        return self._get_size_hint()

    def showPopup(self):
        # type: () -> None
        """
        Reimplemented from QComboBox.showPopup

        Popup up a customized view and filter edit line.

        Note
        ----
        The .popup(), .lineEdit(), .completer() of the base class are not used.
        """
        if self.__popup is not None:
            # We have user entered state that cannot be disturbed
            # (entered filter text, scroll offset, ...)
            return  # pragma: no cover

        if self.count() == 0:
            return

        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        popup = QListView(
            uniformItemSizes=True,
            horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff,
            verticalScrollBarPolicy=Qt.ScrollBarAsNeeded,
            iconSize=self.iconSize(),
        )
        popup.setFocusProxy(self.__searchline)
        popup.setParent(self, Qt.Popup | Qt.FramelessWindowHint)
        popup.setItemDelegate(_ComboBoxListDelegate(popup))
        proxy = QSortFilterProxyModel(
            popup, filterCaseSensitivity=Qt.CaseInsensitive
        )
        proxy.setFilterKeyColumn(self.modelColumn())
        proxy.setSourceModel(self.model())
        popup.setModel(proxy)
        root = proxy.mapFromSource(self.rootModelIndex())
        popup.setRootIndex(root)

        self.__popup = popup
        self.__proxy = proxy
        self.__searchline.setText("")
        self.__searchline.setPlaceholderText("Filter...")
        self.__searchline.setVisible(True)
        self.__searchline.textEdited.connect(proxy.setFilterFixedString)

        style = self.style()  # type: QStyle

        popuprect_origin = style.subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxListBoxPopup, self
        )  # type: QRect
        popuprect_origin = QRect(
            self.mapToGlobal(popuprect_origin.topLeft()),
            popuprect_origin.size()
        )
        editrect = style.subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxEditField, self
        )  # type: QRect
        self.__searchline.setGeometry(editrect)
        desktop = QApplication.desktop()
        screenrect = desktop.availableGeometry(self)  # type: QRect

        # get the height for the view
        listrect = QRect()
        for i in range(min(proxy.rowCount(root), self.maxVisibleItems())):
            index = proxy.index(i, self.modelColumn(), root)
            if index.isValid():
                listrect = listrect.united(popup.visualRect(index))
            if listrect.height() >= screenrect.height():
                break
        window = popup.window()  # type: QWidget
        window.ensurePolished()
        if window.layout() is not None:
            window.layout().activate()
        else:
            QApplication.sendEvent(window, QEvent(QEvent.LayoutRequest))

        margins = qwidget_margin_within(popup.viewport(), window)
        height = (listrect.height() + 2 * popup.spacing() +
                  margins.top() + margins.bottom())

        popup_size = (QSize(popuprect_origin.width(), height)
                      .expandedTo(window.minimumSize())
                      .boundedTo(window.maximumSize())
                      .boundedTo(screenrect.size()))
        popuprect = QRect(popuprect_origin.bottomLeft(), popup_size)

        popuprect = dropdown_popup_geometry(
            popuprect, popuprect_origin, screenrect)
        popup.setGeometry(popuprect)

        current = proxy.mapFromSource(
            self.model().index(self.currentIndex(), self.modelColumn(),
                               self.rootModelIndex()))
        popup.setCurrentIndex(current)
        popup.scrollTo(current, QAbstractItemView.EnsureVisible)
        popup.show()
        popup.setFocus(Qt.PopupFocusReason)
        popup.installEventFilter(self)
        popup.viewport().installEventFilter(self)
        popup.viewport().setMouseTracking(True)
        self.update()
        self.__popupTimer.restart()

    def hidePopup(self):
        """Reimplemented"""
        if self.__popup is not None:
            popup = self.__popup
            self.__popup = self.__proxy = None
            popup.setFocusProxy(None)
            popup.hide()
            popup.deleteLater()
            popup.removeEventFilter(self)
            popup.viewport().removeEventFilter(self)

        # need to call base hidePopup even though the base showPopup was not
        # called (update internal state wrt. 'pressed' arrow, ...)
        super().hidePopup()
        self.__searchline.hide()
        self.update()

    def initStyleOption(self, option):
        # type: (QStyleOptionComboBox) -> None
        super().initStyleOption(option)
        option.editable = True

    def __updateGeometries(self):
        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        editarea = self.style().subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxEditField, self)
        self.__searchline.setGeometry(editarea)

    def resizeEvent(self, event):
        """Reimplemented."""
        super().resizeEvent(event)
        self.__updateGeometries()

    def paintEvent(self, event):
        """Reimplemented."""
        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        painter = QStylePainter(self)
        painter.drawComplexControl(QStyle.CC_ComboBox, opt)
        if not self.__searchline.isVisibleTo(self):
            opt.editable = False
            painter.drawControl(QStyle.CE_ComboBoxLabel, opt)

    def eventFilter(self, obj, event):  # pylint: disable=too-many-branches
        # type: (QObject, QEvent) -> bool
        """Reimplemented."""
        etype = event.type()
        if etype == QEvent.FocusOut and self.__popup is not None:
            self.hidePopup()
            return True
        if etype == QEvent.Hide and self.__popup is not None:
            self.hidePopup()
            return False

        if etype == QEvent.KeyPress or etype == QEvent.KeyRelease or \
                etype == QEvent.ShortcutOverride and obj is self.__popup:
            event = event  # type: QKeyEvent
            key, modifiers = event.key(), event.modifiers()
            if key in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Select):
                current = self.__popup.currentIndex()
                if current.isValid():
                    self.__activateProxyIndex(current)
            elif key in (Qt.Key_Up, Qt.Key_Down,
                         Qt.Key_PageUp, Qt.Key_PageDown):
                return False  #
            elif key in (Qt.Key_Tab, Qt.Key_Backtab):
                pass
            elif key == Qt.Key_Escape or \
                    (key == Qt.Key_F4 and modifiers & Qt.AltModifier):
                self.__popup.hide()
                return True
            else:
                # pass the input events to the filter edit line (no propagation
                # up the parent chain).
                self.__searchline.event(event)
                if event.isAccepted():
                    return True
        if etype == QEvent.MouseButtonRelease and self.__popup is not None \
                and obj is self.__popup.viewport() \
                and self.__popupTimer.elapsed() >= \
                    QApplication.doubleClickInterval():
            event = event  # type: QMouseEvent
            index = self.__popup.indexAt(event.pos())
            if index.isValid():
                self.__activateProxyIndex(index)

        if etype == QEvent.MouseMove and self.__popup is not None \
                and obj is self.__popup.viewport():
            event = event  # type: QMouseEvent
            opt = QStyleOptionComboBox()
            self.initStyleOption(opt)
            style = self.style()  # type: QStyle
            if style.styleHint(QStyle.SH_ComboBox_ListMouseTracking, opt, self):
                index = self.__popup.indexAt(event.pos())
                if index.isValid() and \
                        index.flags() & (Qt.ItemIsEnabled | Qt.ItemIsSelectable):
                    self.__popup.setCurrentIndex(index)

        if etype == QEvent.MouseButtonPress and self.__popup is obj:
            # Popup border or out of window mouse button press/release.
            # At least on windows this needs to be handled.
            style = self.style()
            opt = QStyleOptionComboBox()
            self.initStyleOption(opt)
            opt.subControls = QStyle.SC_All
            opt.activeSubControls = QStyle.SC_ComboBoxArrow
            pos = self.mapFromGlobal(event.globalPos())
            sc = style.hitTestComplexControl(QStyle.CC_ComboBox, opt, pos, self)
            if sc != QStyle.SC_None:
                self.__popup.setAttribute(Qt.WA_NoMouseReplay)
            self.hidePopup()

        return super().eventFilter(obj, event)

    def __activateProxyIndex(self, index):
        # type: (QModelIndex) -> None
        # Set current and activate the source index corresponding to the proxy
        # index in the popup's model.
        if self.__popup is not None and index.isValid():
            proxy = self.__popup.model()
            assert index.model() is proxy
            index = proxy.mapToSource(index)
            assert index.model() is self.model()
            if index.isValid() and \
                    index.flags() & (Qt.ItemIsEnabled | Qt.ItemIsSelectable):
                self.hidePopup()
                text = self.itemText(index.row())
                self.setCurrentIndex(index.row())
                self.activated[int].emit(index.row())
                self.activated[str].emit(text)
Example #8
0
class ComboBoxSearch(QComboBox):
    """
    A drop down list combo box with filter/search.

    The popup list view is filtered by text entered in the filter field.

    Note
    ----
    `popup`, `lineEdit` and `completer` from the base QComboBox class are
    unused. Setting/modifying them will have no effect.
    """
    # NOTE: Setting editable + QComboBox.NoInsert policy + ... did not achieve
    # the same results.
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__searchline = QLineEdit(self, visible=False, frame=False)
        self.__searchline.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.__searchline.setFocusProxy(self)
        self.__popup = None  # type: Optional[QAbstractItemModel]
        self.__proxy = None  # type: Optional[QSortFilterProxyModel]
        self.__popupTimer = QElapsedTimer()
        self.setFocusPolicy(Qt.ClickFocus | Qt.TabFocus)

    def showPopup(self):
        # type: () -> None
        """
        Reimplemented from QComboBox.showPopup

        Popup up a customized view and filter edit line.

        Note
        ----
        The .popup(), .lineEdit(), .completer() of the base class are not used.
        """
        if self.__popup is not None:
            # We have user entered state that cannot be disturbed
            # (entered filter text, scroll offset, ...)
            return  # pragma: no cover

        if self.count() == 0:
            return

        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        popup = QListView(
            uniformItemSizes=True,
            horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOff,
            verticalScrollBarPolicy=Qt.ScrollBarAsNeeded,
            iconSize=self.iconSize(),
        )
        popup.setFocusProxy(self.__searchline)
        popup.setParent(self, Qt.Popup | Qt.FramelessWindowHint)
        popup.setItemDelegate(_ComboBoxListDelegate(popup))
        proxy = QSortFilterProxyModel(
            popup, filterCaseSensitivity=Qt.CaseInsensitive
        )
        proxy.setFilterKeyColumn(self.modelColumn())
        proxy.setSourceModel(self.model())
        popup.setModel(proxy)
        root = proxy.mapFromSource(self.rootModelIndex())
        popup.setRootIndex(root)

        self.__popup = popup
        self.__proxy = proxy
        self.__searchline.setText("")
        self.__searchline.setPlaceholderText("Filter...")
        self.__searchline.setVisible(True)
        self.__searchline.textEdited.connect(proxy.setFilterFixedString)

        style = self.style()  # type: QStyle

        popuprect_origin = style.subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxListBoxPopup, self
        )  # type: QRect
        popuprect_origin = QRect(
            self.mapToGlobal(popuprect_origin.topLeft()),
            popuprect_origin.size()
        )
        editrect = style.subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxEditField, self
        )  # type: QRect
        self.__searchline.setGeometry(editrect)
        desktop = QApplication.desktop()
        screenrect = desktop.availableGeometry(self)  # type: QRect

        # get the height for the view
        listrect = QRect()
        for i in range(min(proxy.rowCount(root), self.maxVisibleItems())):
            index = proxy.index(i, self.modelColumn(), root)
            if index.isValid():
                listrect = listrect.united(popup.visualRect(index))
            if listrect.height() >= screenrect.height():
                break
        window = popup.window()  # type: QWidget
        window.ensurePolished()
        if window.layout() is not None:
            window.layout().activate()
        else:
            QApplication.sendEvent(window, QEvent(QEvent.LayoutRequest))

        margins = qwidget_margin_within(popup.viewport(), window)
        height = (listrect.height() + 2 * popup.spacing() +
                  margins.top() + margins.bottom())

        popup_size = (QSize(popuprect_origin.width(), height)
                      .expandedTo(window.minimumSize())
                      .boundedTo(window.maximumSize())
                      .boundedTo(screenrect.size()))
        popuprect = QRect(popuprect_origin.bottomLeft(), popup_size)

        popuprect = dropdown_popup_geometry(
            popuprect, popuprect_origin, screenrect)
        popup.setGeometry(popuprect)

        current = proxy.mapFromSource(
            self.model().index(self.currentIndex(), self.modelColumn(),
                               self.rootModelIndex()))
        popup.setCurrentIndex(current)
        popup.scrollTo(current, QAbstractItemView.EnsureVisible)
        popup.show()
        popup.setFocus(Qt.PopupFocusReason)
        popup.installEventFilter(self)
        popup.viewport().installEventFilter(self)
        popup.viewport().setMouseTracking(True)
        self.update()
        self.__popupTimer.restart()

    def hidePopup(self):
        """Reimplemented"""
        if self.__popup is not None:
            popup = self.__popup
            self.__popup = self.__proxy = None
            popup.setFocusProxy(None)
            popup.hide()
            popup.deleteLater()
            popup.removeEventFilter(self)
            popup.viewport().removeEventFilter(self)

        # need to call base hidePopup even though the base showPopup was not
        # called (update internal state wrt. 'pressed' arrow, ...)
        super().hidePopup()
        self.__searchline.hide()
        self.update()

    def initStyleOption(self, option):
        # type: (QStyleOptionComboBox) -> None
        super().initStyleOption(option)
        option.editable = True

    def __updateGeometries(self):
        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        editarea = self.style().subControlRect(
            QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxEditField, self)
        self.__searchline.setGeometry(editarea)

    def resizeEvent(self, event):
        """Reimplemented."""
        super().resizeEvent(event)
        self.__updateGeometries()

    def paintEvent(self, event):
        """Reimplemented."""
        opt = QStyleOptionComboBox()
        self.initStyleOption(opt)
        painter = QStylePainter(self)
        painter.drawComplexControl(QStyle.CC_ComboBox, opt)
        if not self.__searchline.isVisibleTo(self):
            opt.editable = False
            painter.drawControl(QStyle.CE_ComboBoxLabel, opt)

    def eventFilter(self, obj, event):  # pylint: disable=too-many-branches
        # type: (QObject, QEvent) -> bool
        """Reimplemented."""
        etype = event.type()
        if etype == QEvent.FocusOut and self.__popup is not None:
            self.hidePopup()
            return True
        if etype == QEvent.Hide and self.__popup is not None:
            self.hidePopup()
            return False

        if etype == QEvent.KeyPress or etype == QEvent.KeyRelease or \
                etype == QEvent.ShortcutOverride and obj is self.__popup:
            event = event  # type: QKeyEvent
            key, modifiers = event.key(), event.modifiers()
            if key in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Select):
                current = self.__popup.currentIndex()
                if current.isValid():
                    self.__activateProxyIndex(current)
            elif key in (Qt.Key_Up, Qt.Key_Down,
                         Qt.Key_PageUp, Qt.Key_PageDown):
                return False  #
            elif key in (Qt.Key_Tab, Qt.Key_Backtab):
                pass
            elif key == Qt.Key_Escape or \
                    (key == Qt.Key_F4 and modifiers & Qt.AltModifier):
                self.__popup.hide()
                return True
            else:
                # pass the input events to the filter edit line (no propagation
                # up the parent chain).
                self.__searchline.event(event)
                if event.isAccepted():
                    return True
        if etype == QEvent.MouseButtonRelease and self.__popup is not None \
                and obj is self.__popup.viewport() \
                and self.__popupTimer.elapsed() >= \
                    QApplication.doubleClickInterval():
            event = event  # type: QMouseEvent
            index = self.__popup.indexAt(event.pos())
            if index.isValid():
                self.__activateProxyIndex(index)

        if etype == QEvent.MouseMove and self.__popup is not None \
                and obj is self.__popup.viewport():
            event = event  # type: QMouseEvent
            opt = QStyleOptionComboBox()
            self.initStyleOption(opt)
            style = self.style()  # type: QStyle
            if style.styleHint(QStyle.SH_ComboBox_ListMouseTracking, opt, self):
                index = self.__popup.indexAt(event.pos())
                if index.isValid() and \
                        index.flags() & (Qt.ItemIsEnabled | Qt.ItemIsSelectable):
                    self.__popup.setCurrentIndex(index)

        if etype == QEvent.MouseButtonPress and self.__popup is obj:
            # Popup border or out of window mouse button press/release.
            # At least on windows this needs to be handled.
            style = self.style()
            opt = QStyleOptionComboBox()
            self.initStyleOption(opt)
            opt.subControls = QStyle.SC_All
            opt.activeSubControls = QStyle.SC_ComboBoxArrow
            pos = self.mapFromGlobal(event.globalPos())
            sc = style.hitTestComplexControl(QStyle.CC_ComboBox, opt, pos, self)
            if sc != QStyle.SC_None:
                self.__popup.setAttribute(Qt.WA_NoMouseReplay)
            self.hidePopup()

        return super().eventFilter(obj, event)

    def __activateProxyIndex(self, index):
        # type: (QModelIndex) -> None
        # Set current and activate the source index corresponding to the proxy
        # index in the popup's model.
        if self.__popup is not None and index.isValid():
            proxy = self.__popup.model()
            assert index.model() is proxy
            index = proxy.mapToSource(index)
            assert index.model() is self.model()
            if index.isValid() and \
                    index.flags() & (Qt.ItemIsEnabled | Qt.ItemIsSelectable):
                self.hidePopup()
                text = self.itemText(index.row())
                self.setCurrentIndex(index.row())
                self.activated[int].emit(index.row())
                self.activated[str].emit(text)