def treePopupWidget(self): """ Returns the popup widget for this record box when it is supposed to be an ORB tree widget. :return <XTreeWidget> """ if not self._treePopupWidget: # create the treewidget tree = XTreeWidget(self) tree.setWindowFlags(Qt.Popup) tree.setFocusPolicy(Qt.StrongFocus) tree.installEventFilter(self) tree.setAlternatingRowColors(True) tree.setShowGridColumns(False) tree.setRootIsDecorated(False) tree.setVerticalScrollMode(tree.ScrollPerPixel) # create connections tree.itemClicked.connect(self.acceptRecord) self.lineEdit().textEdited.connect(tree.filterItems) self.lineEdit().textEdited.connect(self.showPopup) self._treePopupWidget = tree return self._treePopupWidget
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()