Skip to content

Commit e82a047

Browse files
committed
feat: add action icons to datasource toolbar
1 parent 872942f commit e82a047

7 files changed

Lines changed: 70 additions & 23 deletions

File tree

pre_workbench/datawidgets.py

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
from PyQt5.QtCore import (Qt, pyqtSignal, QAbstractItemModel, QModelIndex, pyqtSlot)
2525
from PyQt5.QtWidgets import QTextEdit, QTabWidget, QWidget, QVBoxLayout, \
2626
QMenu, \
27-
QAbstractItemView, QTableView
27+
QAbstractItemView, QTableView, QAction, QInputDialog, QMessageBox
2828

2929
import pre_workbench.app
3030

31-
from pre_workbench.configs import SettingsField
31+
from pre_workbench.configs import SettingsField, getIcon
3232
from pre_workbench.guihelper import getMonospaceFont, setClipboardText, getClipboardText, APP
3333
from pre_workbench.structinfo.expr import Expression
3434
from pre_workbench.controls.genericwidgets import showSettingsDlg, showListSelectDialog
@@ -181,6 +181,7 @@ class PacketListWidget(QWidget):
181181

182182
def __init__(self):
183183
super().__init__()
184+
self.lastFindExpression = ""
184185
self.initUI()
185186

186187
def showData(self, data: List[ByteBuffer]):
@@ -216,6 +217,25 @@ def initUI(self):
216217
self.packetlist.selectionModel().currentChanged.connect(self.onPacketlistCurrentChanged)
217218
#tabs.addTab(self.packetlist, "Raw Frames")
218219
layout.addWidget(self.packetlist)
220+
self.actions = [
221+
QAction(getIcon("magnifier-flag.png"), "Find By Expression", triggered=self._findByExpression),
222+
QAction(getIcon("flag.png"), "Mark/Unmark Selected Packets", triggered=self._markUnmarkSelection),
223+
QAction(getIcon("table-reset.png"), "Reset Header", triggered=lambda: self.packetlistmodel.autoCols()),
224+
QAction(getIcon("table-insert-column-tag.png"), "Add Metadata Column", triggered=lambda: self._quickAddDialog("Quick Add Metadata Column", self._getQuickAddMetadataElements(), None)),
225+
QAction(getIcon("table-insert-column-bookmark.png"), "Add Field Column", triggered=lambda: self._quickAddDialog("Quick Add Field Column", self._getQuickAddFieldElements(), None)),
226+
]
227+
228+
def _findByExpression(self):
229+
expr_str = QInputDialog.getText(self, "Find By Expression", "Please enter expression. All rows for which the expression is true will be marked, all others unmarked.", text=self.lastFindExpression)[0]
230+
if not expr_str: return
231+
self.lastFindExpression = expr_str
232+
expr = Expression(expr_str=expr_str)
233+
matches = 0
234+
for rowIndex, buf in enumerate(self.packetlistmodel.listObject.buffers):
235+
match = buf.metadata['marked'] = bool(expr.evaluate_bbuf(buf))
236+
if match: matches += 1
237+
self.packetlistmodel.headerDataChanged.emit(Qt.Vertical, rowIndex, rowIndex)
238+
QMessageBox.information(self, "Find By Expression", f"Of {len(self.packetlistmodel.listObject.buffers)} buffers, {matches} matched the expression " + expr.serialize())
219239

220240
def _rowHeaderClicked(self, rowIndex: int):
221241
self.packetlistmodel.markPacket(rowIndex)
@@ -225,6 +245,7 @@ def setContents(self, lstObj: Optional[ByteBufferList]):
225245
logging.debug("PacketListWidget::setContents %r %d", lstObj, len(lstObj))
226246
self.setWindowTitle(str(lstObj))
227247
self.packetlistmodel.setList(self.listObject)
248+
self.meta_updated.emit("actions", self.actions)
228249

