def open_file(dialog=None, osm_file=None, output_geom_types=None, white_list_column=None, layer_name="OsmFile", config_outputs=None, output_dir=None, final_query=None, prefix_file=None): """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. :param final_query: The query where the file comes from. Might be empty if it's a local OSM file. :type final_query: basestring """ outputs = {} if output_dir: for layer in ['points', 'lines', 'multilinestrings', 'multipolygons']: if not prefix_file: prefix_file = layer_name outputs[layer] = join(output_dir, prefix_file + "_" + layer + ".geojson") if isfile(outputs[layer]): raise FileOutPutException(suffix='(' + outputs[layer] + ')') # Legacy, waiting to remove the OsmParser for QGIS >= 3.6 # Change in osm_file_dialog.py L131 too output_geom_legacy = [geom.value.lower() for geom in output_geom_types] if not white_list_column: white_list_column = {} white_list_legacy = ({ cols.value.lower(): csv for cols, csv in white_list_column.items() }) LOGGER.info('The OSM file is: {}'.format(osm_file)) # Parsing the file osm_parser = OsmParser(osm_file=osm_file, layers=output_geom_legacy, white_list_column=white_list_legacy) osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) start_time = time.time() layers = osm_parser.parse() elapsed_time = time.time() - start_time parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time)) LOGGER.info('The OSM parser took: {}'.format(parser_time)) # Finishing the process with geojson or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and (LayerType(layer.capitalize()) in output_geom_types): final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] if output_dir: dialog.set_progress_text( tr('From memory layer to GeoJSON: ' + layer)) # Transforming the vector file osm_geometries = { 'points': QgsWkbTypes.Point, 'lines': QgsWkbTypes.LineString, 'multilinestrings': QgsWkbTypes.MultiLineString, 'multipolygons': QgsWkbTypes.MultiPolygon } memory_layer = item['vector_layer'] encoding = get_default_encoding() writer = QgsVectorFileWriter(outputs[layer], encoding, memory_layer.fields(), osm_geometries[layer], memory_layer.crs(), "GeoJSON") for f in memory_layer.getFeatures(): writer.addFeature(f) del writer # Loading the final vector file new_layer = QgsVectorLayer(outputs[layer], final_layer_name, "ogr") else: new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: # Loading default styles if layer == "multilinestrings" or layer == "lines": if "colour" in item['tags']: new_layer.loadNamedStyle( join(dirname(dirname(abspath(__file__))), "styles", layer + "_colour.qml")) # Add action about OpenStreetMap add_actions(new_layer, item['tags']) if final_query: QgsExpressionContextUtils.setLayerVariable( new_layer, 'quickosm_query', final_query) QgsProject.instance().addMapLayer(new_layer) num_layers += 1 return num_layers
class MultiType(Enum): """Type of combination of two queries""" AND = tr('And') OR = tr('Or')
def update_personal_preset_view(self): """Update the presets displayed.""" preset_folder = query_preset() files = filter( lambda folder: os.path.isdir(join(preset_folder, folder)), os.listdir(preset_folder)) self.dialog.list_personal_preset_mp.clear() for file in files: file_path = join(preset_folder, file, file + '.json') with open(file_path, encoding='utf8') as json_file: data = json.load(json_file, object_hook=as_enum) name = data['file_name'] item = QListWidgetItem(self.dialog.list_personal_preset_mp) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.dialog.list_personal_preset_mp.addItem(item) preset = QFrame() preset.setObjectName('FramePreset') preset.setFrameStyle(QFrame.StyledPanel) preset.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox = QHBoxLayout() vbox = QVBoxLayout() label_name = QLabel(name) label_name.setStyleSheet('font-weight: bold;') label_name.setWordWrap(True) vbox.addWidget(label_name) for label in data['description']: if not label: label = tr('No description') real_label = QLabel(label) real_label.setWordWrap(True) vbox.addWidget(real_label) hbox.addItem(vbox) button_edit = QPushButton() button_remove = QPushButton() button_edit.setIcon( QIcon(QgsApplication.iconPath("mActionToggleEditing.svg"))) button_remove.setIcon( QIcon(QgsApplication.iconPath('symbologyRemove.svg'))) button_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_remove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_edit.setToolTip(tr('Edit the preset')) button_remove.setToolTip(tr('Delete the preset')) hbox.addWidget(button_edit) hbox.addWidget(button_remove) if data['advanced']: self.listAdvanced.append(True) preset.setStyleSheet('#FramePreset { margin: 3px;' ' border: 3px solid ' + self.advanced_selected + ';' ' border-width: 1px 1px 1px 4px;}') else: self.listAdvanced.append(False) preset.setStyleSheet('#FramePreset { margin: 3px;' ' border: 3px solid ' + self.basic_selected + ';' ' border-width: 1px 1px 1px 4px;}') preset.setLayout(hbox) # Actions on click remove = partial(self.verification_remove_preset, item, name) button_remove.clicked.connect(remove) edit = partial(self.edit_preset, data) button_edit.clicked.connect(edit) item.setSizeHint(preset.minimumSizeHint()) self.dialog.list_personal_preset_mp.setItemWidget(item, preset) self.listAdvanced.append(False)
def process_query(dialog: QDialog = None, query: str = None, description: str = None, area: Union[str, List[str]] = None, key: Union[str, List[str]] = None, value: Union[str, List[str]] = None, type_multi_request: list = None, bbox: QgsRectangle = None, output_dir: str = None, output_format: Format = None, prefix_file: str = None, output_geometry_types: list = None, layer_name: str = "OsmQuery", white_list_values: dict = None, config_outputs: dict = None) -> int: """execute a query and send the result file to open_file.""" # Save the query in the historic q_manage = QueryManagement(query=query, name=prefix_file if prefix_file else layer_name, description=description, advanced=value is None, type_multi_request=type_multi_request, keys=key, values=value, area=area, bbox=bbox, output_geometry_types=output_geometry_types, white_list_column=white_list_values) q_manage.write_query_historic() if dialog.feedback_process.isCanceled(): return None # Prepare outputs dialog.set_progress_text(tr('Prepare outputs')) # Getting the default overpass api and running the query server = get_setting('defaultOAPI', OVERPASS_SERVERS[0]) + 'interpreter' dialog.set_progress_text( tr('Downloading data from Overpass {server_name}'.format( server_name=server))) # Replace Nominatim or BBOX query = QueryPreparation(query, bbox, area, server) QApplication.processEvents() final_query = query.prepare_query() url = query.prepare_url() connexion_overpass_api = ConnexionOAPI(url) LOGGER.debug('Encoded URL: {}'.format(url)) osm_file = connexion_overpass_api.run() return open_file(dialog=dialog, osm_file=osm_file, output_geom_types=output_geometry_types, white_list_column=white_list_values, key=key, layer_name=layer_name, output_dir=output_dir, output_format=output_format, prefix_file=prefix_file, final_query=final_query, config_outputs=config_outputs, feedback=dialog.feedback_process)
def open_file(dialog: QDialog = None, osm_file: str = None, output_geom_types: list = None, white_list_column: dict = None, key: Union[str, List[str]] = None, layer_name: str = "OsmFile", config_outputs: dict = None, output_dir: str = None, output_format: Format = None, final_query: str = None, prefix_file: str = None, subset: bool = False, subset_query: str = None, feedback: QgsFeedback = None) -> int: """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. :param final_query: The query where the file comes from. Might be empty if it's a local OSM file. :type final_query: basestring """ if output_geom_types is None: output_geom_types = OSM_LAYERS # Legacy, waiting to remove the OsmParser for QGIS >= 3.6 # Change in osm_file_dialog.py L131 too output_geom_legacy = [geom.value.lower() for geom in output_geom_types] if not white_list_column: white_list_column = None LOGGER.info('The OSM file is: {}'.format(osm_file)) if feedback: if feedback.isCanceled(): return None # Parsing the file osm_parser = OsmParser(osm_file=osm_file, layers=output_geom_legacy, output_format=output_format, output_dir=output_dir, prefix_file=prefix_file, layer_name=layer_name, key=key, white_list_column=white_list_column, subset=subset, subset_query=subset_query, feedback=feedback) if dialog: osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) start_time = time.time() layers = osm_parser.processing_parse() elapsed_time = time.time() - start_time parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time)) LOGGER.info('The OSM parser took: {}'.format(parser_time)) if feedback: if feedback.isCanceled(): return None # Finishing the process with an output format or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): if dialog: dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and (LayerType(layer.capitalize()) in output_geom_types): final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: if "colour" in item['tags']: index = item['tags'].index('colour') colors = new_layer.uniqueValues(index) categories = [] for value in colors: if str(value) == 'None': value = '' if layer in ['lines', 'multilinestrings']: symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.LineGeometry) elif layer == "points": symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.PointGeometry) elif layer == "multipolygons": symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.PolygonGeometry) symbol.setColor(QColor(value)) category = QgsRendererCategory(str(value), symbol, str(value)) categories.append(category) renderer = QgsCategorizedSymbolRenderer( "colour", categories) new_layer.setRenderer(renderer) # Add action about OpenStreetMap actions.add_actions(new_layer, item['tags']) QgsProject.instance().addMapLayer(new_layer) if final_query: QgsExpressionContextUtils.setLayerVariable( new_layer, 'quickosm_query', final_query) actions.add_relaunch_action(new_layer, final_layer_name) if dialog: dialog.iface.addCustomActionForLayer( dialog.reload_action, new_layer) metadata = QgsLayerMetadata() metadata.setRights([tr("© OpenStreetMap contributors")]) metadata.setLicenses(['https://openstreetmap.org/copyright']) new_layer.setMetadata(metadata) num_layers += 1 return num_layers
def save_add_existing(self): """Verify and ask the save destination.""" self.existing_preset = True self.dialog.button_save_query.setText(tr('Save and add query to an existing preset'))
def setup_panel(self): super().setup_panel() """Setup the UI for the QuickQuery.""" # Setup presets and keys auto completion self.setup_preset() # Table Keys/Values self.setup_table() # Query type self.dialog.combo_query_type_qq.addItem(tr('In'), 'in') self.dialog.combo_query_type_qq.addItem(tr('Around'), 'around') self.dialog.combo_query_type_qq.addItem(tr('Canvas Extent'), 'canvas') self.dialog.combo_query_type_qq.addItem(tr('Layer Extent'), 'layer') self.dialog.combo_query_type_qq.addItem(tr('Not Spatial'), 'attributes') # self.cb_query_type_qq.setItemIcon( # 0, QIcon(resources_path('in.svg'))) # self.cb_query_type_qq.setItemIcon( # 1, QIcon(resources_path('around.svg'))) # self.cb_query_type_qq.setItemIcon( # 2, QIcon(resources_path('map_canvas.svg'))) # self.cb_query_type_qq.setItemIcon( # 3, QIcon(resources_path('extent.svg'))) # self.cb_query_type_qq.setItemIcon( # 4, QIcon(resources_path('mIconTableLayer.svg'))) self.dialog.combo_query_type_qq.currentIndexChanged.connect( self.query_type_updated) self.dialog.button_save_query.setMenu(QMenu()) self.action_new = QAction(SaveType.New.value) self.action_new.triggered.connect(self.save_new) self.action_existing = QAction(SaveType.Existing.value) self.action_existing.triggered.connect(self.save_add_existing) self.dialog.button_save_query.menu().addAction(self.action_new) self.dialog.button_save_query.menu().addAction(self.action_existing) self.dialog.button_save_query.clicked.connect(self.save_query) self.dialog.button_show_query.setMenu(QMenu()) self.dialog.action_oql_qq.triggered.connect(self.query_language_oql) self.dialog.action_xml_qq.triggered.connect(self.query_language_xml) self.dialog.button_show_query.menu().addAction(self.dialog.action_oql_qq) self.dialog.button_show_query.menu().addAction(self.dialog.action_xml_qq) query_oql = partial(self.show_query, QueryLanguage.OQL) self.dialog.button_show_query.clicked.connect(query_oql) self.dialog.button_run_query_qq.clicked.connect(self.run) self.dialog.button_map_features.clicked.connect(open_plugin_documentation) self.dialog.button_box_qq.button(QDialogButtonBox.Reset).clicked.connect( self.dialog.reset_form) # setup callbacks for friendly-label-update only self.dialog.line_place_qq.textChanged.connect(self.update_friendly) self.dialog.spin_place_qq.valueChanged.connect(self.update_friendly) self.dialog.combo_extent_layer_qq.layerChanged.connect(self.query_type_updated) self.query_type_updated() self.init_nominatim_autofill() self.update_friendly() self.update_history_view()
def save_new(self): """Verify the save destination.""" self.existing_preset = False self.dialog.button_save_query.setText(tr('Save query in a new preset'))
def add_outputs(self): """Set up the outputs of the algorithm.""" output = QgsProcessingOutputVectorLayer( self.OUTPUT_LAYER, tr('Output layer') ) self.addOutput(output)
def shortHelpString(self) -> str: """Return an helper for the algorithm.""" return tr('Decorate the layer as an QuickOSM output.')
def group() -> str: """Return the group of the algorithm.""" return tr('Advanced')
def displayName() -> str: """Return the display name of the algorithm.""" return tr('Decorate a layer from OSM')