Files
idapython-src/pywraps/py_kernwin_choose.py
Elias Bachaalany 44d7546da9 Update py_kernwin_choose.py
minor mods
2023-03-21 21:50:24 -07:00

449 lines
14 KiB
Python

#--------------------------------------------------------------------------
#<pycode(py_kernwin_choose)>
import _ida_kernwin
class Choose(object):
"""
Chooser wrapper class.
Some constants are defined in this class.
Please refer to kernwin.hpp for more information.
"""
CH_MODAL = _ida_kernwin.CH_MODAL
"""Modal chooser"""
CH_MULTI = _ida_kernwin.CH_MULTI
"""
Allow multi selection.
Refer the description of the OnInsertLine(), OnDeleteLine(),
OnEditLine(), OnSelectLine(), OnRefresh(), OnSelectionChange() to
see a difference between single and multi selection callbacks.
"""
CH_NOBTNS = _ida_kernwin.CH_NOBTNS
CH_ATTRS = _ida_kernwin.CH_ATTRS
CH_NOIDB = _ida_kernwin.CH_NOIDB
"""use the chooser even without an open database, same as x0=-2"""
CH_FORCE_DEFAULT = _ida_kernwin.CH_FORCE_DEFAULT
"""
If a non-modal chooser was already open, change selection to the given
default one
"""
CH_CAN_INS = _ida_kernwin.CH_CAN_INS
"""allow to insert new items"""
CH_CAN_DEL = _ida_kernwin.CH_CAN_DEL
"""allow to delete existing item(s)"""
CH_CAN_EDIT = _ida_kernwin.CH_CAN_EDIT
"""allow to edit existing item(s)"""
CH_CAN_REFRESH = _ida_kernwin.CH_CAN_REFRESH
"""allow to refresh chooser"""
CH_QFLT = _ida_kernwin.CH_QFLT
"""open with quick filter enabled and focused"""
CH_QFTYP_SHIFT = _ida_kernwin.CH_QFTYP_SHIFT
CH_QFTYP_DEFAULT = _ida_kernwin.CH_QFTYP_DEFAULT
CH_QFTYP_NORMAL = _ida_kernwin.CH_QFTYP_NORMAL
CH_QFTYP_WHOLE_WORDS = _ida_kernwin.CH_QFTYP_WHOLE_WORDS
CH_QFTYP_REGEX = _ida_kernwin.CH_QFTYP_REGEX
CH_QFTYP_FUZZY = _ida_kernwin.CH_QFTYP_FUZZY
CH_QFTYP_MASK = _ida_kernwin.CH_QFTYP_MASK
CH_NO_STATUS_BAR = _ida_kernwin.CH_NO_STATUS_BAR
"""don't show a status bar"""
CH_RESTORE = _ida_kernwin.CH_RESTORE
"""restore floating position if present (equivalent of WOPN_RESTORE) (GUI version only)"""
CH_RENAME_IS_EDIT = _ida_kernwin.CH_RENAME_IS_EDIT
"""triggering a 'edit/rename' (i.e., F2 shortcut) on a cell,
should call the edit() callback for the corresponding row."""
CH_BUILTIN_SHIFT = _ida_kernwin.CH_BUILTIN_SHIFT
CH_BUILTIN_MASK = _ida_kernwin.CH_BUILTIN_MASK
"""The chooser can provide a dirtree_t, meaning a tree-like structure
can be provided to the user (instead of a flat table)"""
CH_HAS_DIRTREE = _ida_kernwin.CH_HAS_DIRTREE
"""The chooser can be used in a diffing/merging workflow"""
CH_HAS_DIFF = _ida_kernwin.CH_HAS_DIFF
# column flags (are specified in the widths array)
CHCOL_PLAIN = _ida_kernwin.CHCOL_PLAIN
CHCOL_PATH = _ida_kernwin.CHCOL_PATH
CHCOL_HEX = _ida_kernwin.CHCOL_HEX
CHCOL_DEC = _ida_kernwin.CHCOL_DEC
CHCOL_EA = _ida_kernwin.CHCOL_EA
CHCOL_FNAME = _ida_kernwin.CHCOL_FNAME
CHCOL_FORMAT = _ida_kernwin.CHCOL_FORMAT
CHCOL_DEFHIDDEN = _ida_kernwin.CHCOL_DEFHIDDEN
CHCOL_DRAGHINT = _ida_kernwin.CHCOL_DRAGHINT
CHCOL_INODENAME = _ida_kernwin.CHCOL_INODENAME
# special values of the chooser index
NO_SELECTION = -1
"""there is no selected item"""
EMPTY_CHOOSER = -2
"""the chooser is initialized"""
ALREADY_EXISTS = -3
"""the non-modal chooser with the same data is already open"""
NO_ATTR = -4
"""some mandatory attribute is missing"""
# return value of ins(), del(), edit(), enter(), refresh() callbacks
NOTHING_CHANGED = 0
ALL_CHANGED = 1
SELECTION_CHANGED = 2
class UI_Hooks_Trampoline(UI_Hooks):
def __init__(self, v):
UI_Hooks.__init__(self)
self.hook()
import weakref
self.v = weakref.ref(v)
def populating_widget_popup(self, widget, popup_handle):
chooser = self.v()
if widget == chooser.GetWidget() and \
hasattr(chooser, "OnPopup") and \
callable(getattr(chooser, "OnPopup")):
chooser.OnPopup(widget, popup_handle)
def __init__(self, title, cols, flags = 0, popup_names = None,
icon=-1, x1=-1, y1=-1, x2=-1, y2=-1,
deflt = None,
embedded = False, width = None, height = None,
forbidden_cb = 0, flags2 = 0):
"""
Constructs a chooser window.
@param title: The chooser title
@param cols: a list of colums; each list item is a list of two items
example: [ ["Address", 10 | Choose.CHCOL_HEX],
["Name", 30 | Choose.CHCOL_PLAIN] ]
@param flags: One of CH_XXXX constants
@param flags2: One of CH2_XXXX constants
@param deflt: The index of the default item (0-based) for single
selection choosers or the list of indexes for multi selection
chooser
@param popup_names: List of new captions to replace this list
["Insert", "Delete", "Edit", "Refresh"]
@param icon: Icon index (the icon should exist in ida resources or
an index to a custom loaded icon)
@param x1, y1, x2, y2: The default location (for txt-version)
@param embedded: Create as embedded chooser
@param width: Embedded chooser width
@param height: Embedded chooser height
@param forbidden_cb: Explicitly forbidden callbacks
"""
self.title = title
self.flags = flags
self.flags2 = flags2
self.cols = cols
if deflt == None:
deflt = 0 if (flags & Choose.CH_MULTI) == 0 else [0]
self.deflt = deflt
self.popup_names = popup_names
self.icon = icon
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.embedded = embedded
self.width = width
self.height = height
self.forbidden_cb = forbidden_cb
self.ui_hooks_trampoline = None # set on Show
def _qccb(ctx, cmd_id):
for idx in ctx.chooser_selection:
self.OnCommand(idx, cmd_id)
self._quick_commands = quick_widget_commands_t(_qccb)
def Embedded(self, create_chobj=False):
"""
Creates an embedded chooser (as opposed to Show())
@return: Returns 0 on success or NO_ATTR
"""
if not self.embedded:
return Choose.NO_ATTR
if create_chobj:
return _ida_kernwin.choose_create_embedded_chobj(self)
else:
return _ida_kernwin.choose_choose(self)
def GetEmbSelection(self):
"""
Deprecated. For embedded choosers, the selection is
available through 'Form.EmbeddedChooserControl.selection'
"""
return None
def Show(self, modal=False):
"""
Activates or creates a chooser window
@param modal: Display as modal dialog
@return: For all choosers it will return NO_ATTR if some mandatory
attribute is missing. The mandatory attributes are: flags,
title, cols, OnGetSize(), OnGetLine();
For modal choosers it will return the selected item index (0-based),
or NO_SELECTION if no selection,
or EMPTY_CHOOSER if the OnRefresh() callback returns EMPTY_CHOOSER;
For non-modal choosers it will return 0
or ALREADY_EXISTS if the chooser was already open and is active now;
"""
if self.embedded:
return Choose.NO_ATTR
# it will be deleted and unhooked in py_choose_t::closed()
self.ui_hooks_trampoline = self.UI_Hooks_Trampoline(self)
if modal:
self.flags |= Choose.CH_MODAL
# Disable the timeout
with disabled_script_timeout_t():
n = _ida_kernwin.choose_choose(self)
# Delete the modal chooser instance
self.Close()
return n
else:
self.flags &= ~Choose.CH_MODAL
return _ida_kernwin.choose_choose(self)
def Activate(self):
"""Activates a visible chooser"""
return _ida_kernwin.choose_activate(self)
def Refresh(self):
"""Causes the refresh callback to trigger"""
return _ida_kernwin.choose_refresh(self)
def Close(self):
"""Closes the chooser"""
if not self.embedded:
_ida_kernwin.choose_close(self)
def GetWidget(self):
"""
Return the TWidget underlying this view.
@return: The TWidget underlying this view, or None.
"""
return _ida_kernwin.choose_get_widget(self)
def adjust_last_item(self, n):
"""
Helper for OnDeleteLine() and OnRefresh() callbacks.
They can be finished by the following line:
return [Choose.ALL_CHANGED] + self.adjust_last_item(n)
@param: line number of the remaining select item
@return: list of selected lines numbers (one element or empty)
"""
cnt = self.OnGetSize()
if cnt == 0:
return []
# take in account deleting of the last item(s)
if n >= cnt:
n = cnt - 1
return [n]
def AddCommand(self,
caption,
flags = _ida_kernwin.CHOOSER_POPUP_MENU,
menu_index = -1,
icon = -1,
emb=None,
shortcut=None):
return self._quick_commands.add(
caption=caption,
flags=flags,
menu_index=menu_index,
icon=icon,
emb=emb,
shortcut=shortcut)
def OnPopup(self, widget, popup_handle):
self._quick_commands.populate_popup(widget, popup_handle)
def OnInit(self):
"""
Initialize the chooser and populate it.
This callback is optional
"""
pass
def OnGetSize(self):
"""
Get the number of elements in the chooser.
This callback is mandatory
@return the number of elements
"""
pass
def OnGetLine(self, n):
"""
Get data for an element
This callback is mandatory
@param n the index to fetch data for
@return a list of strings
"""
pass
def OnGetIcon(self, n):
"""
Get an icon to associate with the first cell of an element
@param n index of the element
@return an icon ID
"""
pass
def OnGetLineAttr(self, n):
"""
Get attributes for an element
@param n index of the element
@return a tuple (color, flags)
"""
pass
def OnInsertLine(self, sel):
"""
User asked to insert an element
@param sel the current selection
@return a tuple (changed, selection)
"""
pass
def OnDeleteLine(self, sel):
"""
User deleted an element
@param sel the current selection
@return a tuple (changed, selection)
"""
pass
def OnEditLine(self, sel):
"""
User asked to edit an element.
@param sel the current selection
@return a tuple (changed, selection)
"""
pass
def OnSelectLine(self, sel):
"""
User pressed the enter key, or double-clicked a selection
@param sel the current selection
@return a tuple (changed, selection)
"""
pass
def OnSelectionChange(self, sel):
"""
Selection changed
@param sel the new selection
"""
pass
def OnRefresh(self, sel):
"""
The chooser needs to be refreshed.
It returns the new positions of the selected items.
@param sel the current selection
@return a tuple (changed, selection)
"""
pass
def OnClose(self):
"""
The chooser window is closed.
"""
pass
def OnGetEA(self, n):
"""
Get the address of an element
When this function returns valid addresses:
* If any column has the `CHCOL_FNAME` flag, rows will
be colored according to the attributes of the functions
who own those addresses (extern, library function,
Lumina, ... - similar to what the "Functions" widget does)
* When a selection is present and the user presses `<Enter>`
(`<Shift+Enter>` if the chooser is modal), IDA will jump
to that address (through jumpto())
@param n element number (0-based)
@return the effective address, ida_idaapi.BADADDR if the element has no address
"""
pass
def OnGetDirTree(self):
"""
Get the dirtree_t that will be used to present a tree-like
structure to the user (see CH_HAS_DIRTREE)
@return the dirtree_t, or None
"""
pass
def OnIndexToInode(self, n):
"""
Map an element index to a dirtree_t inode
This callback is mandatory if CH_HAS_DIRTREE is specified
@param n index of the element
@return the inode number
"""
pass
def OnIndexToDiffpos(self, n):
"""
Map an element index to a diffpos_t
This callback is mandatory if CH_HAS_DIFF is specified
@param n index of the element
@return the diffpos
"""
pass
def OnLazyLoadDir(self, path):
"""
Callback for lazy-loaded, dirtree-based choosers;
the function will be called when a folder is expanded and it has
not been loaded before. The implementation should use the
given dirtree's link() or mkdir() methods to add the folder contents.
@param path an absolute dirtree path to the directory that is being expanded
@return success
"""
pass
#</pycode(py_kernwin_choose)>