229250
def onPacketlistSelectionChanged(self, selected, deselected):
230251
buffers = list()
@@ -243,13 +264,16 @@ def onPacketlistContextMenu(self, point):
243264
ctx = QMenu("Context menu", self.packetlist)
244265
if index.isValid():
245266
ctx.addAction("Item Details", lambda: self.showData(self.getSelectedBuffers()))
246-
ctx.addAction("Mark/Unmark Packet", lambda: [self.packetlistmodel.markPacket(index.row()) for index in self.packetlist.selectionModel().selectedRows()])
267+
ctx.addAction("Mark/Unmark Packet", self._markUnmarkSelection)
247268
self._buildRunMacroOnBufferSubmenu(ctx, "Run Macro On" + (" Selected Buffers" if len(self.packetlist.selectionModel().selectedRows()) > 1 else " Buffer"))
248269
ctx.addSeparator()
249270
ctx.addAction("Select All", lambda: self.packetlist.selectAll())
250271

251272
ctx.exec(self.packetlist.viewport().mapToGlobal(point))
252273

274+
def _markUnmarkSelection(self):
275+
[self.packetlistmodel.markPacket(index.row()) for index in self.packetlist.selectionModel().selectedRows()]
276+
253277
def _buildRunMacroOnBufferSubmenu(self, ctx, title):
254278
menu = ctx.addMenu(title)
255279
for container_id, container, macroName in APP().find_macros_by_input_types(["BYTE_BUFFER", "BYTE_BUFFER_LIST"]):
@@ -266,17 +290,28 @@ def _runMacroOnSelectedBuffers(self, container, macroname):
266290
lst.add(self.listObject.buffers[index.row()])
267291
macro.execute(lst)
268292

293+
def _quickAddDialog(self, title: str, elements: List[Tuple[str, str]], addIdx: int):
294+
def on_ok(keys):
295+
for key in keys:
296+
self.packetlistmodel.addColumn(ColumnInfo(key, key), addIdx)
297+
showListSelectDialog(elements, None, title, self, on_ok, multiselect=True)
298+
269299
def _generateQuickAddMenu(self, ctx: QMenu, title: str, elements: List[Tuple[str, str]], addIdx: int):
270300
if len(elements) > 20:
271-
def on_ok(keys):
272-
for key in keys:
273-
self.packetlistmodel.addColumn(ColumnInfo(key, key), addIdx)
274-
ctx.addAction(title + " ...", lambda: showListSelectDialog(elements, None, title, self, on_ok, multiselect=True))
301+
ctx.addAction(title + " ...", lambda: self._quickAddDialog(title, elements, addIdx))
275302
else:
276303
quick = ctx.addMenu(title)
277304
for key, text in elements:
278305
quick.addAction(text, lambda key=key, text=text: self.packetlistmodel.addColumn(ColumnInfo(key, text), addIdx))
279306

307+
def _getQuickAddMetadataElements(self):
308+
return [("${\"" + key + "\"}", "$" + key) for key in
309+
sorted(self.listObject.getAllKeys(metadataKeys=True, fieldKeys=False))]
310+
311+
def _getQuickAddFieldElements(self):
312+
return [("fields[\""+key+"\"]", key) for key in
313+
sorted(self.listObject.getAllKeys(metadataKeys=False, fieldKeys=True))]
314+
280315
def onHeaderContextMenu(self, point):
281316
index = self.packetlist.horizontalHeader().logicalIndexAt(point)
282317

@@ -289,13 +324,9 @@ def onHeaderContextMenu(self, point):
289324
addIdx = None if index == -1 else index
290325
ctx.addAction("Add Column ...", lambda: self.onAddColumn(addIdx))
291326

292-
elements = [("${\"" + key + "\"}", "$" + key) for key in
293-
sorted(self.listObject.getAllKeys(metadataKeys=True, fieldKeys=False))]
294-
self._generateQuickAddMenu(ctx, "Quick Add Metadata Column", elements, addIdx)
327+
self._generateQuickAddMenu(ctx, "Quick Add Metadata Column", self._getQuickAddMetadataElements(), addIdx)
295328

296-
elements = [("fields[\""+key+"\"]", key) for key in
297-
sorted(self.listObject.getAllKeys(metadataKeys=False, fieldKeys=True))]
298-
self._generateQuickAddMenu(ctx, "Quick Add Field Column", elements, addIdx)
329+
self._generateQuickAddMenu(ctx, "Quick Add Field Column", self._getQuickAddFieldElements(), addIdx)
299330

300331
ctx.addSeparator()
301332
magic = "!!pre_workbench/packetListHeaderState\n"

pre_workbench/icons/flag.png

