From b295735792b9aead72edd92088f26637b07ba796 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Sat, 22 Aug 2020 09:14:45 +0200 Subject: [PATCH] Revert "Merge pull request #171 from opengisch/localized" This reverts commit 3e15884faa1880d6087eb114d1578a836fc22c95, reversing changes made to 8de959c594eb0d67ff6db7962991bf3422cf6d78. --- .travis.yml | 4 +- qfieldsync/core/layer.py | 88 +++++++++++----------------- qfieldsync/core/offline_converter.py | 14 ----- qfieldsync/gui/package_dialog.py | 56 ++++++------------ qfieldsync/gui/synchronize_dialog.py | 10 +++- qfieldsync/metadata.txt | 2 +- qfieldsync/ui/package_dialog.ui | 63 +------------------- qfieldsync/ui/synchronize_dialog.ui | 21 ++----- 8 files changed, 68 insertions(+), 190 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2891301d..cfec9a11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ install: jobs: include: - stage: test - name: Test on QGIS LTR 3.10 + name: Test on QGIS 3.4 env: - QGIS_TEST_VERSION="final-3_10_9" + QGIS_TEST_VERSION="release-3_4" script: docker-compose -f .docker/docker-compose.travis.yml run qgis /usr/src/.docker/run-docker-tests.sh - stage: test diff --git a/qfieldsync/core/layer.py b/qfieldsync/core/layer.py index f91153bd..3373a8cd 100644 --- a/qfieldsync/core/layer.py +++ b/qfieldsync/core/layer.py @@ -7,11 +7,7 @@ from qgis.core import ( QgsDataSourceUri, QgsMapLayer, - QgsReadWriteContext, - QgsProject, - QgsProviderRegistry, - QgsProviderMetadata, - Qgis + QgsReadWriteContext ) from qfieldsync.utils.file_utils import slugify @@ -78,17 +74,6 @@ def __init__(self, layer): self._is_geometry_locked = None self.read_layer() - self.storedInlocalizedDataPath = False - if self.layer.dataProvider() is not None: - pathResolver = QgsProject.instance().pathResolver() - metadata = QgsProviderRegistry.instance().providerMetadata(self.layer.dataProvider().name()) - if metadata is not None: - decoded = metadata.decodeUri(self.layer.source()) - if "path" in decoded: - path = pathResolver.writePath(decoded["path"]) - if path.startswith("localized:"): - self.storedInlocalizedDataPath = True - def read_layer(self): self._action = self.layer.customProperty('QFieldSync/action') self._photo_naming = json.loads(self.layer.customProperty('QFieldSync/photo_naming') or '{}') @@ -138,20 +123,19 @@ def is_configured(self): @property def is_file(self): - if self.layer.dataProvider() is not None: - metadata = QgsProviderRegistry.instance().providerMetadata(self.layer.dataProvider().name()) - if metadata is not None: - decoded = metadata.decodeUri(self.layer.source()) - if "path" in decoded: - if os.path.isfile(decoded["path"]): - return True - return False + # reading the part before | so it's valid when gpkg + if os.path.isfile(self.layer.source().split('|')[0]): + return True + elif os.path.isfile(QgsDataSourceUri(self.layer.dataProvider().dataSourceUri()).database()): + return True + else: + return False @property def available_actions(self): actions = list() - if self.is_file and not self.storedInlocalizedDataPath: + if self.is_file: actions.append((SyncAction.NO_ACTION, QCoreApplication.translate('LayerAction', 'copy'))) actions.append((SyncAction.KEEP_EXISTENT, QCoreApplication.translate('LayerAction', 'keep existent (copy if missing)'))) else: @@ -216,19 +200,14 @@ def copy(self, target_path, copied_files, keep_existent=False): # Copy will also be called on non-file layers like WMS. In this case, just do nothing. return - file_path = '' - layer_name = '' - - if self.layer.dataProvider() is not None: - metadata = QgsProviderRegistry.instance().providerMetadata(self.layer.dataProvider().name()) - if metadata is not None: - decoded = metadata.decodeUri(self.layer.source()) - if "path" in decoded: - file_path = decoded["path"] - if "layerName" in decoded: - layer_name = decoded["layerName"] - if file_path == '': - file_path = self.layer.source() + layer_name_suffix = '' + # Shapefiles and GeoPackages have the path in the source + uri_parts = self.layer.source().split('|', 1) + file_path = uri_parts[0] + if len(uri_parts) > 1: + layer_name_suffix = uri_parts[1] + # Spatialite have the path in the table part of the uri + uri = QgsDataSourceUri(self.layer.dataProvider().dataSourceUri()) if os.path.isfile(file_path): source_path, file_name = os.path.split(file_path) @@ -239,23 +218,24 @@ def copy(self, target_path, copied_files, keep_existent=False): (keep_existent is False or not os.path.isfile(dest_file)): shutil.copy(os.path.join(source_path, basename + ext), dest_file) - new_source = '' - if Qgis.QGIS_VERSION_INT >= 31200 and self.layer.dataProvider() is not None: - metadata = QgsProviderRegistry.instance().providerMetadata(self.layer.dataProvider().name()) - if metadata is not None: - new_source = metadata.encodeUri({"path":os.path.join(target_path, file_name),"layerName":layer_name}) - if new_source == '': - if self.layer.dataProvider() and self.layer.dataProvider().name == "spatialite": - uri = QgsDataSourceUri() - uri.setDatabase(os.path.join(target_path, file_name)) - uri.setTable(layer_name) - new_source = uri.uri() - else: - new_source = os.path.join(target_path, file_name) - if layer_name != '': - new_source = "{}|{}".format(new_source, layer_name) - + new_source = os.path.join(target_path, file_name) + if layer_name_suffix: + new_source = new_source + '|' + layer_name_suffix self._change_data_source(new_source) + # Spatialite files have a uri + else: + file_path = uri.database() + if os.path.isfile(file_path): + source_path, file_name = os.path.split(file_path) + basename, extensions = get_file_extension_group(file_name) + for ext in extensions: + dest_file = os.path.join(target_path, basename + ext) + if os.path.exists(os.path.join(source_path, basename + ext)) and \ + (keep_existent is False or not os.path.isfile(dest_file)): + shutil.copy(os.path.join(source_path, basename + ext), + dest_file) + uri.setDatabase(os.path.join(target_path, file_name)) + self._change_data_source(uri.uri()) return copied_files def _change_data_source(self, new_data_source): diff --git a/qfieldsync/core/offline_converter.py b/qfieldsync/core/offline_converter.py index c3b90567..84916a51 100644 --- a/qfieldsync/core/offline_converter.py +++ b/qfieldsync/core/offline_converter.py @@ -45,8 +45,6 @@ QgsProcessingFeedback, QgsProcessingContext, QgsMapLayer, - QgsProviderRegistry, - QgsProviderMetadata, QgsEditorWidgetSetup ) import qgis @@ -125,22 +123,10 @@ def convert(self): self.project_configuration.base_map_mupp) # Loop through all layers and copy/remove/offline them - pathResolver = QgsProject.instance().pathResolver() copied_files = list() for current_layer_index, layer in enumerate(self.__layers): self.total_progress_updated.emit(current_layer_index - len(self.__offline_layers), len(self.__layers), self.trUtf8('Copying layers…')) - - if layer.dataProvider() is not None: - md = QgsProviderRegistry.instance().providerMetadata(layer.dataProvider().name()) - if md is not None: - decoded = md.decodeUri(layer.source()) - if "path" in decoded: - path = pathResolver.writePath(decoded["path"]) - if path.startswith("localized:"): - # Layer stored in localized data path, skip - continue - layer_source = LayerSource(layer) if layer_source.action == SyncAction.OFFLINE: diff --git a/qfieldsync/gui/package_dialog.py b/qfieldsync/gui/package_dialog.py index e1e39d04..75e3522b 100644 --- a/qfieldsync/gui/package_dialog.py +++ b/qfieldsync/gui/package_dialog.py @@ -32,9 +32,6 @@ pyqtSlot, Qt ) -from qgis.PyQt.QtGui import ( - QIcon -) from qgis.PyQt.QtWidgets import ( QDialogButtonBox, QPushButton, @@ -45,8 +42,6 @@ from qgis.core import ( QgsProject, QgsApplication, - QgsProviderRegistry, - QgsProviderMetadata, Qgis ) from qgis.PyQt.uic import loadUiType @@ -70,11 +65,9 @@ def __init__(self, iface, project, offline_editing, parent=None): self.project = project self.qfield_preferences = Preferences() self.project_lbl.setText(get_project_title(self.project)) - self.button_box.button(QDialogButtonBox.Save).setText(self.tr('Create')) - self.button_box.button(QDialogButtonBox.Save).clicked.connect(self.package_project) - self.button_box.button(QDialogButtonBox.Reset).setText(self.tr('Configure project...')) - self.button_box.button(QDialogButtonBox.Reset).setIcon(QIcon()) - self.button_box.button(QDialogButtonBox.Reset).clicked.connect(self.show_settings) + self.push_btn = QPushButton(self.tr('Create')) + self.push_btn.clicked.connect(self.package_project) + self.button_box.addButton(self.push_btn, QDialogButtonBox.ActionRole) self.iface.mapCanvas().extentsChanged.connect(self.extent_changed) self.extent_changed() @@ -99,6 +92,8 @@ def setup_gui(self): self.manualDir.setText(export_folder_path) self.manualDir_btn.clicked.connect(make_folder_selector(self.manualDir)) self.update_info_visibility() + self.infoLabel.setTextInteractionFlags(Qt.TextBrowserInteraction) + self.infoLabel.linkActivated.connect(lambda: self.show_settings()) def get_export_folder_from_dialog(self): """Get the export folder according to the inputs in the selected""" @@ -106,7 +101,7 @@ def get_export_folder_from_dialog(self): return self.manualDir.text() def package_project(self): - self.button_box.button(QDialogButtonBox.Save).setEnabled(False) + self.push_btn.setEnabled(False) self.informationStack.setCurrentWidget(self.progressPage) export_folder = self.get_export_folder_from_dialog() @@ -133,41 +128,24 @@ def do_post_offline_convert_action(self): """ export_folder = self.get_export_folder_from_dialog() - result_message = self.tr('Finished creating the project at {result_folder}. Please copy this folder to ' - 'your QField device.').format(result_folder='{folder}'.format(folder=export_folder)) - self.iface.messageBar().pushMessage(result_message, Qgis.Success, 0) + result_label = QLabel(self.tr('Finished creating the project at {result_folder}. Please copy this folder to ' + 'your QField device.').format( + result_folder='{folder}'.format(folder=export_folder))) + result_label.setTextFormat(Qt.RichText) + result_label.setTextInteractionFlags(Qt.TextBrowserInteraction) + result_label.linkActivated.connect(lambda: open_folder(export_folder)) + result_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) + + self.iface.messageBar().pushWidget(result_label, Qgis.Info, 0) def update_info_visibility(self): """ Show the info label if there are unconfigured layers """ - pathResolver = QgsProject.instance().pathResolver() - showInfoConfiguration = False - localizedDataPathLayers = [] + self.infoGroupBox.hide() for layer in list(self.project.mapLayers().values()): if not LayerSource(layer).is_configured: - showInfoConfiguration = True - if layer.dataProvider() is not None: - metadata = QgsProviderRegistry.instance().providerMetadata(layer.dataProvider().name()) - if metadata is not None: - decoded = metadata.decodeUri(layer.source()) - if "path" in decoded: - path = pathResolver.writePath(decoded["path"]) - if path.startswith("localized:"): - localizedDataPathLayers.append('- {} ({})'.format(layer.name(), path[10:])) - - self.infoConfigurationLabel.setVisible(showInfoConfiguration) - if localizedDataPathLayers: - if len(localizedDataPathLayers) == 1: - self.infoLocalizedLayersLabel.setText(self.tr('The layer stored in a localized data path is:\n{}').format("\n".join(localizedDataPathLayers))) - else: - self.infoLocalizedLayersLabel.setText(self.tr('The layers stored in a localized data path are:\n{}').format("\n".join(localizedDataPathLayers))) - self.infoLocalizedLayersLabel.setVisible(True) - self.infoLocalizedPresentLabel.setVisible(True) - else: - self.infoLocalizedLayersLabel.setVisible(False) - self.infoLocalizedPresentLabel.setVisible(False) - self.infoGroupBox.setVisible(showInfoConfiguration or len(localizedDataPathLayers) > 0) + self.infoGroupBox.show() project_configuration = ProjectConfiguration(self.project) diff --git a/qfieldsync/gui/synchronize_dialog.py b/qfieldsync/gui/synchronize_dialog.py index c35d197b..850cc9e9 100644 --- a/qfieldsync/gui/synchronize_dialog.py +++ b/qfieldsync/gui/synchronize_dialog.py @@ -51,18 +51,20 @@ def __init__(self, iface, offline_editing, parent=None): self.iface = iface self.preferences = Preferences() self.offline_editing = offline_editing - self.button_box.button(QDialogButtonBox.Save).setText(self.tr('Synchronize')) - self.button_box.button(QDialogButtonBox.Save).clicked.connect(self.start_synchronization) + self.push_btn = QPushButton(self.tr('Synchronize')) + self.push_btn.clicked.connect(self.start_synchronization) + self.button_box.addButton(self.push_btn, QDialogButtonBox.ActionRole) self.qfieldDir.setText(self.preferences.value('importDirectoryProject') or self.preferences.value('importDirectory')) self.qfieldDir_button.clicked.connect(make_folder_selector(self.qfieldDir)) self.offline_editing_done = False def start_synchronization(self): - self.button_box.button(QDialogButtonBox.Save).setEnabled(False) + self.push_btn.setEnabled(False) qfield_folder = self.qfieldDir.text() self.preferences.set_value('importDirectoryProject', qfield_folder) try: + self.progress_group.setEnabled(True) current_import_file_checksum = import_file_checksum(qfield_folder) imported_files_checksums = import_checksums_of_project(qfield_folder) @@ -97,6 +99,8 @@ def start_synchronization(self): raise NoProjectFoundError(message) except NoProjectFoundError as e: self.iface.messageBar().pushWarning('QFieldSync', str(e)) + finally: + self.progress_group.setEnabled(False) @pyqtSlot(int, int) def update_total(self, current, layer_count): diff --git a/qfieldsync/metadata.txt b/qfieldsync/metadata.txt index 6639dd58..69af1520 100644 --- a/qfieldsync/metadata.txt +++ b/qfieldsync/metadata.txt @@ -8,7 +8,7 @@ [general] name=QField Sync -qgisMinimumVersion=3.10 +qgisMinimumVersion=3.0 description=Sync your projects to QField version=dev author=OPENGIS.ch diff --git a/qfieldsync/ui/package_dialog.ui b/qfieldsync/ui/package_dialog.ui index 328e3199..56a2a84b 100644 --- a/qfieldsync/ui/package_dialog.ui +++ b/qfieldsync/ui/package_dialog.ui @@ -67,22 +67,6 @@ - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 16 - 16 - - - - @@ -243,7 +227,7 @@ Qt::Horizontal - QDialogButtonBox::Close|QDialogButtonBox::Save|QDialogButtonBox::Reset + QDialogButtonBox::Close @@ -254,50 +238,9 @@ - - - - 0 - 0 - - + - Some layers in this project have not yet been configured, configure those now. - - - true - - - - - - - - 0 - 0 - - - - The current project relies on datasets stored in localized data paths, make sure to copy the relevant datasets into the localized data path of devices running QField. On most devices, the path is <u>/QField/basemaps.</u> - - - true - - - - - - - - 0 - 0 - - - - - - - true + Some layers in this project have not yet been configured. <a href="configuration">Configure project now</a>. diff --git a/qfieldsync/ui/synchronize_dialog.ui b/qfieldsync/ui/synchronize_dialog.ui index 14bf398a..4e886771 100644 --- a/qfieldsync/ui/synchronize_dialog.ui +++ b/qfieldsync/ui/synchronize_dialog.ui @@ -40,6 +40,9 @@ + + false + Progress @@ -72,22 +75,6 @@ - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 16 - 16 - - - - @@ -97,7 +84,7 @@ Qt::Horizontal - QDialogButtonBox::Close|QDialogButtonBox::Save + QDialogButtonBox::Close