示例#1
0
class SpecifySearchConditionsDialog(BaseDialog):
    def __init__(self, parent, entity):
        super().__init__(parent, _("Search criteria"), _("&Start search"),
                         _("&Cancel"))
        self._entity = entity
        self._value_widget = None
        self._value_label = None
        self._search_expression_parts = []
        self._added_condition = False
        self._populate_fields_tree(self._entity)

    def create_ui(self):
        fields_label = QLabel(_("Class fields"), self)
        self.layout.addWidget(fields_label, 0, 0)
        self._fields_tree = QTreeWidget(self)
        fields_label.setBuddy(self._fields_tree)
        self._fields_tree.currentItemChanged.connect(
            self.on_fields_tree_sel_changed)
        self.layout.addWidget(self._fields_tree, 1, 0)
        operator_label = QLabel(_("Operator"), self)
        self.layout.addWidget(operator_label, 0, 1)
        self._operator = QListWidget(self)
        operator_label.setBuddy(self._operator)
        self.layout.addWidget(self._operator, 1, 1)
        self._operator.currentRowChanged.connect(self.on_operator_choice)
        self._operator.setCurrentRow(0)
        add_button = QPushButton(_("&Add condition"), self)
        add_button.clicked.connect(self.on_add_clicked)
        self.layout.addWidget(add_button, 2, 0, 1, 3)
        criteria_label = QLabel(_("Current search criteria"), self)
        self.layout.addWidget(criteria_label, 3, 0, 1, 3)
        self._criteria_list = QListWidget(self)
        criteria_label.setBuddy(self._criteria_list)
        self.layout.addWidget(self._criteria_list, 4, 0, 1, 3)
        remove_button = QPushButton(_("&Remove condition"), self)
        remove_button.clicked.connect(self.on_remove_clicked)
        self.layout.addWidget(remove_button, 5, 0, 1, 3)
        distance_label = QLabel(_("Search objects to distance"), self)
        self.layout.addWidget(distance_label, 6, 0)
        self._distance_field = QSpinBox(self)
        self._distance_field.setMaximum(100000)
        self._distance_field.setSuffix(" " + _("meters"))
        self._distance_field.setSpecialValueText(_("No limit"))
        distance_label.setBuddy(self._distance_field)
        self.layout.addWidget(self._distance_field, 6, 1)

    def _populate_fields_tree(self, entity, parent=None):
        if parent is None:
            parent = self._fields_tree.invisibleRootItem()
        metadata = EntityMetadata.for_discriminator(entity)
        for field_name, field in sorted(
                metadata.all_fields.items(),
                key=lambda i: underscored_to_words(i[0])):
            child_metadata = None
            try:
                child_metadata = EntityMetadata.for_discriminator(
                    field.type_name)
            except KeyError:
                pass
            if child_metadata:
                name = get_class_display_name(field.type_name)
                subparent = QTreeWidgetItem([name])
                subparent.setData(0, Qt.UserRole, field_name)
                parent.addChild(subparent)
                self._populate_fields_tree(field.type_name, subparent)
            else:
                item = QTreeWidgetItem([underscored_to_words(field_name)])
                item.setData(0, Qt.UserRole, (field_name, field))
                parent.addChild(item)

    def on_fields_tree_sel_changed(self, item):
        data = item.data(0, Qt.UserRole)
        if data is not None and not isinstance(data, str):
            self._field_name = data[0]
            self._field = data[1]
            self._operators = operators_for_column_class(self._field.type_name)
            self._operator.clear()
            self._operator.addItems([o.label for o in self._operators])
            self._added_condition = False

    def on_operator_choice(self, index):
        self._added_condition = False
        if self._value_widget:
            self.layout.removeWidget(self._value_widget)
            self._value_widget.deleteLater()
        if self._value_label:
            self.layout.removeWidget(self._value_label)
            self._value_label.deleteLater()
            self._value_label = None
        operator = self._operators[self._operator.currentRow()]
        value_label = self._create_value_label(
            operator.get_value_label(self._field))
        self._value_widget = operator.get_value_widget(self, self._field)
        if not self._value_widget:
            return
        QWidget.setTabOrder(self._operator, self._value_widget)
        self._value_label = value_label
        if self._value_label:
            self._value_label.setBuddy(self._value_widget)
            self.layout.addWidget(self._value_label, 0, 2)
        self.layout.addWidget(self._value_widget, 1, 2)

    def _create_value_label(self, label):
        if not label:
            return
        label = QLabel(label, self)
        return label

    def on_add_clicked(self, evt):
        if not hasattr(self, "_field_name"):
            return
        self._added_condition = True
        json_path = []
        parent_item = self._fields_tree.currentItem().parent()
        parent_data = parent_item.data(0, Qt.UserRole) if parent_item else None
        if isinstance(parent_data, str):
            json_path.append(parent_data)
        json_path.append(self._field_name)
        json_path = ".".join(json_path)
        operator_obj = self._operators[self._operator.currentRow()]
        expression = operator_obj.get_comparison_expression(
            self._field, FieldNamed(json_path), self._value_widget)
        self._search_expression_parts.append(expression)
        self._criteria_list.addItem(
            f"{underscored_to_words(self._field_name)} {operator_obj.label} {operator_obj.get_value_as_string(self._field, self._value_widget)}"
        )

    @property
    def distance(self):
        return self._distance_field.value()

    def create_conditions(self):
        conditions = []
        if self._search_expression_parts:
            for part in self._search_expression_parts:
                conditions.append(part)
        return conditions

    def on_remove_clicked(self, evt):
        selection = self._criteria_list.currentRow()
        if selection < 0:
            return
        del self._search_expression_parts[selection]
        self._criteria_list.removeItemWidget(self._criteria_list.currentItem())

    def ok_clicked(self):
        if not self._added_condition:
            if QMessageBox.question(
                    self, _("Question"),
                    _("It appears that you forgot to add the current condition to the conditions list. Do you want to add it before starting the search?"
                      )):
                self.on_add_clicked(None)
        super().ok_clicked()
