55from PyQt6 .QtCore import Qt , pyqtSlot
66from PyQt6 .QtGui import QTextCursor , QAction , QCursor
77from PyQt6 .QtWidgets import QTextEdit , QApplication , QWidget , QVBoxLayout , QSlider , QLabel , QHBoxLayout , QListWidget , \
8- QPushButton , QMenu
8+ QPushButton , QMenu , QCheckBox , QWidgetAction
99
1010import globvar
1111
@@ -336,9 +336,35 @@ def __init__(self, text):
336336
337337# Custom TextEdit class for NewWatchWidget
338338class CustomTextEdit (QTextEdit ):
339+ def __init__ (self , parent = None ):
340+ super (CustomTextEdit , self ).__init__ (parent )
341+ self .key = None
342+ self .args_index = None
343+ self .addr = None
344+ self .checkedStates = {}
345+
346+ def closeEvent (self , e : QtGui .QCloseEvent ) -> None :
347+ self .checkedStates .clear ()
348+
349+ def get_args_index_and_addr_from_selected_text (self ):
350+ # Get the currently selected text
351+ tc = self .textCursor ()
352+ selected_text = self .textCursor ().selectedText ()
353+ if ":" in selected_text :
354+ self .args_index = selected_text [4 :selected_text .index (":" )]
355+ else :
356+ self .args_index = selected_text [4 :]
357+
358+ while True :
359+ tc .movePosition (QTextCursor .MoveOperation .Up , QTextCursor .MoveMode .MoveAnchor )
360+ if re .search (r"] 0x[a-f0-9]+" , tc .block ().text ()):
361+ self .addr = tc .block ().text ()[4 :].strip ()
362+ break
363+
339364 def contextMenuEvent (self , e : QtGui .QContextMenuEvent ) -> None :
340365 menu = super (CustomTextEdit , self ).createStandardContextMenu () # Get the default context menu
341366 select_all_action = None
367+ self .get_args_index_and_addr_from_selected_text ()
342368
343369 for action in menu .actions (): # loop over the existing actions
344370 if action .text () == "Select All" :
@@ -349,6 +375,21 @@ def contextMenuEvent(self, e: QtGui.QContextMenuEvent) -> None:
349375 args_regx = re .compile (r'(\bargs\d+\b|\breturn\b)' )
350376 match = args_regx .match (self .textCursor ().selectedText ())
351377
378+ on_leave_check = QCheckBox ("OnLeave" , self )
379+ if match is not None :
380+ self .key = (self .addr , self .args_index ) # Use a tuple as the key
381+ # If the key is not in the checkedStates dictionary, add it with a default state of unchecked
382+ if self .key not in self .checkedStates :
383+ self .checkedStates [self .key ] = Qt .CheckState .Unchecked
384+ # Set the checked state based on the checkedStates dictionary
385+ on_leave_check .setCheckState (Qt .CheckState (self .checkedStates [self .key ]))
386+ # Connect the checkbox's stateChanged signal to a function
387+ on_leave_check .stateChanged .connect (lambda state : self .on_leave_check_state_changed (state , self .key ))
388+
389+ check_action = QWidgetAction (self )
390+ check_action .setDefaultWidget (on_leave_check )
391+ menu .insertAction (select_all_action , check_action )
392+
352393 read_pointer_action = QAction ("readPointer" , self )
353394 if match is not None :
354395 read_pointer_action .setEnabled (True )
@@ -394,6 +435,11 @@ def contextMenuEvent(self, e: QtGui.QContextMenuEvent) -> None:
394435 # Show the context menu.
395436 menu .exec (e .globalPos ())
396437
438+ # handle the checkbox state change
439+ def on_leave_check_state_changed (self , state , key ):
440+ # Update the checked state in the checkedStates dictionary
441+ self .checkedStates [key ] = state
442+
397443 def read_pointer (self ):
398444 self .read_args_with_options ("readPointer" )
399445
@@ -416,18 +462,12 @@ def reset(self):
416462 self .read_args_with_options ("" )
417463
418464 def read_args_with_options (self , option ):
419- tc = self .textCursor ()
420- args_index = self .textCursor ().selectedText ()[4 :]
421- while True :
422- tc .movePosition (QTextCursor .MoveOperation .Up , QTextCursor .MoveMode .MoveAnchor )
423- if re .search (r"] 0x[a-f0-9]+" , tc .block ().text ()):
424- addr = tc .block ().text ()[4 :].strip ()
425- break
426465 try :
427466 if self .textCursor ().selectedText () == "return" :
428- globvar .fridaInstrument .set_read_retval_options (addr , option )
467+ globvar .fridaInstrument .set_read_retval_options (self . addr , option )
429468 else :
430- globvar .fridaInstrument .set_read_args_options (addr , args_index , option )
469+ globvar .fridaInstrument .set_read_args_options (self .addr , self .args_index , option ,
470+ self .checkedStates [self .key ])
431471 except Exception as e :
432472 print (f"{ inspect .currentframe ().f_code .co_name } : { e } " )
433473 return
@@ -470,6 +510,7 @@ def __init__(self):
470510
471511 def closeEvent (self , e : QtGui .QCloseEvent ) -> None :
472512 self .text_edit .clear ()
513+ self .text_edit .closeEvent (e )
473514 self .watch_list .clear ()
474515 try :
475516 globvar .fridaInstrument .detach_all ()
0 commit comments