diff --git a/preditor/gui/command_palette/__init__.py b/preditor/gui/command_palette/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/preditor/gui/command_palette/command_palette.py b/preditor/gui/command_palette/command_palette.py
new file mode 100644
index 00000000..b5f2b625
--- /dev/null
+++ b/preditor/gui/command_palette/command_palette.py
@@ -0,0 +1,57 @@
+import six
+from Qt.QtCore import QPoint, Qt
+from Qt.QtWidgets import QFrame, QHBoxLayout, QLineEdit, QShortcut
+
+from .workbox_completer import WorkboxCompleter
+
+
+class CommandPalette(QFrame):
+ 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.uiCloseSCT = QShortcut(
+ Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
+ )
+ self.uiCloseSCT.activated.connect(self.hide)
+ self.uiLineCOMPL = WorkboxCompleter()
+ 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.current_name = parent.name_for_workbox(parent.current_workbox())
+
+ def completed(self, name):
+ if isinstance(name, six.string_types):
+ self.current_name = name
+ else:
+ self.current_name = self.uiLineCOMPL.pathFromIndex(name)
+ self.hide()
+
+ def completer_selected(self, name):
+ self.parent().workbox_for_name(name.rstrip("/"), visible=True)
+
+ def hide(self):
+ # Close the popup if its open
+ self.uiLineCOMPL.popup().hide()
+ # Restore the original tab as the user didn't choose the new tab
+ self.completer_selected(self.current_name)
+ super(CommandPalette, self).hide()
+
+ def reposition(self):
+ pgeo = self.parent().geometry()
+ geo = self.geometry()
+ center = QPoint(pgeo.width() // 2, self.y_offset)
+ geo.moveCenter(center)
+ self.setGeometry(geo)
+
+ def popup(self):
+ self.reposition()
+ self.uiLineEDIT.setFocus(Qt.PopupFocusReason)
+ self.show()
+ self.uiLineCOMPL.complete()
diff --git a/preditor/gui/command_palette/workbox_completer.py b/preditor/gui/command_palette/workbox_completer.py
new file mode 100644
index 00000000..dab9cb19
--- /dev/null
+++ b/preditor/gui/command_palette/workbox_completer.py
@@ -0,0 +1,9 @@
+from Qt.QtWidgets import QCompleter
+
+
+class WorkboxCompleter(QCompleter):
+ def splitPath(self, path):
+ return path.split("/")
+
+ def pathFromIndex(self, index):
+ return self.model().pathFromIndex(index)
diff --git a/preditor/gui/command_palette/workbox_item_model.py b/preditor/gui/command_palette/workbox_item_model.py
new file mode 100644
index 00000000..c45019fd
--- /dev/null
+++ b/preditor/gui/command_palette/workbox_item_model.py
@@ -0,0 +1,60 @@
+from Qt.QtCore import Qt
+from Qt.QtGui import QStandardItem, QStandardItemModel
+
+
+def manager_items(manager):
+ for group_index in range(manager.count()):
+ group_name = manager.tabText(group_index)
+
+ tab_widget = manager.widget(group_index)
+ for tab_index in range(tab_widget.count()):
+ tab_name = tab_widget.tabText(tab_index)
+ yield group_name, tab_name, group_index, tab_index
+
+
+class WorkboxItemModel(QStandardItemModel):
+ def __init__(self, manager, *args, **kwargs):
+ super(WorkboxItemModel, self).__init__(*args, **kwargs)
+ self.manager = manager
+
+ def pathFromIndex(self, index):
+ parts = [""]
+ while index.isValid():
+ parts.append(self.data(index, Qt.DisplayRole))
+ index = index.parent()
+ if len(parts) == 1:
+ return ""
+ return "/".join([x for x in parts[::-1] if x])
+
+
+class WorkboxTreeItemModel(WorkboxItemModel):
+ def process(self):
+ root = self.invisibleRootItem()
+ prev_group = -1
+ for group_name, tab_name, group_index, _ in manager_items(self.manager):
+ if prev_group != group_index:
+ group_item = QStandardItem(group_name)
+ root.appendRow(group_item)
+ prev_group = group_index
+
+ tab_item = QStandardItem(tab_name)
+ group_item.appendRow(tab_item)
+
+ # for group in range(self.manager.count()):
+ # group_name = self.manager.tabText(group)
+ # group_item = QStandardItem(group_name)
+ # root.appendRow(group_item)
+
+ # tab_widget = self.manager.widget(group)
+ # for index in range(tab_widget.count()):
+ # tab_name = tab_widget.tabText(index)
+ # tab_item = QStandardItem(tab_name)
+ # group_item.appendRow(tab_item)
+
+
+class WorkboxListItemModel(WorkboxItemModel):
+ def process(self):
+ root = self.invisibleRootItem()
+ for group_name, tab_name, _, _ in manager_items(self.manager):
+ group_item = QStandardItem('/'.join((group_name, tab_name)))
+ root.appendRow(group_item)
diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py
index 415347ae..e1173782 100644
--- a/preditor/gui/loggerwindow.py
+++ b/preditor/gui/loggerwindow.py
@@ -37,6 +37,8 @@
)
from ..delayable_engine import DelayableEngine
from ..gui import Dialog, Window, loadUi
+from ..gui.command_palette.command_palette import CommandPalette
+from ..gui.command_palette.workbox_item_model import WorkboxListItemModel
from ..logging_config import LoggingConfig
from ..utils import stylesheets
from .completer import CompleterMode
@@ -180,6 +182,8 @@ def __init__(self, parent, name=None, run_workbox=False):
self.uiGroup8ACT.triggered.connect(partial(self.gotoGroupByIndex, 8))
self.uiGroupLastACT.triggered.connect(partial(self.gotoGroupByIndex, -1))
+ self.uiFocusNameACT.triggered.connect(self.show_focus_name)
+
self.uiCommentToggleACT.triggered.connect(self.comment_toggle)
self.uiSpellCheckEnabledACT.toggled.connect(self.setSpellCheckEnabled)
@@ -306,7 +310,18 @@ def current_workbox(self):
return self.uiWorkboxTAB.current_groups_widget()
@classmethod
- def workbox_for_name(cls, name, show=False):
+ def name_for_workbox(cls, workbox):
+ ret = []
+ logger = cls.instance()
+ index = logger.uiWorkboxTAB.currentIndex()
+ ret.append(logger.uiWorkboxTAB.tabText(index))
+ group_widget = logger.uiWorkboxTAB.currentWidget()
+ index = group_widget.currentIndex()
+ ret.append(group_widget.tabText(index))
+ return "/".join(ret)
+
+ @classmethod
+ def workbox_for_name(cls, name, show=False, visible=False):
"""Used to find a workbox for a given name. It accepts a string matching
the "{group}/{workbox}" format, or if True, the current workbox.
@@ -326,13 +341,19 @@ def workbox_for_name(cls, name, show=False):
# If name is a string, find first tab with that name
elif isinstance(name, six.string_types):
- group, editor = name.split('/', 1)
- index = logger.uiWorkboxTAB.index_for_text(group)
- if index != -1:
- tab_widget = logger.uiWorkboxTAB.widget(index)
+ split = name.split('/', 1)
+ if len(split) < 2:
+ return None
+ group, editor = split
+ group_index = logger.uiWorkboxTAB.index_for_text(group)
+ if group_index != -1:
+ tab_widget = logger.uiWorkboxTAB.widget(group_index)
index = tab_widget.index_for_text(editor)
if index != -1:
workbox = tab_widget.widget(index)
+ if visible:
+ tab_widget.setCurrentIndex(index)
+ logger.uiWorkboxTAB.setCurrentIndex(group_index)
if show and workbox:
workbox.__show__()
@@ -979,6 +1000,13 @@ def showEvent(self, event):
def show_workbox_options(self):
self.uiWorkboxSTACK.setCurrentIndex(WorkboxPages.Options)
+ @Slot()
+ def show_focus_name(self):
+ model = WorkboxListItemModel(manager=self.uiWorkboxTAB)
+ model.process()
+ w = CommandPalette(model, parent=self)
+ w.popup()
+
def updateCopyIndentsAsSpaces(self):
for workbox in self.uiWorkboxTAB.all_widgets():
workbox.__set_copy_indents_as_spaces__(
diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui
index 32526914..d4bdab47 100644
--- a/preditor/gui/ui/loggerwindow.ui
+++ b/preditor/gui/ui/loggerwindow.ui
@@ -321,6 +321,7 @@
+
@@ -930,6 +931,14 @@ at the indicated line in the specified text editor.
Backup
+
+
+ Focus To Name
+
+
+ Ctrl+P
+
+