728 Bytes
Loading
1.34 KB
Loading
1.32 KB
Loading
1.32 KB
Loading
1.24 KB
Loading

pre_workbench/windows/content/objectwindow.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,34 +74,36 @@ def _initUI(self, collapseSettings):
7474
#tb.addItem(self.sourceConfig, "Data Source Options")
7575
#layout.addWidget(ExpandWidget("Data Source Options", self.sourceConfig, collapseSettings))
7676

77-
toolbar = QToolBar()
78-
dsoVisAction = toolbar.addAction(getIcon("gear--pencil.png"), "Data Source Options")
77+
self.toolbar = QToolBar()
78+
dsoVisAction = self.toolbar.addAction(getIcon("gear--pencil.png"), "Data Source Options")
7979
dsoVisAction.setCheckable(True); dsoVisAction.setChecked(not collapseSettings)
8080
dsoVisAction.toggled.connect(lambda val: self.sourceConfig.setVisible(val))
81-
metadataVisAction = toolbar.addAction(getIcon("tags-label.png"), "Metadata")
81+
metadataVisAction = self.toolbar.addAction(getIcon("tags-label.png"), "Metadata")
8282
metadataVisAction.setCheckable(True)
83-
toolbar.addSeparator()
83+
self.toolbar.addSeparator()
8484

8585
self.reloadAction = QAction(getIcon("arrow-circle-double.png"), "Load Data")
8686
reloadButton = QToolButton()
8787
reloadButton.setDefaultAction(self.reloadAction)
8888
reloadButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
89-
toolbar.addWidget(reloadButton)
89+
self.toolbar.addWidget(reloadButton)
9090
self.reloadAction.triggered.connect(self.reload)
91-
self.cancelAction = toolbar.addAction(getIcon("control-stop-square.png"), "Cancel")
91+
self.cancelAction = self.toolbar.addAction(getIcon("control-stop-square.png"), "Cancel")
9292
self.cancelAction.triggered.connect(self.onCancelFetch)
9393
self.cancelAction.setEnabled(False)
94-
exportAction = toolbar.addAction(getIcon("document-export.png"), "Export")
94+
exportAction = self.toolbar.addAction(getIcon("document-export.png"), "Export")
9595
exportAction.triggered.connect(self.exportInTab)
96-
# macroMenu = toolbar.addAction(getIcon("scripts.png"), "Run Macro On Object")
96+
self.childActions = []
97+
self.toolbar.addSeparator()
98+
# macroMenu = self.toolbar.addAction(getIcon("scripts.png"), "Run Macro On Object")
9799
# self.macroMenu = QMenu(self)
98100
# macroMenu.setMenu(self.macroMenu)
99101
# self.macroMenu.aboutToShow.connect(self._fillMacroMenu)
100-
layout.addWidget(toolbar)
102+
layout.addWidget(self.toolbar)
101103
layout.addWidget(self.sourceConfig)
102104

103105
self.dataDisplay = DynamicDataWidget()
104-
self.dataDisplay.meta_updated.connect(self.meta_updated.emit)
106+
self.dataDisplay.meta_updated.connect(self._forwardMetaUpdate)
105107
metadataVisAction.toggled.connect(self.dataDisplay.setMetadataVisible)
106108
#tb.addItem(self.dataDisplay, "Results")
107109
#layout.addWidget(ExpandWidget("Results", self.dataDisplay))
@@ -175,6 +177,11 @@ def reloadFile(self): # action Ctrl-R
175177
def reload(self):
176178
try:
177179
self.cancelAction.setEnabled(True)
180+
181+
for old in self.childActions:
182+
self.toolbar.removeAction(old)
183+
self.childActions = []
184+
178185
clz = self._getDatasource(self.params["dataSourceType"])
179186
self.dataSource = clz(self.params)
180187
self.dataSource.on_finished.connect(self.onFinished)
@@ -192,3 +199,12 @@ def childActionProxy(self):
192199
def exportInTab(self):
193200
pass
194201

202+
def _forwardMetaUpdate(self, name, value):
203+
if name == 'actions':
204+
for old in self.childActions:
205+
self.toolbar.removeAction(old)
206+
self.childActions = value
207+
for new in self.childActions:
208+
self.toolbar.addAction(new)
209+
210+
self.meta_updated.emit(name, value)

0 commit comments

Comments
 (0)