From f29abe081325bbc445146b7c0ce77ee6f067212c Mon Sep 17 00:00:00 2001
From: Suzanne Soy
Date: Wed, 1 Sep 2021 01:32:06 +0100
Subject: [PATCH] Run tools, show extra info
---
SearchTools/GatherTools.py | 2 -
SearchTools/SearchTools.py | 446 ++++++++++++++-----------------
SearchTools/SearchTools_notes.py | 150 +++++++++++
3 files changed, 358 insertions(+), 240 deletions(-)
diff --git a/SearchTools/GatherTools.py b/SearchTools/GatherTools.py
index 441d003..e69de29 100644
--- a/SearchTools/GatherTools.py
+++ b/SearchTools/GatherTools.py
@@ -1,2 +0,0 @@
-# action = json.loads(str(index.model().data(index.siblingAtColumn(2))))
-#² actionHandlers[action['handler']](action)
diff --git a/SearchTools/SearchTools.py b/SearchTools/SearchTools.py
index fef7d7a..a91d0d0 100644
--- a/SearchTools/SearchTools.py
+++ b/SearchTools/SearchTools.py
@@ -3,17 +3,53 @@ if True:
def toolbarAction(act):
print('show toolbar ' + act['toolbar'] + ' from workbenches ' + repr(act['workbenches']))
- def toolAction(act):
- print('start action for tool ' + act['toolbar'] + '.' + act['tool'] + ' from workbenches ' + repr(act['workbenches']))
def subToolAction(act):
- print('start action for tool ' + act['toolbar'] + '.' + act['tool'] + '.' + act['subTool'] + ' from workbenches ' + repr(act['workbenches']))
- def documentObjectAction():
- print('select object ' + o.Document.Name + '.' + o.Name)
- def documentAction():
- print('switch to document ' + o.Document.Name)
+ toolPath = act['toolbar'] + '.' + act['tool']
+ if 'subTool' in act:
+ toolPath = toolPath + '.' + act['subTool']
+ def runTool():
+ for the_toolbar in mw.findChildren(QtGui.QToolBar, act['toolbar']):
+ for tbt in the_toolbar.findChildren(QtGui.QToolButton):
+ if tbt.text() == act['tool']:
+ action = None
+ if 'subTool' in act:
+ men = tbt.menu()
+ if men:
+ for mac in men.actions():
+ if mac.text() == act['subTool']:
+ action = mac
+ break
+ else:
+ action = tbt.defaultAction()
+ if 'showMenu' in act and act['showMenu']:
+ print('Popup submenu of tool ' + toolPath + ' available in workbenches ' + repr(act['workbenches']))
+ the_toolbar.show()
+ tbt.showMenu()
+ return True
+ elif action is not None:
+ print('Run action of tool ' + toolPath + ' available in workbenches ' + repr(act['workbenches']))
+ action.trigger()
+ return True
+ return False
+ if runTool():
+ return
+ else:
+ for workbench in act['workbenches']:
+ print('Activating workbench ' + workbench + ' to access tool ' + toolPath)
+ Gui.activateWorkbench(workbench)
+ if runTool():
+ return
+ print('Tool ' + toolPath + ' not found, was it offered by an extension that is no longer present?')
+ def documentObjectAction(act):
+ print('select object ' + act['document'] + '.' + act['object'])
+ Gui.Selection.addSelection(act['document'], act['object'])
+ def documentAction(act):
+ # Todo: this should also select the document in the tree view
+ print('switch to document ' + act['document'])
+ App.setActiveDocument(act['document'])
actionHandlers = {
'toolbarAction': toolbarAction,
- 'toolAction': toolAction,
+ 'toolAction': subToolAction,
'subToolAction': subToolAction,
'documentObjectAction': documentObjectAction,
'documentAction': documentAction
@@ -48,14 +84,22 @@ if True:
self.listView = QtGui.QListView(self)
self.listView.setWindowFlags(QtGui.Qt.ToolTip)
self.listView.setWindowFlag(QtGui.Qt.FramelessWindowHint)
+ self.listView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.listView.setModel(self.proxyModel)
self.listView.setItemDelegate(itemDelegate) # https://stackoverflow.com/a/65930408/324969
# make the QListView non-editable
self.listView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
+ # Create pane for showing extra info about the currently-selected tool
+ #self.extraInfo = QtGui.QLabel()
+ self.extraInfo = QtGui.QTextEdit()
+ self.extraInfo.setReadOnly(True)
+ self.extraInfo.setWindowFlags(QtGui.Qt.ToolTip)
+ self.extraInfo.setWindowFlag(QtGui.Qt.FramelessWindowHint)
+ self.extraInfo.setAlignment(QtCore.Qt.AlignTop)
# Connect signals and slots
self.textChanged.connect(self.filterModel)
- self.listView.clicked.connect(self.selectResult)
- self.listView.selectionModel().selectionChanged.connect(self.showExtraInfo)
+ self.listView.clicked.connect(lambda x: self.selectResult('select', x))
+ self.listView.selectionModel().selectionChanged.connect(self.onSelectionChanged)
# Thanks to https://saurabhg.com/programming/search-box-using-qlineedit/ for indicating a few useful options
ico = QtGui.QIcon(':/icons/help-browser.svg')
#ico = QtGui.QIcon(':/icons/WhatsThis.svg')
@@ -69,15 +113,15 @@ if True:
self.showList()
super(SearchBox, self).focusInEvent(qFocusEvent)
def focusOutEvent(self, qFocusEvent):
- self.listView.hide()
+ self.hideList()
super(SearchBox, self).focusOutEvent(qFocusEvent)
def keyPressEvent(self, qKeyEvent):
key = qKeyEvent.key()
listMovementKeys = {
QtCore.Qt.Key_Down: lambda current, nbRows: (current + 1) % nbRows,
QtCore.Qt.Key_Up: lambda current, nbRows: (current - 1) % nbRows,
- QtCore.Qt.Key_PageDown: lambda current, nbRows: max(current + min(1, self.maxVisibleRows / 2), nbRows),
- QtCore.Qt.Key_PageUp: lambda current, nbRows: min(current - min(1, self.maxVisibleRows / 2), 0),
+ QtCore.Qt.Key_PageDown: lambda current, nbRows: min(current + max(1, self.maxVisibleRows / 2), nbRows - 1),
+ QtCore.Qt.Key_PageUp: lambda current, nbRows: max(current - max(1, self.maxVisibleRows / 2), 0),
}
acceptKeys = {
QtCore.Qt.Key_Enter: 'select',
@@ -101,14 +145,67 @@ if True:
elif key in acceptKeys:
self.showList()
if currentIndex.isValid():
- self.selectResult(acceptKeys[key], currentIndex, currentIndex.data())
+ self.selectResult(acceptKeys[key], currentIndex)
elif key in cancelKeys:
- self.listView.hide()
+ self.hideList()
self.clearFocus()
else:
self.showList()
super(SearchBox, self).keyPressEvent(qKeyEvent)
def showList(self):
+ self.setFloatingWidgetsGeometry()
+ self.listView.show()
+ self.showExtraInfo()
+ def hideList(self):
+ self.listView.hide()
+ self.hideExtraInfo()
+ def hideExtraInfo(self):
+ self.extraInfo.hide()
+ def selectResult(self, mode, index):
+ action = str(index.model().itemData(index.siblingAtColumn(2))[0])
+ self.hideList()
+ # TODO: allow other options, e.g. some items could act as combinators / cumulative filters
+ self.setText('')
+ self.filterModel(self.text())
+ # TODO: emit index relative to the base model
+ self.resultSelected.emit(index, action)
+ def filterModel(self, userInput):
+ def matches(s):
+ return userInput.lower() in s.lower()
+ def filterGroup(group):
+ if matches(group['text']):
+ # If a group matches, include the entire subtree (might need to disable this if it causes too much noise)
+ return group
+ else:
+ subitems = filterGroups(group['subitems'])
+ if len(subitems) > 0 or matches(group['text']):
+ return { 'text': group['text'], 'icon': group['icon'], 'action': group['action'], 'toolTipHTML':group['toolTipHTML'], 'subitems': subitems }
+ else:
+ return None
+ def filterGroups(groups):
+ groups = (filterGroup(group) for group in groups)
+ return [group for group in groups if group is not None]
+ def addGroups(filteredGroups, depth=0):
+ for group in filteredGroups:
+ mdl.appendRow([QtGui.QStandardItem(group['icon'] or QtGui.QIcon(), group['text']),
+ QtGui.QStandardItem(str(depth)),
+ QtGui.QStandardItem(group['action']),
+ QtGui.QStandardItem(group['toolTipHTML'])])
+ addGroups(group['subitems'], depth+1)
+ mdl = QtGui.QStandardItemModel()
+ mdl.appendColumn([])
+ addGroups(filterGroups(self.itemGroups))
+ self.proxyModel.setSourceModel(mdl)
+ # TODO: try to find the already-highlighted item
+ nbRows = self.listView.model().rowCount()
+ if nbRows > 0:
+ index = self.listView.model().index(0, 0)
+ self.listView.setCurrentIndex(index)
+ self.setExtraInfo(index)
+ else:
+ self.clearExtraInfo()
+ #self.showList()
+ def setFloatingWidgetsGeometry(self):
def getScreenPosition(widget):
geo = widget.geometry()
parent = widget.parent()
@@ -123,174 +220,46 @@ if True:
# TODO: this can still bump into the bottom of the screen, in that case we should flip
w = max(siz.width(), hint_w)
h = 100
+ extraw = w # choose a preferred width that doesn't change all the time,
+ # self.extraInfo.sizeHint().width() would change for every item.
+ extrax = x - extraw
if screen is not None:
scr = screen.geometry()
x = min(scr.x() + scr.width() - hint_w, x)
- self.listView.setGeometry(x, y, w, h)
- self.listView.show()
- def selectResult(self):
- self.listView.hide()
- # TODO: allow other options, e.g. some items could act as combinators / cumulative filters
- self.setText('')
- self.filterModel(self.text())
- self.resultSelected.emit("TODO: index", "TODO: str")
- def filterModel(self, userInput):
- def matches(s):
- return userInput.lower() in s.lower()
- def filterGroup(group):
- if matches(group['text']):
- # If a group matches, include the entire subtree (might need to disable this if it causes too much noise)
- return group
+ extraleftw = x - scr.x()
+ extrarightw = scr.x() + scr.width() - x
+ # flip the extraInfo if it doesn't fit on the screen
+ if extraleftw < extraw and extrarightw > extraleftw:
+ extrax = x + w
+ extraw = min(extrarightw, extraw)
else:
- subitems = filterGroups(group['subitems'])
- if len(subitems) > 0 or matches(group['text']):
- return { 'text': group['text'], 'icon': group['icon'], 'action': group['action'], 'subitems': subitems }
- else:
- return None
- def filterGroups(groups):
- groups = (filterGroup(group) for group in groups)
- return [group for group in groups if group is not None]
- def addGroups(filteredGroups, depth=0):
- for group in filteredGroups:
- mdl.appendRow([QtGui.QStandardItem(group['icon'] or QtGui.QIcon(), group['text']),
- QtGui.QStandardItem(str(depth)),
- QtGui.QStandardItem(group['action'])])
- addGroups(group['subitems'], depth+1)
- mdl = QtGui.QStandardItemModel()
- mdl.appendColumn([])
- addGroups(filterGroups(self.itemGroups))
+ extrax = x - extraw
+ extraw = min(extraleftw, extraw)
+ self.listView.setGeometry(x, y, w, h)
+ self.extraInfo.setGeometry(extrax, y, extraw, h)
+ def onSelectionChanged(self, selected, deselected):
+ # The list has .setSelectionMode(QtGui.QAbstractItemView.SingleSelection),
+ # so there is always at most one index in selected.indexes() and at most one
+ # index in deselected.indexes()
+ selected = selected.indexes()
+ deselected = deselected.indexes()
+ if len(selected) > 0:
+ index = selected[0]
+ self.setExtraInfo(index)
+ # Poor attempt to circumvent a glitch where the extra info pane stays visible after pressing Return
+ if not self.listView.isHidden():
+ self.showExtraInfo()
+ elif len(deselected) > 0:
+ self.hideExtraInfo()
+ def setExtraInfo(self, index):
+ toolTipHTML = str(index.model().itemData(index.siblingAtColumn(3))[0])
+ self.extraInfo.setText(toolTipHTML)
+ self.setFloatingWidgetsGeometry()
+ def clearExtraInfo(self, index):
+ self.extraInfo.setText('')
+ def showExtraInfo(self):
+ self.extraInfo.show()
- print('setSourceModel for userInput ' + repr(userInput) + ' with ' + str(mdl.rowCount()) + ' rows.')
- self.proxyModel.setSourceModel(mdl)
- #print('TODO: do the actual filtering')
- #flt = QtCore.QSortFilterProxyModel()
- #flt.setSourceModel(self.model)
- #flt.setFilterCaseSensitivity(QtCore.Qt.CaseSensitivity.CaseInsensitive)
- #flt.setFilterWildcard(query)
- #self.listView.setModel(flt)
- # TODO: try to find the already-highlighted item
- nbRows = self.listView.model().rowCount()
- if nbRows > 0:
- index = self.listView.model().index(0, 0)
- self.listView.setCurrentIndex(index)
- #self.showList()
- def showExtraInfo(selected, deselected):
- print('show extra info...', repr(selected))
- pass
- #mdl = QtCore.QStringListModel(['aaa', 'aab', 'aac', 'bxy', 'bac'])
- #sbx = SearchBox(mdl, 10, None)
- #sbx.show()
-
- # Inspired by https://stackoverflow.com/a/7767999/324969
- #class SearchQCompleter(QtGui.QCompleter):
- # def __init__(self, model, itemDelegate):
- # super(SearchQCompleter, self).__init__()
- # super(SearchQCompleter, self).setModel(QtCore.QIdentityProxyModel())
- # #https://stackoverflow.com/a/65930408/324969
- # super(SearchQCompleter, self).popup().setItemDelegate(itemDelegate)
- # self.setModel(model)
- #
- # def setModel(self, itemGroups):
- # self.itemGroups = itemGroups
- # self.filterModel('')
- #
- # def filterModel(self, userInput):
- # def matches(s):
- # return userInput.lower() in s.lower()
- # def filterGroup(group):
- # if matches(group['text']):
- # # If a group matches, include the entire subtree (might need to disable this if it causes too much noise)
- # return group
- # else:
- # subitems = filterGroups(group['subitems'])
- # if len(subitems) > 0 or matches(group['text']):
- # return { 'text': group['text'], 'icon': group['icon'], 'action': group['action'], 'subitems': subitems }
- # else:
- # return None
- # def filterGroups(groups):
- # groups = (filterGroup(group) for group in groups)
- # return [group for group in groups if group is not None]
- # def addGroups(filteredGroups, depth=0):
- # for group in filteredGroups:
- # mdl.appendRow([QtGui.QStandardItem(group['icon'] or QtGui.QIcon(), group['text']),
- # QtGui.QStandardItem(str(depth)),
- # QtGui.QStandardItem(group['action'])])
- # addGroups(group['subitems'], depth+1)
- # mdl = QtGui.QStandardItemModel()
- # mdl.appendColumn([])
- # addGroups(filterGroups(itemGroups))
- #
- # print('setSourceModel for userInput ' + repr(userInput) + ' with ' + str(mdl.rowCount()) + ' rows.')
- # self.model().setSourceModel(mdl)
- # # https://stackoverflow.com/a/65930408/324969
- #
- # # the splitPath(self, path) method is called every time the input string changes, before
- # # drawing the completion list, we latch onto this method to also update the model to contain
- # # the appropriate results, as given by the custom filterAcceptsRow method above.
- # def splitPath(self, path):
- # self.filterModel(path)
- # # Pretend that the user endered the empty string, so that all items from the filteredProxyModel match.
- # return ''
- #
- #class SearchBox(QtGui.QLineEdit):
- # resultSelected = QtCore.Signal(int, str)
- # def __init__(self, itemGroups):
- # super(SearchBox, self).__init__()
- # qom = SearchQCompleter(itemGroups, IndentedItemDelegate())
- # qom.setMaxVisibleItems(20)
- # #qom.setCompletionMode(QtGui.QCompleter.CompletionMode.PopupCompletion)
- # # Thanks to https://saurabhg.com/programming/search-box-using-qlineedit/ for indicating a few useful options
- # ico = QtGui.QIcon(':/icons/help-browser.svg')
- # #ico = QtGui.QIcon(':/icons/WhatsThis.svg')
- # self.addAction(ico, QtGui.QLineEdit.LeadingPosition)
- # self.setClearButtonEnabled(True)
- # self.setPlaceholderText('Search tools, prefs & tree')
- # self.setFixedWidth(200)
- # # Signals & slots for enter / click
- # def completerActivated(index):
- # print('fooooooooooooo')
- # print(qom.model().rowCount(), index.row())
- # # TODO: run the action!
- # result = str(qom.model().data(index.siblingAtColumn(1)))
- # print('res='+result)
- # self.clear()
- # self.completer().setCompletionPrefix('')
- # self.resultSelected.emit(str(index), result)
- # def returnPressed():
- # #self.clear()
- # #self.completer().setCompletionPrefix('')
- # pass
- # #text = sea.text()
- # #self.clear()
- # #self.resultSelected.emit('text returnPressed' + text)
- # self.returnPressed.connect(returnPressed)
- # #QtCore.QObject.connect(self.completer(), QtCore.SIGNAL('activated(QModelIndex)'), completerActivated) #, QtCore.Qt.ConnectionType.QueuedConnection)
- # qom.activated.connect(completerActivated, QtCore.Qt.ConnectionType.DirectConnection) #, QtCore.Qt.ConnectionType.QueuedConnection)
- # #self.completer().activated.connect(returnPressedOrCompleterActivated)
- # def textChanged():
- # print('textChanged')
- # # Workaround: Clear completion prefix and still show the completion box when doing backspace after typing a single character
- # if self.text() == '':
- # self.completer().setCompletionPrefix(self.text())
- # self.completer().complete()
- # self.textChanged.connect(textChanged)
- # QtCore.QObject.connect(qom.popup(), QtCore.SIGNAL('clicked(QModelIndex)'), lambda x: print(x))
- # self.setCompleter(qom)
- # def focusInEvent(self, e):
- # super(SearchBox, self).focusInEvent(e)
- # self.completer().setCompletionPrefix(self.text())
- # self.completer().complete()
- # self.completer().setCurrentRow(1) # Does not work
- # #d=QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Down, QtCore.Qt.NoModifier)
- # #QtCore.QCoreApplication.postEvent(self, d)
- # def mousePressEvent(self, e):
- # super(SearchBox, self).mousePressEvent(e)
- # self.completer().setCompletionPrefix(self.text())
- # self.completer().complete()
- # self.completer().setCurrentRow(1) # Does not work
- # #d=QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Down, QtCore.Qt.NoModifier)
- # #QtCore.QCoreApplication.postEvent(self, d)
- #
mw = Gui.getMainWindow()
mdi = mw.findChild(QtGui.QMdiArea)
@@ -299,16 +268,20 @@ if True:
mwx = QtGui.QMainWindow()
mbr = mw.findChildren(QtGui.QToolBar, 'File')[0]
- all_tbs = set()
- for wbname, workbench in Gui.listWorkbenches().items():
- try:
- tbs = workbench.listToolbars()
- except:
- continue
- # careful, tbs contains all the toolbars of the workbench, including shared toolbars
- for tb in tbs:
- all_tbs.add(tb)
-
+ def getAllToolbars():
+ all_tbs = dict()
+ for wbname, workbench in Gui.listWorkbenches().items():
+ try:
+ tbs = workbench.listToolbars()
+ except:
+ continue
+ # careful, tbs contains all the toolbars of the workbench, including shared toolbars
+ for tb in tbs:
+ if tb not in all_tbs:
+ all_tbs[tb] = set()
+ all_tbs[tb].add(wbname)
+ return all_tbs
+
import json
def serializeIcon(icon):
iconPixmaps = {}
@@ -331,7 +304,8 @@ if True:
'workbenches': tool['workbenches'],
'toolbar': tool['toolbar'],
'text': tool['text'],
- 'icon': serializeIcon(tool['icon'])
+ 'icon': serializeIcon(tool['icon']),
+ 'toolTipHTML': tool['toolTipHTML']
}
def deserializeIcon(iconPixmaps):
@@ -352,76 +326,68 @@ if True:
'workbenches': tool['workbenches'],
'toolbar': tool['toolbar'],
'text': tool['text'],
- 'icon': deserializeIcon(tool['icon'])
+ 'icon': deserializeIcon(tool['icon']),
+ 'toolTipHTML': tool['toolTipHTML']
}
- #serialized = serializeTools([{'workbenches': ['wb1', 'wb2'], 'toolbar': 'tbr', 'text': 'aa', 'icon': ic}])
- #serialized = serializeTools([])
-
- #TODO:save in App.getUserAppDataDir() ################################################################################################################
+ # TODO: save serialized tools in App.getUserAppDataDir() ################################################################################################################
+ # + never cache the document objects
def GatherTools():
itemGroups = []
- for toolbarName in all_tbs:
+ all_tbs = getAllToolbars()
+ for toolbarName, toolbarIsInWorkbenches in all_tbs.items():
+ toolbarIsInWorkbenches = sorted(list(toolbarIsInWorkbenches))
for the_toolbar in mw.findChildren(QtGui.QToolBar, toolbarName):
- group = []
-
- for tbt in the_toolbar.findChildren(QtGui.QToolButton):
- text = tbt.text()
- act = tbt.defaultAction()
- if text != '':
- # TODO: there also is the tooltip
- icon = tbt.icon()
- #sim.appendRow([QtGui.QStandardItem(icon, 't:' + text), QtGui.QStandardItem('tool')])
- men = tbt.menu()
+ group = []
+ for tbt in the_toolbar.findChildren(QtGui.QToolButton):
+ text = tbt.text()
+ act = tbt.defaultAction()
+ if text != '':
+ # TODO: there also is the tooltip
+ icon = tbt.icon()
+ men = tbt.menu()
+ subgroup = []
+ if men:
subgroup = []
- if men:
- subgroup = []
- for mac in men.actions():
- if mac.text():
- #all_actions.append(mac.trigger)
- action = { 'handler': 'subToolAction', 'workbenches': [], 'toolbar': toolbarName, 'tool': text, 'subtool': mac.text() }
- #print('whaaaat', str(len(all_actions)))
- subgroup.append({'icon':mac.icon(), 'text':mac.text(), 'action':json.dumps(action), 'subitems':[]})
- #all_actions.append(tbt.actions().trigger)
- #global lalala
- #lalala=tbt
- #print('whuuuut', str(len(all_actions)))
- action = { 'handler': 'toolAction', 'workbenches': [], 'toolbar': toolbarName, 'tool': text }
- group.append({'icon':icon, 'text':text, 'action': json.dumps(action), 'subitems': subgroup})
-
- #viu = mw.findChildren(QtGui.QToolBar, 'View')[0]
- #tbt = viu.findChildren(QtGui.QToolButton)
- #men = tbt[3].menu()
- #acs = men.actions() # QtGui.QAction list
- #act = tbt[2].defaultAction() # QtGui.QAction
- #act.trigger()
- action = { 'handler': 'toolbarAction', 'workbenches': [], 'toolbar': toolbarName }
- itemGroups.append({
- 'icon': QtGui.QIcon(':/icons/Group.svg'),
- 'text': toolbarName,
- 'action': json.dumps(action),
- 'subitems': group
- })
+ for mac in men.actions():
+ if mac.text():
+ action = { 'handler': 'subToolAction', 'workbenches': toolbarIsInWorkbenches, 'toolbar': toolbarName, 'tool': text, 'subTool': mac.text() }
+ subgroup.append({'icon':mac.icon(), 'text':mac.text(), 'toolTipHTML': mac.toolTip(), 'action':json.dumps(action), 'subitems':[]})
+ # The default action of a menu changes dynamically, instead of triggering the last action, just show the menu.
+ action = { 'handler': 'toolAction', 'workbenches': toolbarIsInWorkbenches, 'toolbar': toolbarName, 'tool': text, 'showMenu': bool(men) }
+ group.append({'icon':icon, 'text':text, 'toolTipHTML': tbt.toolTip(), 'action': json.dumps(action), 'subitems': subgroup})
+ # TODO: move the 'workbenches' field to the itemgroup
+ action = { 'handler': 'toolbarAction', 'workbenches': toolbarIsInWorkbenches, 'toolbar': toolbarName }
+ itemGroups.append({
+ 'icon': QtGui.QIcon(':/icons/Group.svg'),
+ 'text': toolbarName,
+ 'toolTipHTML': 'Display toolbar ' + toolbarName + '
This toolbar appears in the following workbenches:
' + ''.join(['- ' + wb + '
' for wb in toolbarIsInWorkbenches]) + '
',
+ 'action': json.dumps(action),
+ 'subitems': group
+ })
#
def document(doc):
group = []
for o in doc.Objects:
- #all_actions.append(lambda: Gui.Selection.addSelection(o.Document.Name, o.Name))
+ #all_actions.append(lambda: )
action = { 'handler': 'documentObjectAction', 'document': o.Document.Name, 'object': o.Name }
item = {
'icon': o.ViewObject.Icon if o.ViewObject and o.ViewObject.Icon else None,
'text': o.Label + ' (' + o.Name + ')',
+ # TODO: preview of the object
+ 'toolTipHTML': '' + o.Label + '
App.getDocument(' + repr(o.Document.Name) + ').getObject(' + repr(o.Name) + ')
' + '

',
'action': json.dumps(action),
'subitems': []
}
group.append(item)
- # Todo: this should also select the document in the tree view
- action = { 'handler': 'documentAction', 'document': o.Document.Name }
+ action = { 'handler': 'documentAction', 'document': doc.Name }
itemGroups.append({
'icon': QtGui.QIcon(':/icons/Document.svg'),
'text': doc.Label + ' (' + doc.Name + ')',
+ # TODO: preview of the document
+ 'toolTipHTML': '' + doc.Label + '
App.getDocument(' + repr(doc.Name) + ')

',
'action':json.dumps(action),
'subitems': group })
if App.ActiveDocument:
@@ -435,6 +401,7 @@ if True:
return {
'icon': serializeIcon(itemGroup['icon']),
'text': itemGroup['text'],
+ 'toolTipHTML': itemGroup['toolTipHTML'],
'action': itemGroup['action'],
'subitems': serializeItemGroups(itemGroup['subitems'])
}
@@ -443,10 +410,10 @@ if True:
def serialize(itemGroups):
return json.dumps(serializeItemGroups(itemGroups))
def deserializeItemGroup(itemGroup):
- #print('dIG' + text + " : " + repr(itemGroup['icon'])[:100] + "......................." + repr(itemGroup['icon'])[-100:])
return {
'icon': deserializeIcon(itemGroup['icon']),
'text': itemGroup['text'],
+ 'toolTipHTML': itemGroup['toolTipHTML'],
'action': itemGroup['action'],
'subitems': deserializeItemGroups(itemGroup['subitems'])
}
@@ -460,7 +427,10 @@ if True:
#
sea = SearchBox(itemGroups)
- sea.resultSelected.connect(lambda x, y: print('aaa' + repr(y) + 'end'))
+ def onResultSelected(index, metadata):
+ action = json.loads(metadata)
+ actionHandlers[action['handler']](action)
+ sea.resultSelected.connect(onResultSelected)
wax = QtGui.QWidgetAction(None)
wax.setDefaultWidget(sea)
#mbr.addWidget(sea)
diff --git a/SearchTools/SearchTools_notes.py b/SearchTools/SearchTools_notes.py
index 6a242ad..bd25882 100644
--- a/SearchTools/SearchTools_notes.py
+++ b/SearchTools/SearchTools_notes.py
@@ -191,3 +191,153 @@
# return True
#filteredProxyModel = FilterProxyModel()
#filteredProxyModel.setSourceModel(mdl)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #mdl = QtCore.QStringListModel(['aaa', 'aab', 'aac', 'bxy', 'bac'])
+ #sbx = SearchBox(mdl, 10, None)
+ #sbx.show()
+
+ # Inspired by https://stackoverflow.com/a/7767999/324969
+ #class SearchQCompleter(QtGui.QCompleter):
+ # def __init__(self, model, itemDelegate):
+ # super(SearchQCompleter, self).__init__()
+ # super(SearchQCompleter, self).setModel(QtCore.QIdentityProxyModel())
+ # #https://stackoverflow.com/a/65930408/324969
+ # super(SearchQCompleter, self).popup().setItemDelegate(itemDelegate)
+ # self.setModel(model)
+ #
+ # def setModel(self, itemGroups):
+ # self.itemGroups = itemGroups
+ # self.filterModel('')
+ #
+ # def filterModel(self, userInput):
+ # def matches(s):
+ # return userInput.lower() in s.lower()
+ # def filterGroup(group):
+ # if matches(group['text']):
+ # # If a group matches, include the entire subtree (might need to disable this if it causes too much noise)
+ # return group
+ # else:
+ # subitems = filterGroups(group['subitems'])
+ # if len(subitems) > 0 or matches(group['text']):
+ # return { 'text': group['text'], 'icon': group['icon'], 'action': group['action'], 'subitems': subitems }
+ # else:
+ # return None
+ # def filterGroups(groups):
+ # groups = (filterGroup(group) for group in groups)
+ # return [group for group in groups if group is not None]
+ # def addGroups(filteredGroups, depth=0):
+ # for group in filteredGroups:
+ # mdl.appendRow([QtGui.QStandardItem(group['icon'] or QtGui.QIcon(), group['text']),
+ # QtGui.QStandardItem(str(depth)),
+ # QtGui.QStandardItem(group['action'])])
+ # addGroups(group['subitems'], depth+1)
+ # mdl = QtGui.QStandardItemModel()
+ # mdl.appendColumn([])
+ # addGroups(filterGroups(itemGroups))
+ #
+ # print('setSourceModel for userInput ' + repr(userInput) + ' with ' + str(mdl.rowCount()) + ' rows.')
+ # self.model().setSourceModel(mdl)
+ # # https://stackoverflow.com/a/65930408/324969
+ #
+ # # the splitPath(self, path) method is called every time the input string changes, before
+ # # drawing the completion list, we latch onto this method to also update the model to contain
+ # # the appropriate results, as given by the custom filterAcceptsRow method above.
+ # def splitPath(self, path):
+ # self.filterModel(path)
+ # # Pretend that the user endered the empty string, so that all items from the filteredProxyModel match.
+ # return ''
+ #
+ #class SearchBox(QtGui.QLineEdit):
+ # resultSelected = QtCore.Signal(int, str)
+ # def __init__(self, itemGroups):
+ # super(SearchBox, self).__init__()
+ # qom = SearchQCompleter(itemGroups, IndentedItemDelegate())
+ # qom.setMaxVisibleItems(20)
+ # #qom.setCompletionMode(QtGui.QCompleter.CompletionMode.PopupCompletion)
+ # # Thanks to https://saurabhg.com/programming/search-box-using-qlineedit/ for indicating a few useful options
+ # ico = QtGui.QIcon(':/icons/help-browser.svg')
+ # #ico = QtGui.QIcon(':/icons/WhatsThis.svg')
+ # self.addAction(ico, QtGui.QLineEdit.LeadingPosition)
+ # self.setClearButtonEnabled(True)
+ # self.setPlaceholderText('Search tools, prefs & tree')
+ # self.setFixedWidth(200)
+ # # Signals & slots for enter / click
+ # def completerActivated(index):
+ # print('fooooooooooooo')
+ # print(qom.model().rowCount(), index.row())
+ # # TODO: run the action!
+ # result = str(qom.model().data(index.siblingAtColumn(1)))
+ # print('res='+result)
+ # self.clear()
+ # self.completer().setCompletionPrefix('')
+ # self.resultSelected.emit(str(index), result)
+ # def returnPressed():
+ # #self.clear()
+ # #self.completer().setCompletionPrefix('')
+ # pass
+ # #text = sea.text()
+ # #self.clear()
+ # #self.resultSelected.emit('text returnPressed' + text)
+ # self.returnPressed.connect(returnPressed)
+ # #QtCore.QObject.connect(self.completer(), QtCore.SIGNAL('activated(QModelIndex)'), completerActivated) #, QtCore.Qt.ConnectionType.QueuedConnection)
+ # qom.activated.connect(completerActivated, QtCore.Qt.ConnectionType.DirectConnection) #, QtCore.Qt.ConnectionType.QueuedConnection)
+ # #self.completer().activated.connect(returnPressedOrCompleterActivated)
+ # def textChanged():
+ # print('textChanged')
+ # # Workaround: Clear completion prefix and still show the completion box when doing backspace after typing a single character
+ # if self.text() == '':
+ # self.completer().setCompletionPrefix(self.text())
+ # self.completer().complete()
+ # self.textChanged.connect(textChanged)
+ # QtCore.QObject.connect(qom.popup(), QtCore.SIGNAL('clicked(QModelIndex)'), lambda x: print(x))
+ # self.setCompleter(qom)
+ # def focusInEvent(self, e):
+ # super(SearchBox, self).focusInEvent(e)
+ # self.completer().setCompletionPrefix(self.text())
+ # self.completer().complete()
+ # self.completer().setCurrentRow(1) # Does not work
+ # #d=QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Down, QtCore.Qt.NoModifier)
+ # #QtCore.QCoreApplication.postEvent(self, d)
+ # def mousePressEvent(self, e):
+ # super(SearchBox, self).mousePressEvent(e)
+ # self.completer().setCompletionPrefix(self.text())
+ # self.completer().complete()
+ # self.completer().setCurrentRow(1) # Does not work
+ # #d=QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Down, QtCore.Qt.NoModifier)
+ # #QtCore.QCoreApplication.postEvent(self, d)
+ #
+
+ #sim.appendRow([QtGui.QStandardItem(icon, 't:' + text), QtGui.QStandardItem('tool')])
+
+ #all_actions.append(mac.trigger)
+
+ #print('whaaaat', str(len(all_actions)))
+
+ #all_actions.append(tbt.actions().trigger)
+ #global lalala
+ #lalala=tbt
+ #print('whuuuut', str(len(all_actions)))
+
+ #viu = mw.findChildren(QtGui.QToolBar, 'View')[0]
+ #tbt = viu.findChildren(QtGui.QToolButton)
+ #men = tbt[3].menu()
+ #acs = men.actions() # QtGui.QAction list
+ #act = tbt[2].defaultAction() # QtGui.QAction
+ #act.trigger()