Exemplo n.º 1
0
class XSearchActionWidget(QWidget):
    def __init__(self, parent, action):
        super(XSearchActionWidget, self).__init__(parent)
        
        # define custom properties
        self._initialized = False
        self._triggerText = ''
        
        # define the interface
        self._searchEdit = XLineEdit(self)
        self._searchEdit.setIcon(QIcon(resources.find('img/search.png')))
        self._searchEdit.setHint('enter search')
        self._searchEdit.setFixedHeight(24)
        
        # define the completer
        self._completer = XTreeWidget(self)
        self._completer.setHint('No actions were found.')
        self._completer.setWindowFlags(Qt.Popup)
        self._completer.setRootIsDecorated(False)
        self._completer.header().hide()
        self._completer.setSortingEnabled(True)
        self._completer.sortByColumn(0, Qt.AscendingOrder)
        self._completer.installEventFilter(self)
        self._completer.setFocusProxy(self._searchEdit)
        self._completer.setShowGrid(False)
        self._completer.setFrameShape(XTreeWidget.Box)
        self._completer.setFrameShadow(XTreeWidget.Plain)
        
        # match the look for the completer to the menu
        palette = self._completer.palette()
        palette.setColor(palette.Base, palette.color(palette.Window))
        palette.setColor(palette.Text, palette.color(palette.WindowText))
        palette.setColor(palette.WindowText, palette.color(palette.Mid))
        self._completer.setPalette(palette)
        
        # create the layout
        layout = QHBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        layout.addWidget(self._searchEdit)
        self.setLayout(layout)
        
        # create connections
        self._searchEdit.textChanged.connect(self.filterOptions)
        self._completer.itemClicked.connect(self.triggerItem)
        parent.aboutToShow.connect(self.aboutToShow)
    
    def aboutToShow(self):
        """
        Processes the search widget when the menu is about to show.
        """
        self.clear()
        self._searchEdit.setFocus()
    
    def addItems(self, menus, processed=None):
        """
        Adds items to the completion tree from the menu.
        
        :param      menus | [<QMenu>, ..]
                    procesed | [<QAction>, ..] || None
        """
        if processed is None:
            processed = []
        
        for menu in menus:
            for action in menu.actions():
                # since we can have 1 action in more than 1 submenu, we
                # will want to make sure we're only adding a unique one
                # so we don't have duplicates
                text = nativestring(action.text())
                if text in processed or action.isSeparator():
                    continue
                
                processed.append(text)
                
                if text and unwrapVariant(action.data()) != 'menu':
                    item = XTreeWidgetItem(self._completer, [text])
                    item.setFixedHeight(20)
                    item.setIcon(0, action.icon())
                    item.setToolTip(0, action.toolTip())
                    item.setData(0, Qt.UserRole, wrapVariant(action))
    
    def clear(self):
        """
        Clears the text from the search edit.
        """
        self._searchEdit.blockSignals(True)
        self._searchEdit.setText('')
        self._searchEdit.blockSignals(False)
    
    def completer(self):
        """
        Returns the completion widget for this menu.
        
        :return     <projexui.widgets.xtreewidget.XTreeWidget>
        """
        return self._completer
    
    def eventFilter(self, object, event):
        """
        Listens for the key press event from the tree widget to pass along
        to the line edit.
        
        :param      object | <QWidget>
                    event  | <QEvent>
        
        :return     <bool> | consumed
        """
        if event.type() == event.KeyPress:
            if event.key() == Qt.Key_Escape:
                self._completer.hide()
                self._completer.setCurrentItem(None)

            elif event.key() in (Qt.Key_Enter, Qt.Key_Return):
                tree = self._completer
                item = tree.currentItem() or tree.itemAt(0, 0)
                self.triggerItem(item)

            self._searchEdit.keyPressEvent(event)

        return False

    def filterOptions(self, text):
        """
        Filters the searched actions based on the inputed text.
        
        :param      text | <str>
        """
        if not text:
            self._completer.hide()
            self._completer.setCurrentItem(None)
            return

        # block the signals
        self._completer.setUpdatesEnabled(False)
        self._completer.blockSignals(True)

        # initialize the actions
        menu = self.parent()
        if not self._initialized:
            self.addItems([menu] + menu.findChildren(QMenu))
            self._initialized = True

        # filter the actions in the search view
        visible_count = 0
        item_count = self._completer.topLevelItemCount()
        for i in range(item_count):
            item = self._completer.topLevelItem(i)
            check = nativestring(item.text(0)).lower()
            hidden = not nativestring(text).lower() in check
            item.setHidden(hidden)
            visible_count += 1 if not hidden else 0

        # show the popup widget if it is not visible
        if not self._completer.isVisible():
            point = QPoint(-1, self.height())
            width = menu.width()
            height = menu.height() - self.height() - 1
            height = max(height, 22 * min(visible_count, 5))
            
            self._completer.move(self.mapToGlobal(point))
            self._completer.resize(width, height)
            self._completer.show()

        # restore signals
        self._completer.setUpdatesEnabled(True)
        self._completer.blockSignals(False)

    def searchEdit(self):
        """
        Returns the line edit associated with this widget.
        
        :return     <projexui.widgets.xlineedit.XLineEdit>
        """
        return self._searchEdit
    
    def text(self):
        """
        Returns the text of the item that was triggered.
        
        :return     <str>
        """
        return self._triggerText
    
    def triggerItem(self, item):
        """
        Triggers the item by calling its action's toggled state to display or
        hide the dock panel.
        
        :param      item | <QtGui.QTreeWidgetItem>
        """
        if not item:
            return
        
        # emit the trigger action
        self._triggerText = item.text(0)
        self._completer.hide()
        self._completer.setCurrentItem(None)
        self.parent().hide()
        
        # trigger the action
        unwrapVariant(item.data(0, Qt.UserRole)).trigger()
