示例#1
0
 def down_list(tree: QTreeWidget):
     selected = tree.currentItem()
     if selected:
         index = tree.indexOfTopLevelItem(selected)
         name = selected.text(0)
         desc = selected.text(1)
         data = selected.data(2, 2)
         new = QTreeWidgetItem([name, desc])
         new.setData(2, 2, data)
         tree.takeTopLevelItem(index)
         tree.insertTopLevelItem(index + 1, new)
         tree.setCurrentItem(new)
示例#2
0
class ObjectsBrowserWindow(QWidget):
    def __init__(self,
                 parent,
                 title,
                 person,
                 unsorted_objects,
                 autoshow=True,
                 progress_indicator=None):
        super().__init__(None)
        act = QAction("close", self)
        act.triggered.connect(self._do_close)
        act.setShortcut(QKeySequence("escape"))
        self.addAction(act)
        layout = QGridLayout()
        bar = QMenuBar(self)
        self._object_actions = bar.addMenu(_("Object actions"))
        property_actions = bar.addMenu(_("Property actions"))
        self._create_item(property_actions, _("Copy property value"), "ctrl+c",
                          self.on_copypropvalue_selected)
        self._create_item(property_actions, _("Copy property name"), "alt+c",
                          self.on_copypropname_selected)
        self._create_item(property_actions, _("Copy property name and value"),
                          "ctrl+alt+c", self.on_copypropline_selected)
        objects_label = QLabel(_("Objects"), self)
        layout.addWidget(objects_label, 0, 0)
        self._objects_list = QListWidget(self)
        self._objects_list.setAccessibleName(objects_label.text())
        self._objects_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._objects_list.currentRowChanged.connect(self.on_objects_listbox)
        self._objects_list.customContextMenuRequested.connect(
            self._on_objects_list_menu)
        objects_label.setBuddy(self._objects_list)
        layout.addWidget(self._objects_list, 1, 0)
        props_label = QLabel(_("Object properties"), self)
        layout.addWidget(props_label, 0, 1)
        self._props = QTreeWidget(self)
        self._props.setAccessibleName(props_label.text())
        props_label.setBuddy(self._props)
        layout.addWidget(self._props, 1, 1)
        goto_button = QPushButton(_("Go to"), self)
        goto_button.setDefault(True)
        goto_button.clicked.connect(self.on_goto_clicked)
        self._objects_list.itemActivated.connect(goto_button.click)
        layout.addWidget(goto_button, 2, 0)
        close_button = QPushButton(_("Close"), self)
        close_button.clicked.connect(self.close)
        layout.addWidget(close_button, 2, 1)
        self.setLayout(layout)
        self.setWindowTitle(title + _(" ({num_objects} objects shown)").format(
            num_objects=len(unsorted_objects)))
        self._person = person
        self._autoshow = autoshow
        self._progress_indicator = progress_indicator
        self._all_actions = []
        for member in object_actions.__dict__.values():
            if inspect.isclass(member) and issubclass(member, ObjectAction):
                self._all_actions.append(member)
        self._objects_list.setCurrentRow(0)
        self._sorter = ObjectsSorter(unsorted_objects, person)
        self._sorter.objects_sorted.connect(self._objects_sorted)
        self._sorter.start()

    def _objects_sorted(self, data):
        objects, item_data = data
        self._objects = objects
        for (desc, dist, rel_bearing) in item_data:
            self._objects_list.addItem(
                _("{object}: distance {distance} meters, {rel_bearing}").
                format(object=desc, distance=dist, rel_bearing=rel_bearing))
        if self._progress_indicator:
            self._progress_indicator.hide()
            self._progress_indicator.deleteLater()
        if self._autoshow:
            self._objects_list.setCurrentRow(0)
            self.show()

    def _create_item(self, menu, label, shortcut, callback):
        action = menu.addAction(label)
        action.triggered.connect(callback)
        action.setShortcut(QKeySequence(shortcut))

    def on_goto_clicked(self, evt):
        self._person.move_to(self.selected_object[2], force=True)

    def _do_close(self):
        self.close()
        self.destroy()
        windows = QApplication.topLevelWidgets()
        other_browsers = [
            w for w in windows if w is not self
            and isinstance(w, self.__class__) and w.isVisible()
        ]
        if other_browsers:
            other_browsers[-1].activateWindow()
        else:
            menu_service().ensure_key_capturer_focus()

    def on_objects_listbox(self, current_index):
        selected = self._objects[current_index][1]
        self._props.clear()
        common_item = QTreeWidgetItem([_("Common properties")])
        specific_item = QTreeWidgetItem([_("Specific properties")])
        other_item = QTreeWidgetItem([
            _("Other properties - they can not be searched and are not processed in any way"
              )
        ])
        common_fields = list(
            EntityMetadata.for_discriminator("OSMEntity").fields.keys())
        selected_metadata = EntityMetadata.for_discriminator(
            selected.discriminator)
        known_fields = selected_metadata.all_fields
        formatted_values = {}
        for field_name in selected.defined_field_names():
            raw_value = selected.value_of_field(field_name)
            if field_name not in known_fields:
                # By the mere fact that the other fields have no defined order, we can add them there without losing anything.
                other_item.addChild(
                    QTreeWidgetItem([
                        "%s: %s" %
                        (underscored_to_words(field_name), raw_value)
                    ]))
            else:
                value_str = "%s: %s" % (
                    underscored_to_words(field_name),
                    format_field_value(raw_value,
                                       known_fields[field_name].type_name))
                formatted_values[field_name] = value_str
        for common in common_fields:
            del known_fields[common]
            common_item.addChild(QTreeWidgetItem([formatted_values[common]]))
        for specific in known_fields.keys(
        ):  # Because we deleted the common ones in the loop before this, only the specific remain.
            if specific in formatted_values:
                specific_item.addChild(
                    QTreeWidgetItem([formatted_values[specific]]))
        # We add the entity ID mainly for debugging purposes, and that's the reason why it is added the last and so special in the first place.
        common_item.addChild(
            QTreeWidgetItem([_("Object id: {}").format(selected.id)]))
        self._props.addTopLevelItem(common_item)
        if specific_item.childCount() > 0:
            self._props.addTopLevelItem(specific_item)
            self._props.expandItem(specific_item)
            #self._props.setCurrentItem(specific_item) # Breaks focus behavior slightly, but annoingly enough.
        if other_item.childCount() > 0:
            self._props.addTopLevelItem(other_item)
        self._object_actions.clear()
        for action in self._all_actions:
            if action.executable(selected):
                mi = self._object_actions.addAction(action.label)
                mi.triggered.connect(
                    action_execution_handler_factory(action, selected, self))

    @property
    def selected_object(self):
        return self._objects[self._objects_list.currentRow()]

    def on_copypropvalue_selected(self, evt):
        prop = self._props.currentItem().text(0)
        val = prop.split(": ", 1)[1]
        QApplication.clipboard().setText(val)

    def on_copypropname_selected(self, evt):
        prop = self._props.currentItem().text(0)
        name = prop.split(": ", 1)[0]
        QApplication.clipboard().setText(name)

    def on_copypropline_selected(self, evt):
        prop = self._props.currentItem().text(0)
        QApplication.clipboard().setText(prop)

    def _on_objects_list_menu(self, point):
        self._object_actions.exec_(point)
示例#3
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()
示例#4
0
 def delete_list(tree: QTreeWidget):
     selected = tree.currentItem()
     if selected:
         index = tree.indexOfTopLevelItem(selected)
         tree.takeTopLevelItem(index)