示例#2
0
class MemTree(QWidget):
    def __init__(self, qmp, parent):
        super().__init__()
        self.qmp = qmp
        self.qmp.memoryMap.connect(self.update_tree)

        self.parent = parent

        self.tree_sem = QSemaphore(1)
        self.sending_sem = QSemaphore(
            1)  # used to prevent sending too many requests at once

        self.init_ui()
        self.get_map()

    def init_ui(self):

        self.vbox = QVBoxLayout()

        self.refresh = QPushButton('Refresh')
        self.refresh.clicked.connect(lambda: self.get_map())
        self.vbox.addWidget(self.refresh)

        self.tree = QTreeWidget()
        self.tree.itemDoubleClicked.connect(self.open_region)
        self.tree.setColumnCount(3)
        self.tree.header().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.tree.header().setStretchLastSection(False)
        self.tree.setHeaderLabels(
            ['Memory Region', 'Start Address', 'End Address'])
        self.vbox.addWidget(self.tree)

        self.setLayout(self.vbox)
        self.setGeometry(100, 100, 500, 300)
        self.setWindowTitle("Memory Tree")
        self.show()

    def get_map(self):
        self.tree.clear()
        self.qmp.command('mtree')

    # finds item with name 'name' in self.tree
    # self.tree_sem must be acquired before use
    def find(self, name, node):
        if node.text(0) == name:
            return node
        else:
            for i in range(node.childCount()):
                result = self.find(name, node.child(i))
                if result:
                    return result
            return None

    def update_tree(self, value):
        if value != None:
            self.tree_sem.acquire()
            current_addr_space = ''

            for region in value:
                parent_node = self.tree
                parent = region['parent']

                if parent != '':
                    root = self.tree.invisibleRootItem()
                    for i in range(root.childCount()):
                        if root.child(i).text(0) == current_addr_space:
                            root = root.child(i)
                            break
                    parent_node = self.find(parent, root)
                else:
                    current_addr_space = region['name']

                node = QTreeWidgetItem(parent_node)
                node.setText(0, region['name'])
                start = region['start']
                end = region['end']
                if start < 0:
                    start = start + (1 << constants['bits'])
                if end < 0:
                    end = end + (1 << constants['bits'])
                node.setText(1, f'{start:016x}')
                node.setText(2, f'{end:016x}')
                node.setFont(0, QFont('Courier New'))
                node.setFont(1, QFont('Courier New'))
                node.setFont(2, QFont('Courier New'))

            self.tree_sem.release()

    def open_region(self, node, col):
        self.parent.open_new_window(
            MemDumpWindow(self.qmp,
                          base=int(node.text(1), 16),
                          max=int(node.text(2), 16)))