Exemplo n.º 2
0
class XSearchActionWidget(QWidget):
    def __init__(self, parent, action):
        super(XSearchActionWidget, self).__init__(parent)

        # define custom properties
        self._initialized = False
        self._triggerText = ''

        # define the interface
        self._searchEdit = XLineEdit(self)
        self._searchEdit.setIcon(QIcon(resources.find('img/search.png')))
        self._searchEdit.setHint('enter search')
        self._searchEdit.setFixedHeight(24)

        # define the completer
        self._completer = XTreeWidget(self)
        self._completer.setHint('No actions were found.')
        self._completer.setWindowFlags(Qt.Popup)
        self._completer.setRootIsDecorated(False)
        self._completer.header().hide()
        self._completer.setSortingEnabled(True)
        self._completer.sortByColumn(0, Qt.AscendingOrder)
        self._completer.installEventFilter(self)
        self._completer.setFocusProxy(self._searchEdit)
        self._completer.setShowGrid(False)
        self._completer.setFrameShape(XTreeWidget.Box)
        self._completer.setFrameShadow(XTreeWidget.Plain)

        # match the look for the completer to the menu
        palette = self._completer.palette()
        palette.setColor(palette.Base, palette.color(palette.Window))
        palette.setColor(palette.Text, palette.color(palette.WindowText))
        palette.setColor(palette.WindowText, palette.color(palette.Mid))
        self._completer.setPalette(palette)

        # create the layout
        layout = QHBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        layout.addWidget(self._searchEdit)
        self.setLayout(layout)

        # create connections
        self._searchEdit.textChanged.connect(self.filterOptions)
        self._completer.itemClicked.connect(self.triggerItem)
        parent.aboutToShow.connect(self.aboutToShow)

    def aboutToShow(self):
        """
        Processes the search widget when the menu is about to show.
        """
        self.clear()
        self._searchEdit.setFocus()

    def addItems(self, menus, processed=None):
        """
        Adds items to the completion tree from the menu.
        
        :param      menus | [<QMenu>, ..]
                    procesed | [<QAction>, ..] || None
        """
        if processed is None:
            processed = []

        for menu in menus:
            for action in menu.actions():
                # since we can have 1 action in more than 1 submenu, we
                # will want to make sure we're only adding a unique one
                # so we don't have duplicates
                text = nativestring(action.text())
                if text in processed or action.isSeparator():
                    continue

                processed.append(text)

                if text and unwrapVariant(action.data()) != 'menu':
                    item = XTreeWidgetItem(self._completer, [text])
                    item.setFixedHeight(20)
                    item.setIcon(0, action.icon())
                    item.setToolTip(0, action.toolTip())
                    item.setData(0, Qt.UserRole, wrapVariant(action))

    def clear(self):
        """
        Clears the text from the search edit.
        """
        self._searchEdit.blockSignals(True)
        self._searchEdit.setText('')
        self._searchEdit.blockSignals(False)

    def completer(self):
        """
        Returns the completion widget for this menu.
        
        :return     <projexui.widgets.xtreewidget.XTreeWidget>
        """
        return self._completer

    def eventFilter(self, object, event):
        """
        Listens for the key press event from the tree widget to pass along
        to the line edit.
        
        :param      object | <QWidget>
                    event  | <QEvent>
        
        :return     <bool> | consumed
        """
        if event.type() == event.KeyPress:
            if event.key() == Qt.Key_Escape:
                self._completer.hide()
                self._completer.setCurrentItem(None)

            elif event.key() in (Qt.Key_Enter, Qt.Key_Return):
                tree = self._completer
                item = tree.currentItem() or tree.itemAt(0, 0)
                self.triggerItem(item)

            self._searchEdit.keyPressEvent(event)

        return False

    def filterOptions(self, text):
        """
        Filters the searched actions based on the inputed text.
        
        :param      text | <str>
        """
        if not text:
            self._completer.hide()
            self._completer.setCurrentItem(None)
            return

        # block the signals
        self._completer.setUpdatesEnabled(False)
        self._completer.blockSignals(True)

        # initialize the actions
        menu = self.parent()
        if not self._initialized:
            self.addItems([menu] + menu.findChildren(QMenu))
            self._initialized = True

        # filter the actions in the search view
        visible_count = 0
        item_count = self._completer.topLevelItemCount()
        for i in range(item_count):
            item = self._completer.topLevelItem(i)
            check = nativestring(item.text(0)).lower()
            hidden = not nativestring(text).lower() in check
            item.setHidden(hidden)
            visible_count += 1 if not hidden else 0

        # show the popup widget if it is not visible
        if not self._completer.isVisible():
            point = QPoint(-1, self.height())
            width = menu.width()
            height = menu.height() - self.height() - 1
            height = max(height, 22 * min(visible_count, 5))

            self._completer.move(self.mapToGlobal(point))
            self._completer.resize(width, height)
            self._completer.show()

        # restore signals
        self._completer.setUpdatesEnabled(True)
        self._completer.blockSignals(False)

    def searchEdit(self):
        """
        Returns the line edit associated with this widget.
        
        :return     <projexui.widgets.xlineedit.XLineEdit>
        """
        return self._searchEdit

    def text(self):
        """
        Returns the text of the item that was triggered.
        
        :return     <str>
        """
        return self._triggerText

    def triggerItem(self, item):
        """
        Triggers the item by calling its action's toggled state to display or
        hide the dock panel.
        
        :param      item | <QtGui.QTreeWidgetItem>
        """
        if not item:
            return

        # emit the trigger action
        self._triggerText = item.text(0)
        self._completer.hide()
        self._completer.setCurrentItem(None)
        self.parent().hide()

        # trigger the action
        unwrapVariant(item.data(0, Qt.UserRole)).trigger()