mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Draft implementation for search in settings
This commit is contained in:
parent
13266d005c
commit
4af3b1b1f9
2 changed files with 162 additions and 0 deletions
137
openpype/tools/settings/settings/search.py
Normal file
137
openpype/tools/settings/settings/search.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
from functools import partial
|
||||
import re
|
||||
|
||||
from Qt import QtCore, QtWidgets
|
||||
from openpype.tools.utils.models import TreeModel, Item
|
||||
from openpype.tools.utils.lib import schedule
|
||||
|
||||
|
||||
def get_entity_children(entity):
|
||||
|
||||
if hasattr(entity, "values"):
|
||||
return entity.values()
|
||||
return []
|
||||
|
||||
|
||||
class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
"""Filters recursively to regex in all columns"""
|
||||
|
||||
def __init__(self):
|
||||
super(RecursiveSortFilterProxyModel, self).__init__()
|
||||
|
||||
# Note: Recursive filtering was introduced in Qt 5.10.
|
||||
self.setRecursiveFilteringEnabled(True)
|
||||
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
|
||||
if not parent.isValid():
|
||||
return False
|
||||
|
||||
regex = self.filterRegExp()
|
||||
if not regex.isEmpty() and regex.isValid():
|
||||
pattern = regex.pattern()
|
||||
source_model = self.sourceModel()
|
||||
|
||||
# Check current index itself in all columns
|
||||
for column in range(source_model.columnCount(parent)):
|
||||
source_index = source_model.index(row, column, parent)
|
||||
if not source_index.isValid():
|
||||
continue
|
||||
|
||||
key = source_model.data(source_index, self.filterRole())
|
||||
if not key:
|
||||
continue
|
||||
|
||||
if re.search(pattern, key, re.IGNORECASE):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
return super(RecursiveSortFilterProxyModel,
|
||||
self).filterAcceptsRow(row, parent)
|
||||
|
||||
|
||||
class SearchEntitiesDialog(QtWidgets.QDialog):
|
||||
|
||||
path_clicked = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, entity, parent=None):
|
||||
super(SearchEntitiesDialog, self).__init__(parent=parent)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
filter_edit = QtWidgets.QLineEdit()
|
||||
filter_edit.setPlaceholderText("Search..")
|
||||
|
||||
model = EntityTreeModel()
|
||||
proxy = RecursiveSortFilterProxyModel()
|
||||
proxy.setSourceModel(model)
|
||||
proxy.setDynamicSortFilter(True)
|
||||
view = QtWidgets.QTreeView()
|
||||
view.setModel(proxy)
|
||||
|
||||
layout.addWidget(filter_edit)
|
||||
layout.addWidget(view)
|
||||
|
||||
filter_edit.textChanged.connect(self._on_filter_changed)
|
||||
view.selectionModel().selectionChanged.connect(self.on_select)
|
||||
|
||||
view.setAllColumnsShowFocus(True)
|
||||
view.setSortingEnabled(True)
|
||||
view.sortByColumn(1, QtCore.Qt.AscendingOrder)
|
||||
|
||||
self._model = model
|
||||
self._proxy = proxy
|
||||
self._view = view
|
||||
|
||||
# Refresh to the passed entity
|
||||
model.set_root(entity)
|
||||
|
||||
view.resizeColumnToContents(0)
|
||||
|
||||
def _on_filter_changed(self, txt):
|
||||
# Provide slight delay to filtering so user can type quickly
|
||||
schedule(partial(self.on_filter_changed, txt), 250, channel="search")
|
||||
|
||||
def on_filter_changed(self, txt):
|
||||
self._proxy.setFilterRegExp(txt)
|
||||
|
||||
# WARNING This expanding and resizing is relatively slow.
|
||||
self._view.expandAll()
|
||||
self._view.resizeColumnToContents(0)
|
||||
|
||||
def on_select(self):
|
||||
current = self._view.currentIndex()
|
||||
item = current.data(EntityTreeModel.ItemRole)
|
||||
self.path_clicked.emit(item["path"])
|
||||
|
||||
|
||||
class EntityTreeModel(TreeModel):
|
||||
|
||||
Columns = ["trail", "label", "key", "path"]
|
||||
|
||||
def add_entity(self, entity, parent=None):
|
||||
|
||||
item = Item()
|
||||
|
||||
# Label and key can sometimes be emtpy so we use the trail from path
|
||||
# in the most left column since it's never empty
|
||||
item["trail"] = entity.path.rsplit("/", 1)[-1]
|
||||
item["label"] = entity.label
|
||||
item["key"] = entity.key
|
||||
item["path"] = entity.path
|
||||
|
||||
parent.add_child(item)
|
||||
|
||||
for child in get_entity_children(entity):
|
||||
self.add_entity(child, parent=item)
|
||||
|
||||
def set_root(self, root_entity):
|
||||
self.clear()
|
||||
self.beginResetModel()
|
||||
|
||||
# We don't want to see the root entity so we directly add its children
|
||||
for child in get_entity_children(root_entity):
|
||||
self.add_entity(child, parent=self._root_item)
|
||||
self.endResetModel()
|
||||
|
||||
|
|
@ -164,3 +164,28 @@ class MainWidget(QtWidgets.QWidget):
|
|||
result = dialog.exec_()
|
||||
if result == 1:
|
||||
self.trigger_restart.emit()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
|
||||
# todo: This might not be the cleanest place but works for prototype
|
||||
if event.matches(QtGui.QKeySequence.Find):
|
||||
print("Search!")
|
||||
|
||||
# todo: search in all widgets (or in active)?
|
||||
widget = self._header_tab_widget.currentWidget()
|
||||
root_entity = widget.entity
|
||||
|
||||
from .search import SearchEntitiesDialog
|
||||
search = SearchEntitiesDialog(root_entity, parent=self)
|
||||
search.resize(700, 500)
|
||||
search.setWindowTitle("Search")
|
||||
search.show()
|
||||
|
||||
def on_path(path):
|
||||
widget.breadcrumbs_widget.change_path(path)
|
||||
|
||||
search.path_clicked.connect(on_path)
|
||||
event.accept()
|
||||
return
|
||||
|
||||
return super(MainWidget, self).keyPressEvent(event)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue