Exemplo n.º 1
0
class JavaExplorerPanel(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)

        self._app_window = parent

        self._handle_history = []

        self._setup_ui()
        self._setup_models()

    def _setup_ui(self):
        self.setContentsMargins(0, 0, 0, 0)

        top_font = QFont()
        top_font.setBold(True)
        top_font.setPixelSize(19)

        # main wrapper
        main_wrapper = QVBoxLayout()
        main_wrapper.setContentsMargins(1, 1, 1, 1)

        # wrapwdgt
        wrap_wdgt = QWidget()
        self._top_class_name = QLabel(wrap_wdgt)
        self._top_class_name.setContentsMargins(10, 10, 10, 10)
        self._top_class_name.setAttribute(Qt.WA_TranslucentBackground,
                                          True)  # keep this
        self._top_class_name.setFont(top_font)
        self._top_class_name.setStyleSheet('color: #ef5350;')
        wrap_wdgt.setMaximumHeight(self._top_class_name.height() + 20)

        main_wrapper.addWidget(wrap_wdgt)

        # left list
        left_wrap_wdgt = QWidget()

        left_v_box = QVBoxLayout(left_wrap_wdgt)
        left_v_box.setContentsMargins(0, 0, 0, 0)

        methods_label = QLabel('METHODS')
        font = methods_label.font()
        font.setBold(True)
        methods_label.setFont(font)
        methods_label.setContentsMargins(10, 0, 10, 2)
        methods_label.setAttribute(Qt.WA_TranslucentBackground,
                                   True)  # keep this
        left_v_box.addWidget(methods_label)

        self._methods_list = DwarfListView()
        left_v_box.addWidget(self._methods_list)

        # center list
        center_wrap_wdgt = QWidget()

        center_v_box = QVBoxLayout(center_wrap_wdgt)
        center_v_box.setContentsMargins(0, 0, 0, 0)

        methods_label = QLabel('NATIVE FIELDS')
        methods_label.setFont(font)
        methods_label.setContentsMargins(10, 0, 10, 2)
        methods_label.setAttribute(Qt.WA_TranslucentBackground,
                                   True)  # keep this
        center_v_box.addWidget(methods_label)

        self._native_fields_list = DwarfListView()
        self._native_fields_list.doubleClicked.connect(
            self._on_native_field_dblclicked)
        center_v_box.addWidget(self._native_fields_list)

        # right list
        right_wrap_wdgt = QWidget()

        right_v_box = QVBoxLayout(right_wrap_wdgt)
        right_v_box.setContentsMargins(0, 0, 0, 0)

        methods_label = QLabel('FIELDS')
        methods_label.setFont(font)
        methods_label.setContentsMargins(10, 0, 10, 2)
        methods_label.setAttribute(Qt.WA_TranslucentBackground,
                                   True)  # keep this
        right_v_box.addWidget(methods_label)

        self._fields_list = DwarfListView()
        self._fields_list.doubleClicked.connect(self._on_field_dblclicked)
        right_v_box.addWidget(self._fields_list)

        # main splitter
        main_splitter = QSplitter(Qt.Horizontal)
        main_splitter.setContentsMargins(0, 0, 0, 0)
        main_splitter.addWidget(left_wrap_wdgt)
        main_splitter.addWidget(center_wrap_wdgt)
        main_splitter.addWidget(right_wrap_wdgt)
        main_splitter.setSizes([250, 100, 100])

        main_wrapper.addWidget(main_splitter)
        main_wrapper.setSpacing(0)
        self.setLayout(main_wrapper)

    def _setup_models(self):
        # left list
        self._methods_model = QStandardItemModel(0, 3)
        self._methods_model.setHeaderData(0, Qt.Horizontal, 'Name')
        self._methods_model.setHeaderData(1, Qt.Horizontal, 'Return')
        self._methods_model.setHeaderData(2, Qt.Horizontal, 'Arguments')
        self._methods_list.setModel(self._methods_model)
        self._methods_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self._methods_list.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        # center list
        self._native_fields_model = QStandardItemModel(0, 2)
        self._native_fields_model.setHeaderData(0, Qt.Horizontal, 'Name')
        self._native_fields_model.setHeaderData(1, Qt.Horizontal, 'Value')
        self._native_fields_list.setModel(self._native_fields_model)
        self._native_fields_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        # right list
        self._fields_model = QStandardItemModel(0, 2)
        self._fields_model.setHeaderData(0, Qt.Horizontal, 'Name')
        self._fields_model.setHeaderData(1, Qt.Horizontal, 'Class')
        self._fields_list.setModel(self._fields_model)
        self._fields_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def _set_data(self, data):
        if 'class' not in data:
            return

        self._top_class_name.setText(data['class'])
        data = data['data']

        self._methods_list.clear()
        self._native_fields_list.clear()
        self._fields_list.clear()

        for key in data:
            ref = data[key]
            if ref['type'] == 'function':
                if not key.startswith('$'):
                    self._add_method(key, ref)
            elif ref['type'] == 'object':
                if ref['handle'] is not None:
                    if not key.startswith('$'):
                        self._add_field(key, ref['value'], ref['handle'],
                                        ref['handle_class'])
            else:
                if not key.startswith('$'):
                    self._add_field(key, ref['value'], is_native=True)

        self._methods_list.sortByColumn(0, 0)
        self._native_fields_list.sortByColumn(0, 0)
        self._fields_list.sortByColumn(0, 0)

    def _add_method(self, name, ref):
        ref_overloads = ref['overloads']
        for _, ref_overload in enumerate(ref_overloads):
            args = []

            if 'args' in ref_overload:
                for arg in ref_overload['args']:
                    if 'className' in arg:
                        args.append(arg['className'])

            self._methods_model.appendRow([
                QStandardItem(name),
                QStandardItem(ref_overload['return']['className']),
                QStandardItem('(%s)' % ', '.join(args)),
            ])

    def _add_field(self,
                   name,
                   value,
                   handle=None,
                   handle_class=None,
                   is_native=False):
        if handle:
            handle = {'handle': handle, 'handle_class': handle_class}
            handle_item = QStandardItem(name)
            handle_item.setData(handle, Qt.UserRole + 1)
        else:
            handle_item = QStandardItem(name)

        if not is_native:
            self._fields_model.appendRow(
                [handle_item, QStandardItem(str(value))])
        else:
            self._native_fields_model.appendRow(
                [handle_item, QStandardItem(str(value))])

    def _set_handle(self, handle):
        data = self._app_window.dwarf.dwarf_api('javaExplorer', handle)
        if not data:
            return
        self._handle_history.append({'handle': handle})
        self._set_data(data)

    def _set_handle_arg(self, arg):
        data = self._app_window.dwarf.dwarf_api('javaExplorer', arg)
        if not data:
            return
        self._handle_history.append({'handle': arg})
        self._set_data(data)

    def clear_panel(self):
        self._top_class_name.setText('')
        self._handle_history = []
        self._methods_list.clear()
        self._native_fields_list.clear()
        self._fields_list.clear()

    def _back(self):
        if len(self._handle_history) < 2:
            return
        self._handle_history.pop()
        data = self._handle_history.pop(len(self._handle_history) -
                                        1)['handle']
        if isinstance(data, int):
            self._set_handle_arg(data)
        else:
            self._set_handle(data)

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_field_dblclicked(self, _):
        field_row = self._fields_list.selectionModel().currentIndex().row()
        if field_row >= 0:
            field_handle = self._fields_model.item(field_row,
                                                   0).data(Qt.UserRole + 1)
            if field_handle:
                self._set_handle(field_handle)

    def _on_native_field_dblclicked(self, _):
        field_row = self._native_fields_list.selectionModel().currentIndex(
        ).row()
        if field_row:
            field_handle = self._native_fields_model.item(
                field_row, 0).data(Qt.UserRole + 1)
            if field_handle:
                self._set_handle(field_handle)

    def keyPressEvent(self, event):  # pylint: disable=invalid-name
        if event.key() == Qt.Key_Backspace:
            self._back()

        return super().keyPressEvent(event)
