Skip to content

Commit

Permalink
WIP: Don't use a QCompleter for CommandPalette
Browse files Browse the repository at this point in the history
  • Loading branch information
MHendricks committed Mar 6, 2024
1 parent 7439110 commit 609d9b7
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 40 deletions.
99 changes: 64 additions & 35 deletions preditor/gui/command_palette/command_palette.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,93 @@
from __future__ import absolute_import

import six
from Qt.QtCore import QPoint, Qt
from Qt.QtWidgets import QFrame, QHBoxLayout, QLineEdit, QShortcut
from functools import partial

from .workbox_completer import WorkboxCompleter
from Qt.QtCore import QModelIndex, QPoint, Qt, Signal
from Qt.QtWidgets import QFrame, QLineEdit, QListView, QShortcut, QVBoxLayout

from .workbox_item_model import WorkboxFuzzyFilterProxyModel


class CommandPalette(QFrame):
canceled = Signal("QModelIndex")
"""Passes the original QModelIndex for the tab that was selected when the
widget was first shown. This lets you reset back to the orignal state."""
highlighted = Signal("QModelIndex")
"""Emitted when the user navitages to the given index, but hasn't selected."""
selected = Signal("QModelIndex")
"""Emitted when the user selects a item."""

def __init__(self, model, parent=None, **kwargs):
super(CommandPalette, self).__init__(parent=parent, **kwargs)
self.y_offset = 100
lyt = QHBoxLayout(self)
self.uiLineEDIT = QLineEdit(parent=self)
lyt.addWidget(self.uiLineEDIT)
self.setMinimumSize(400, self.sizeHint().height())
self.setMinimumSize(400, 200)
self.uiCloseSCT = QShortcut(
Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
)
self.uiCloseSCT.activated.connect(self.hide)
self.uiLineCOMPL = WorkboxCompleter()
self.uiLineCOMPL.split_char = None
self.uiLineCOMPL.setCaseSensitivity(False)
self.uiLineCOMPL.setModel(model)
self.uiLineEDIT.setCompleter(self.uiLineCOMPL)
self.uiLineCOMPL.activated.connect(self.completed)
self.uiLineCOMPL.highlighted.connect(self.completer_selected)
# self.uiLineCOMPL.popup().clicked.connect(self.completed)
self.uiCloseSCT.activated.connect(self._canceled)

self.uiUpSCT = QShortcut(Qt.Key_Up, self, context=Qt.WidgetWithChildrenShortcut)
self.uiUpSCT.activated.connect(partial(self.increment_selection, -1))
self.uiDownSCT = QShortcut(
Qt.Key_Down, self, context=Qt.WidgetWithChildrenShortcut
)
self.uiDownSCT.activated.connect(partial(self.increment_selection, 1))

lyt = QVBoxLayout(self)
self.uiLineEDIT = QLineEdit(parent=self)
self.uiLineEDIT.textChanged.connect(self.update_completer)
self.current_name = parent.name_for_workbox(parent.current_workbox())
self.uiLineEDIT.returnPressed.connect(self.activated)
lyt.addWidget(self.uiLineEDIT)
self.uiResultsLIST = QListView(self)
self.uiResultsLIST.activated.connect(self.activated)
self.proxy_model = WorkboxFuzzyFilterProxyModel(self)
self.proxy_model.setSourceModel(model)
self.uiResultsLIST.setModel(self.proxy_model)
lyt.addWidget(self.uiResultsLIST)

def update_completer(self, wildcard):
self.uiLineCOMPL.updatePattern(wildcard)
self.original_model_index = model.original_model_index

def completed(self, name):
if isinstance(name, six.string_types):
self.current_name = name
else:
self.current_name = self.uiLineCOMPL.pathFromIndex(name)
def activated(self):
current = self.uiResultsLIST.currentIndex()
self.selected.emit(current)
self.hide()

def completer_selected(self, name):
self.parent().workbox_for_name(name.rstrip("/"), visible=True)
def increment_selection(self, direction):
current = self.uiResultsLIST.currentIndex()
col = 0
row = 0
if current.isValid():
col = current.column()
row = current.row() + direction
new = self.uiResultsLIST.model().index(row, col)
self.uiResultsLIST.setCurrentIndex(new)
self.highlighted.emit(new)

def update_completer(self, wildcard):
if wildcard:
if not self.uiResultsLIST.currentIndex().isValid():
new = self.uiResultsLIST.model().index(0, 0)
self.uiResultsLIST.setCurrentIndex(new)
else:
self.uiResultsLIST.clearSelection()
self.uiResultsLIST.setCurrentIndex(QModelIndex())
self.proxy_model.setFuzzySearch(wildcard)
self.highlighted.emit(self.uiResultsLIST.currentIndex())

