Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions capa/ida/plugin/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import capa.ida.helpers
from capa.features.address import Address, FileOffsetAddress, AbsoluteVirtualAddress
from capa.ida.plugin.qt_compat import QtCore, qt_get_item_flag_tristate
from capa.ida.plugin.qt_compat import QtCore, qt_get_item_flag_tristate, flag_val


def info_to_name(display):
Expand Down Expand Up @@ -52,10 +52,10 @@ def __init__(self, parent: Optional["CapaExplorerDataItem"], data: list[str], ca
self._can_check = can_check

# default state for item
self.flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
self.flags = flag_val(QtCore.Qt.ItemIsEnabled) | flag_val(QtCore.Qt.ItemIsSelectable)

if self._can_check:
self.flags = self.flags | QtCore.Qt.ItemIsUserCheckable | qt_get_item_flag_tristate()
self.flags = self.flags | flag_val(QtCore.Qt.ItemIsUserCheckable) | qt_get_item_flag_tristate()

if self.pred:
self.pred.appendChild(self)
Expand All @@ -66,9 +66,9 @@ def setIsEditable(self, isEditable=False):
@param isEditable: True, can edit, False cannot edit
"""
if isEditable:
self.flags |= QtCore.Qt.ItemIsEditable
self.flags |= flag_val(QtCore.Qt.ItemIsEditable)
else:
self.flags &= ~QtCore.Qt.ItemIsEditable
self.flags &= ~flag_val(QtCore.Qt.ItemIsEditable)

def setChecked(self, checked):
"""set item as checked
Expand Down
25 changes: 11 additions & 14 deletions capa/ida/plugin/qt_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
Qt = QtCore.Qt


def flag_val(flag):
if hasattr(flag, 'value'):
return flag.value
return flag


def qt_get_item_flag_tristate():
"""
Get the tristate item flag compatible with Qt5 and Qt6.
Expand All @@ -51,29 +57,20 @@ def qt_get_item_flag_tristate():
ItemIsAutoTristate automatically manages tristate based on child checkboxes,
matching the original ItemIsTristate behavior where parent checkboxes reflect
the check state of their children.

Returns:
int: The appropriate flag value for the Qt version

Raises:
AttributeError: If the tristate flag cannot be found in the Qt library
"""
def qt_get_item_flag_tristate():
if QT_LIBRARY == "PySide6":
# Qt6: ItemIsTristate was removed, replaced with ItemIsAutoTristate
# Try different possible locations (API varies slightly across PySide6 versions)
if hasattr(Qt, "ItemIsAutoTristate"):
return Qt.ItemIsAutoTristate
return flag_val(Qt.ItemIsAutoTristate)
elif hasattr(Qt, "ItemFlag") and hasattr(Qt.ItemFlag, "ItemIsAutoTristate"):
return Qt.ItemFlag.ItemIsAutoTristate
return flag_val(Qt.ItemFlag.ItemIsAutoTristate)
else:
raise AttributeError(
"Cannot find ItemIsAutoTristate in PySide6. "
+ "Your PySide6 version may be incompatible with capa. "
+ f"Available Qt attributes: {[attr for attr in dir(Qt) if 'Item' in attr]}"
)
else:
# Qt5: Use the original ItemIsTristate flag
return Qt.ItemIsTristate
return flag_val(Qt.ItemIsTristate)


__all__ = ["qt_get_item_flag_tristate", "Signal", "QAction", "QtGui", "QtCore", "QtWidgets"]
__all__ = ["flag_val", "qt_get_item_flag_tristate", "Signal", "QAction", "QtGui", "QtCore", "QtWidgets"]
12 changes: 6 additions & 6 deletions capa/ida/plugin/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from capa.ida.plugin.item import CapaExplorerFunctionItem
from capa.features.address import FileOffsetAddress, AbsoluteVirtualAddress, _NoAddress
from capa.ida.plugin.model import CapaExplorerDataModel
from capa.ida.plugin.qt_compat import QtGui, QtCore, Signal, QAction, QtWidgets
from capa.ida.plugin.qt_compat import QtGui, QtCore, Signal, QAction, QtWidgets, flag_val

MAX_SECTION_SIZE = 750

Expand Down Expand Up @@ -484,9 +484,9 @@ def slot_item_double_clicked(self, o, column):
CapaExplorerRulegenEditor.get_column_comment_index(),
CapaExplorerRulegenEditor.get_column_description_index(),
):
o.setFlags(o.flags() | QtCore.Qt.ItemIsEditable)
o.setFlags(int(o.flags()) | flag_val(QtCore.Qt.ItemIsEditable))
self.editItem(o, column)
o.setFlags(o.flags() & ~QtCore.Qt.ItemIsEditable)
o.setFlags(int(o.flags()) & ~flag_val(QtCore.Qt.ItemIsEditable))
self.is_editing = True

def update_preview(self):
Expand Down Expand Up @@ -601,13 +601,13 @@ def set_expression_node(self, o):
def set_feature_node(self, o):
""" """
setattr(o, "capa_type", CapaExplorerRulegenEditor.get_node_type_feature())
o.setFlags(o.flags() & ~QtCore.Qt.ItemIsDropEnabled)
o.setFlags(int(o.flags()) & ~flag_val(QtCore.Qt.ItemIsDropEnabled))
self.style_feature_node(o)

def set_comment_node(self, o):
""" """
setattr(o, "capa_type", CapaExplorerRulegenEditor.get_node_type_comment())
o.setFlags(o.flags() & ~QtCore.Qt.ItemIsDropEnabled)
o.setFlags(int(o.flags()) & ~flag_val(QtCore.Qt.ItemIsDropEnabled))

self.style_comment_node(o)

Expand Down Expand Up @@ -1009,7 +1009,7 @@ def style_leaf_node(self, o):

def set_parent_node(self, o):
""" """
o.setFlags(o.flags() & ~QtCore.Qt.ItemIsSelectable)
o.setFlags(int(o.flags()) & ~flag_val(QtCore.Qt.ItemIsSelectable))
setattr(o, "capa_type", CapaExplorerRulegenFeatures.get_node_type_parent())
self.style_parent_node(o)

Expand Down
Loading