Exemplo n.º 2
0
class JavaInspector(QWidget):
    """ Java Class/Methods Lists
    """
    def __init__(self, parent=None):
        super(JavaInspector, self).__init__(parent)

        self._app_window = parent

        self._app_window.dwarf.onEnumerateJavaMethodsComplete.connect(
            self._on_method_enumeration_complete)
        self._app_window.dwarf.onEnumerateJavaClassesStart.connect(
            self._on_class_enumeration_start)
        self._app_window.dwarf.onEnumerateJavaClassesMatch.connect(
            self._on_class_enumeration_match)
        self._app_window.dwarf.onEnumerateJavaClassesComplete.connect(
            self._on_class_enumeration_complete)

        self._java_classes = DwarfListView(self)
        self._javaclass_model = QStandardItemModel(0, 1)
        self._javaclass_model.setHeaderData(0, Qt.Horizontal, 'Class')
        self._java_classes.setModel(self._javaclass_model)
        self._java_classes.selectionModel().selectionChanged.connect(
            self._class_clicked)
        self._java_classes.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self._java_classes.setContextMenuPolicy(Qt.CustomContextMenu)
        self._java_classes.customContextMenuRequested.connect(
            self._on_class_contextmenu)
        self._java_classes.doubleClicked.connect(self._class_dblclicked)

        self._java_methods = DwarfListView(self)
        self._javamethod_model = QStandardItemModel(0, 1)
        self._javamethod_model.setHeaderData(0, Qt.Horizontal, 'Method')
        self._java_methods.setModel(self._javamethod_model)
        self._java_methods.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self._java_methods.setContextMenuPolicy(Qt.CustomContextMenu)
        self._java_methods.customContextMenuRequested.connect(
            self._on_method_contextmenu)
        self._java_methods.doubleClicked.connect(self._method_dblclicked)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(0, 0, 0, 0)
        h_box.addWidget(self._java_classes)
        h_box.addWidget(self._java_methods)
        self.setLayout(h_box)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def update_classes(self):
        """ Refresh Classeslist
        """
        self._app_window.dwarf.dwarf_api('enumerateJavaClasses')

    def update_methods(self, class_name):
        """ Refresh Methodslist
        """
        if class_name:
            self._app_window.dwarf.dwarf_api('enumerateJavaMethods',
                                             class_name)

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _class_clicked(self):
        index = self._java_classes.selectionModel().currentIndex().row()
        _class = self._javaclass_model.item(index, 0)
        if _class is None:
            return

        self._app_window.dwarf.dwarf_api('enumerateJavaMethods', _class.text())

    def _on_class_enumeration_start(self):
        self._java_classes.clear()

    def _on_class_enumeration_match(self, java_class):
        _class_name = QStandardItem()
        _class_name.setText(java_class)
        self._javaclass_model.appendRow(_class_name)

    def _on_class_enumeration_complete(self):
        self._java_classes.sortByColumn(0, 0)

    def _on_method_enumeration_complete(self, data):
        self._java_methods.clear()
        _class, methods = data
        for method in methods:
            _method_name = QStandardItem()
            _method_name.setText(method)
            self._javamethod_model.appendRow(_method_name)

    def _class_dblclicked(self):
        """ Class DoubleClicked
        """
        index = self._java_classes.selectionModel().currentIndex().row()
        if index:
            class_item = self._javaclass_model.item(index, 0)
            if class_item:
                class_name = class_item.text()
                if class_name:
                    self._hook_class(class_name)

    def _method_dblclicked(self):
        """ Function DoubleClicked
        """
        class_index = self._java_classes.selectionModel().currentIndex().row()
        method_index = self._java_methods.selectionModel().currentIndex().row()
        if class_index and method_index:
            class_item = self._javaclass_model.item(class_index, 0)
            method_item = self._javamethod_model.item(method_index, 0)
            if class_item and method_item:
                class_name = class_item.text()
                method_name = method_item.text()
                if class_name and method_name:
                    self._app_window.dwarf.hook_java(class_name + '.' +
                                                     method_name)

    def _hook_class(self, class_name):
        if class_name:
            self._app_window.dwarf.hook_java(class_name)

    def _hook_class_functions(self, class_name):
        if class_name:
            self._app_window.dwarf.dwarf_api('hookAllJavaMethods', class_name)

    def _on_class_contextmenu(self, pos):
        """ Modules ContextMenu
        """
        index = self._java_classes.indexAt(pos).row()
        glbl_pt = self._java_classes.mapToGlobal(pos)
        context_menu = QMenu(self)
        if index != -1:
            context_menu.addAction(
                'Hook constructor', lambda: self._hook_class(
                    self._javaclass_model.item(index, 0).text()))
            context_menu.addAction(
                'Hook all methods', lambda: self._hook_class_functions(
                    self._javaclass_model.item(index, 0).text()))
            context_menu.addSeparator()

        context_menu.addAction('Refresh', self.update_classes)
        context_menu.exec_(glbl_pt)

    def _hook_method(self, method_name):
        class_index = self._java_classes.selectionModel().currentIndex().row()
        if class_index:
            class_item = self._javaclass_model.item(class_index, 0)
            if class_item:
                class_name = class_item.text()
                if class_name and method_name:
                    self._app_window.dwarf.hook_java(class_name + '.' +
                                                     method_name)

    def _cm_refresh_methods(self):
        index = self._java_classes.selectionModel().currentIndex().row()
        _class = self._javaclass_model.item(index, 0)
        if _class is None:
            return

        self.update_methods(_class.text())

    def _on_method_contextmenu(self, pos):
        """ Modules ContextMenu
        """
        index = self._java_methods.indexAt(pos).row()
        glbl_pt = self._java_methods.mapToGlobal(pos)
        context_menu = QMenu(self)
        if index != -1:
            context_menu.addAction(
                'Hook method', lambda: self._hook_method(
                    self._javamethod_model.item(index, 0).text()))
            context_menu.addSeparator()

        context_menu.addAction('Refresh', self._cm_refresh_methods)
        context_menu.exec_(glbl_pt)