def hide(self):
# Close the popup if its open
self.uiLineCOMPL.popup().hide()
def _canceled(self):
# Restore the original tab as the user didn't choose the new tab
self.completer_selected(self.current_name)
super(CommandPalette, self).hide()
self.canceled.emit(self.original_model_index)
self.hide()

def reposition(self):
pgeo = self.parent().geometry()
geo = self.geometry()
center = QPoint(pgeo.width() // 2, self.y_offset)
center = QPoint(pgeo.width() // 2, 0)
geo.moveCenter(center)
geo.setY(self.y_offset)
self.setGeometry(geo)

def popup(self):
self.show()
self.reposition()
self.uiLineEDIT.setFocus(Qt.PopupFocusReason)
self.show()
self.uiLineCOMPL.complete()
38 changes: 34 additions & 4 deletions preditor/gui/command_palette/workbox_item_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@


class WorkboxItemModel(QStandardItemModel):
GroupIndexRole = Qt.UserRole + 1
TabIndexRole = GroupIndexRole + 1

def __init__(self, manager, *args, **kwargs):
super(WorkboxItemModel, self).__init__(*args, **kwargs)
self.manager = manager

def workbox_indexes_from_model_index(self, index):
"""Returns the group_index and tab_index for the provided QModelIndex"""
return (
index.data(WorkboxListItemModel.GroupIndexRole),
index.data(WorkboxListItemModel.TabIndexRole),
)

def pathFromIndex(self, index):
parts = [""]
while index.isValid():
Expand All @@ -24,23 +34,43 @@ def pathFromIndex(self, index):
class WorkboxTreeItemModel(WorkboxItemModel):
def process(self):
root = self.invisibleRootItem()
current_group = self.manager.currentIndex()
current_tab = self.manager.currentWidget().currentIndex()

prev_group = -1
for _, group_name, tab_name, group_index, _ in self.manager.all_widgets():
all_widgets = self.manager.all_widgets()
for _, group_name, tab_name, group_index, tab_index in all_widgets:
if prev_group != group_index:
group_item = QStandardItem(group_name)
group_item.setData(group_index, self.GroupIndexRole)
root.appendRow(group_item)
prev_group = group_index

tab_item = QStandardItem(tab_name)
tab_item.setData(group_index, self.GroupIndexRole)
tab_item.setData(tab_index, self.TabIndexRole)
group_item.appendRow(tab_item)
if group_index == current_group and tab_index == current_tab:
self.original_model_index = self.indexFromItem(tab_item)


class WorkboxListItemModel(WorkboxItemModel):
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable

def process(self):
root = self.invisibleRootItem()
for _, group_name, tab_name, _, _ in self.manager.all_widgets():
group_item = QStandardItem('/'.join((group_name, tab_name)))
root.appendRow(group_item)
current_group = self.manager.currentIndex()
current_tab = self.manager.currentWidget().currentIndex()

all_widgets = self.manager.all_widgets()
for _, group_name, tab_name, group_index, tab_index in all_widgets:
tab_item = QStandardItem('/'.join((group_name, tab_name)))
tab_item.setData(group_index, self.GroupIndexRole)
tab_item.setData(tab_index, self.TabIndexRole)
root.appendRow(tab_item)
if group_index == current_group and tab_index == current_tab:
self.original_model_index = self.indexFromItem(tab_item)


class WorkboxFuzzyFilterProxyModel(QSortFilterProxyModel):
Expand Down
2 changes: 1 addition & 1 deletion preditor/gui/group_tab_widget/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def all_widgets(self):
"""A generator yielding information about every widget under every group.
Yields:
group tab name, widget tab name, group tab index, widget tab index, widget
widget, group tab name, widget tab name, group tab index, widget tab index
"""
for group_index in range(self.count()):
group_name = self.tabText(group_index)
Expand Down
9 changes: 9 additions & 0 deletions preditor/gui/loggerwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,16 @@ def show_find_in_workboxes(self):
def show_focus_name(self):
model = WorkboxListItemModel(manager=self.uiWorkboxTAB)
model.process()

def update_tab(index):
group, tab = model.workbox_indexes_from_model_index(index)
if group is not None:
self.uiWorkboxTAB.set_current_groups_from_index(group, tab)

w = CommandPalette(model, parent=self)
w.selected.connect(update_tab)
w.canceled.connect(update_tab)
w.highlighted.connect(update_tab)
w.popup()

def updateCopyIndentsAsSpaces(self):
Expand Down

0 comments on commit 609d9b7

Please sign in to comment.