def test_widget(self): """Manual local GUI test for the model""" d = QDialog() l = QVBoxLayout(d) d.setLayout(l) lbl = QLabel('fetching...', d) l.addWidget(lbl) v = QListView() l.addWidget(v) d.show() md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(self.uri, {}) res = conn.execSql('SELECT * FROM qgis_test.random_big_data') model = QgsQueryResultModel(res) v.setModel(model) def _set_row_count(idx, first, last): lbl.setText('Rows %s fetched' % model.rowCount(model.index(-1, -1))) # noqa: F821 model.rowsInserted.connect(_set_row_count) d.exec_() # Because exit handler will exit QGIS and clear the connections pool before # the model is deleted (and it will in turn clear the connection) del (model)
def onLoad(self): dlg = QDialog(self.iface.mainWindow()) dlg.setWindowTitle("Choose the database to load layers from") layout = QVBoxLayout() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(dlg.accept) button_box.rejected.connect(dlg.reject) db_widget = DatabaseWidget(dlg, is_input=True) layout.addWidget(db_widget) layout.addWidget(button_box) dlg.setLayout(layout) if dlg.exec_() == QDialog.Rejected: return try: source = db_widget.datasource_name() if source.startswith("PG:"): schema = db_widget.schema() else: schema = None QApplication.setOverrideCursor(Qt.WaitCursor) import_in_qgis(source, db_widget.format(), schema) except InputError as e: QMessageBox.warning(None, "Error during layer loading", e.args[0]) except RuntimeError as e: QMessageBox.warning(None, "Error during layer loading", e.args[0]) finally: QApplication.restoreOverrideCursor()
def testFindParentPanel(self): """ test QgsPanelWidget.findParentPanel """ # no widget self.assertFalse(QgsPanelWidget.findParentPanel(None)) # widget with no parent w = QWidget() self.assertFalse(QgsPanelWidget.findParentPanel(w)) # widget with no panel parent w2 = QWidget(w) self.assertFalse(QgsPanelWidget.findParentPanel(w2)) # panel widget itself w3 = QgsPanelWidget() self.assertEqual(QgsPanelWidget.findParentPanel(w3), w3) # widget with direct QgsPanelWidget parent w4 = QWidget(w3) self.assertEqual(QgsPanelWidget.findParentPanel(w4), w3) # widget with QgsPanelWidget grandparent w5 = QWidget(w4) self.assertEqual(QgsPanelWidget.findParentPanel(w5), w3) # chain should be broken when a new window is encountered n = QgsPanelWidget() n2 = QDialog(n) n3 = QWidget(n2) self.assertFalse(QgsPanelWidget.findParentPanel(n3))
def on_load_base_layer(self): # look for base layers in the config layer_config = get_layer_config() dlg = QDialog() vbox = QVBoxLayout() list_widget = QListWidget() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) vbox.addWidget(list_widget) vbox.addWidget(button_box) dlg.setWindowTitle("Select a base layer to load") dlg.setLayout(vbox) # populate the list widget for (uri, provider), cfg in layer_config.items(): layer_name = cfg.get( "layer_name", "Unnamed layer ({}, {})".format(uri, provider)) list_item = QListWidgetItem() list_item.setText(layer_name) list_item.setData(Qt.UserRole, (uri, provider)) list_widget.addItem(list_item) button_box.rejected.connect(dlg.reject) button_box.accepted.connect(dlg.accept) if dlg.exec_(): item = list_widget.currentItem() if item: uri, provider = item.data(Qt.UserRole) self.iface.addVectorLayer(uri, item.text(), provider)
def runImportObservationData(self): # Get the list of series series = self.getSeries() if not series: return # Create dialog to let the user choose the serie dialog = QDialog() dialog.setWindowTitle(tr('Import observation data')) layout = QVBoxLayout() dialog.setLayout(layout) # Combobox combo_box = QComboBox() combo_box.setObjectName((tr('Choose series'))) for i, d in enumerate(series): combo_box.addItem(d[1]) combo_box.setItemData(i, d[0]) layout.addWidget(combo_box) # Validation button button_box = QDialogButtonBox() button_box.addButton(QDialogButtonBox.Ok) button_box.button(QDialogButtonBox.Ok).clicked.connect(dialog.accept) layout.addWidget(button_box) if dialog.exec_() == QDialog.Accepted: idx = combo_box.currentIndex() val = combo_box.itemData(idx) self.openImportObservationData(val)
def _showDialog(self, widget): """Used during development""" from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout d = QDialog() l = QVBoxLayout() l.addWidget(widget) d.setLayout(l) d.exec()
def canvasReleaseEvent(self, event): """ Canvas is released. This means: * start digitizing * stop digitizing (create a rectangle * if the Ctrl-modifier is pressed, ask for the rectangle width :param event: coordinates etc. """ if event.button() == Qt.RightButton: self.deactivate() else: mousepos = self.canvas.getCoordinateTransform()\ .toMapCoordinates(event.pos().x(), event.pos().y()) self.rubberband.addPoint(mousepos) if self.firstPoint: # If the first point was set before, we are doing the second one lp1 = self.rubberband.asGeometry().asPolyline()[0] lp2 = self.rubberband.asGeometry().asPolyline()[1] width = 0.2 if QApplication.keyboardModifiers() & Qt.ControlModifier: dlg = QDialog() dlg.setLayout(QGridLayout()) dlg.layout().addWidget(QLabel(self.tr('Enter width'))) txt = QLineEdit('0.2') dlg.layout().addWidget(txt) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) dlg.layout().addWidget(bb) bb.accepted.connect(dlg.accept) bb.rejected.connect(dlg.reject) if dlg.exec_(): try: width = float(txt.text()) except ValueError: width = 0.2 length = math.sqrt( math.pow(lp1.x() - lp2.x(), 2) + math.pow(lp1.y() - lp2.y(), 2)) xd = lp2.x() - lp1.x() yd = lp2.y() - lp1.y() pt1 = QgsPointXY(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length)) pt2 = QgsPointXY(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length)) pt3 = QgsPointXY(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length)) pt4 = QgsPointXY(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length)) self.geometry = QgsGeometry.fromPolygonXY( [[pt1, pt2, pt3, pt4, pt1]]) self.geometryDigitized.emit() self.firstPoint = mousepos
def connect_features(self, source, target): """ Connects the source feature with the target feature. @param source: A QgsPointLocator.Match object. Its foreign key will be updated. A dialog will be opened which asks the user for which foreign key(s) he wants to update. @param target: A QgsPointLocator.Match object. This feature will be used as link target. Its obj_id attribute will be used as primary key. """ dlg = QDialog(self.iface.mainWindow()) dlg.setWindowTitle(self.tr('Select properties to connect')) dlg.setLayout(QFormLayout()) properties = list() for prop in self.network_element_sources[source.layer()]['fields']: if 'filter' in prop.keys(): if not prop['filter'](source, target): continue cbx = QCheckBox(prop['name']) cbx.setObjectName(prop['id']) if 'is_checked' in prop.keys(): cbx.setChecked(prop['is_checked'](source, target)) properties.append(cbx) dlg.layout().addWidget(cbx) btn_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) dlg.layout().addWidget(btn_box) btn_box.accepted.connect(dlg.accept) btn_box.rejected.connect(dlg.reject) source_feature = self.get_feature_for_match(source) target_feature = self.get_feature_for_match(target) if dlg.exec_(): for cbx in properties: if cbx.isChecked(): source_feature[cbx.objectName()] = target_feature['obj_id'] if not source.layer().isEditable(): self.iface.messageBar().pushMessage('QGEP', self.tr('Layer "{layername}" is not in edit mode').format( layername=source.layer().name()), Qgis.Warning, 5) elif source.layer().updateFeature(source_feature): self.iface.messageBar().pushMessage('QGEP', self.tr('Connected {} to {}').format( source_feature['identifier'], target_feature['identifier']), Qgis.Info, 5) else: self.iface.messageBar().pushMessage('QGEP', self.tr( 'Error connecting features'), Qgis.Warning, 5) self.reset()
def widget_dialog(self, widget): dlg = QDialog() widget.setParent(dlg) layout = QVBoxLayout() layout.addWidget(widget) layout.setMargin(6) button_box = QDialogButtonBox(QDialogButtonBox.Close) button_box.rejected.connect(dlg.close) layout.addWidget(button_box) dlg.setLayout(layout) return dlg
def simple_dialog(parent, title, message, checkbox_text=None, yes_no=True): """ A simple dialog the enable you show an html message with checkbox. :param parent: The parent of the dialog. :type parent: QWidget :param title: The title of the dialog :type title: String :param message: The message of the dialog. Use <br> to add a new line as it is html. :type message: String :param checkbox_text: Add a checkbox text, if None, the checkbox will not be shown. :type checkbox_text: String :param yes_no: A boolean to add the Yes No buttons. If false, the Ok button is shown. :type yes_no: Boolean :return: Tuple containing the dialog exec_ result and the checkbox result. :rtype: Tuple """ simple_dialog = QDialog(parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint) simple_layout = QVBoxLayout(simple_dialog) simple_label = QLabel() simple_dialog.setWindowTitle(title) simple_label.setTextFormat(Qt.RichText) simple_label.setText(message) simple_layout.addWidget(simple_label) if checkbox_text: confirm_checkbox = QCheckBox() confirm_checkbox.setText(checkbox_text) simple_layout.addWidget(confirm_checkbox) simple_buttons = QDialogButtonBox() if yes_no: simple_buttons.setStandardButtons(QDialogButtonBox.Yes | QDialogButtonBox.No) simple_buttons.rejected.connect(simple_dialog.reject) else: simple_buttons.setStandardButtons(QDialogButtonBox.Ok) simple_buttons.accepted.connect(simple_dialog.accept) simple_layout.addWidget(simple_buttons) simple_dialog.setModal(True) result = simple_dialog.exec_() if not checkbox_text is None: return result, confirm_checkbox.isChecked() else: return result, False
def _on_tb_btn_clicked(message, tb_text): vbox = QVBoxLayout() dlg = QDialog() dlg.setWindowTitle('Traceback') text_browser = QTextBrowser() unformatted_msg = message formatted_msg = highlight(tb_text, PythonLexer(), HtmlFormatter(full=True)) text_browser.setHtml(unformatted_msg + formatted_msg) vbox.addWidget(text_browser) dlg.setLayout(vbox) dlg.setMinimumSize(700, 500) dlg.exec_()
def __init__(self, iface: QgisInterface): # Save reference to the QGIS interface self.iface = iface # Declare instance attributes self.dlg = QDialog() self.actions = [] self.menu_item = "&Quick API" # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None
def showAdvancedVectorDialog(self): dlg = QDialog() dlg.setObjectName('dbManagerAdvancedVectorDialog') settings = QgsSettings() dlg.restoreGeometry(settings.value("/DB_Manager/advancedAddDialog/geometry", QByteArray(), type=QByteArray)) layout = QFormLayout() dlg.setLayout(layout) dlg.setWindowTitle(self.tr('Add Layer {}').format(self.name)) geometryTypeComboBox = QComboBox() geometryTypeComboBox.addItem(self.tr('Point'), 'POINT') geometryTypeComboBox.addItem(self.tr('Line'), 'LINESTRING') geometryTypeComboBox.addItem(self.tr('Polygon'), 'POLYGON') layout.addRow(self.tr('Geometry Type'), geometryTypeComboBox) zCheckBox = QCheckBox(self.tr('With Z')) mCheckBox = QCheckBox(self.tr('With M')) layout.addRow(zCheckBox) layout.addRow(mCheckBox) crsSelector = QgsProjectionSelectionWidget() crsSelector.setCrs(self.crs()) layout.addRow(self.tr('CRS'), crsSelector) def selectedGeometryType(): geomType = geometryTypeComboBox.currentData() if zCheckBox.isChecked(): geomType += 'Z' if mCheckBox.isChecked(): geomType += 'M' return geomType def selectedCrs(): return crsSelector.crs() addButton = QPushButton(self.tr('Load Layer')) addButton.clicked.connect(lambda: self.addLayer(selectedGeometryType(), selectedCrs())) btns = QDialogButtonBox(QDialogButtonBox.Cancel) btns.addButton(addButton, QDialogButtonBox.ActionRole) layout.addRow(btns) addButton.clicked.connect(dlg.accept) btns.accepted.connect(dlg.accept) btns.rejected.connect(dlg.reject) dlg.exec_() settings = QgsSettings() settings.setValue("/DB_Manager/advancedAddDialog/geometry", dlg.saveGeometry())
def editAuthCfgId(self): dlg = QDialog(self) dlg.setWindowModality(Qt.WindowModal) layout = QVBoxLayout() selector = QgsAuthConfigSelect(self) if self.editAuthCfg.text(): selector.setConfigId(self.editAuthCfg.text()) layout.addWidget(selector) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close) buttonBox.accepted.connect(dlg.accept) buttonBox.rejected.connect(dlg.reject) layout.addWidget(buttonBox) dlg.setLayout(layout) if dlg.exec_(): self.editAuthCfg.setText(selector.configId()) del dlg
def showLabelOptions(self): options = self.labelOptions self.dialog = QDialog() lo = uic.loadUiType(os.path.join(self.path, LABEL_OPTIONS_WIDGET_FILE))[0] self.labelOptionsDialog = lo() self.labelOptionsDialog.setupUi(self.dialog) self.labelOptionsDialog.fontsize.setValue(options.size) self.labelOptionsDialog.time_format.setText(options.fmt) self.labelOptionsDialog.font.setCurrentFont(QFont(options.font)) self.labelOptionsDialog.placement.addItems(TimestampLabelConfig.PLACEMENTS) self.labelOptionsDialog.placement.setCurrentIndex(TimestampLabelConfig.PLACEMENTS.index(options.placement)) self.labelOptionsDialog.text_color.setColor(QColor(options.color)) self.labelOptionsDialog.bg_color.setColor(QColor(options.bgcolor)) self.labelOptionsDialog.buttonBox.accepted.connect(self.saveLabelOptions) self.dialog.show()
def edit_style(self): from qgis.gui import QgsSingleSymbolRendererWidget from qgis.core import QgsStyle style = QgsStyle() sw = QStackedWidget() sw.addWidget for i in range(3): if self.__renderer and i == self.__render_type: w = QgsSingleSymbolRendererWidget(self.__layer, style, self.__renderer) else: w = QgsSingleSymbolRendererWidget(self.__layer, style, self.__default_renderers[i]) sw.addWidget(w) combo = QComboBox() combo.addItem("Points") combo.addItem("Line") combo.addItem("Polygon") combo.currentIndexChanged[int].connect(sw.setCurrentIndex) combo.setCurrentIndex(self.__render_type) dlg = QDialog() vbox = QVBoxLayout() btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn.accepted.connect(dlg.accept) btn.rejected.connect(dlg.reject) vbox.addWidget(combo) vbox.addWidget(sw) vbox.addWidget(btn) dlg.setLayout(vbox) dlg.resize(800, 600) r = dlg.exec_() if r == QDialog.Accepted: self.__render_type = combo.currentIndex() self.__renderer = sw.currentWidget().renderer().clone() self.update() self.style_updated.emit()
def on_copy(self): select_group_dialog = QDialog(self) select_group_dialog.resize(300, 400) select_group_dialog.setWindowTitle(self.tr("Choose source group")) layout = QVBoxLayout(select_group_dialog) select_group_dialog.setLayout(layout) groups_list_view = QTableView(self) layout.addWidget(groups_list_view) groups_list_view.setModel(self.ds_model) groups_list_view.setColumnHidden(DSManagerModel.COLUMN_VISIBILITY, True) groups_list_view.setSelectionMode(QTableView.NoSelection) groups_list_view.setAlternatingRowColors(True) groups_list_view.setShowGrid(False) if hasattr(groups_list_view.horizontalHeader(), "setResizeMode"): # Qt4 groups_list_view.horizontalHeader().setResizeMode( DSManagerModel.COLUMN_GROUP_DS, QHeaderView.Stretch) groups_list_view.verticalHeader().setResizeMode( QHeaderView.ResizeToContents) else: # Qt5 groups_list_view.horizontalHeader().setSectionResizeMode( DSManagerModel.COLUMN_GROUP_DS, QHeaderView.Stretch) groups_list_view.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) groups_list_view.verticalHeader().hide() groups_list_view.clicked.connect( lambda index: select_group_dialog.accept() \ if self.ds_model.isGroup(index) and \ index.column() == DSManagerModel.COLUMN_GROUP_DS \ else None ) if select_group_dialog.exec_() == QDialog.Accepted: group_info = self.ds_model.data(groups_list_view.currentIndex(), Qt.UserRole) group_info.id += "_copy" edit_dialog = GroupEditDialog() edit_dialog.setWindowTitle(self.tr('Create group from existing')) edit_dialog.fill_group_info(group_info) if edit_dialog.exec_() == QDialog.Accepted: self.feel_list() self.ds_model.resetModel()
def on_copy(self): self.ds_model.sort(DSManagerModel.COLUMN_GROUP_DS) select_data_sources_dialog = QDialog(self) select_data_sources_dialog.resize(400, 400) select_data_sources_dialog.setWindowTitle( self.tr("Choose source service")) layout = QVBoxLayout(select_data_sources_dialog) select_data_sources_dialog.setLayout(layout) list_view = QTreeView(self) layout.addWidget(list_view) list_view.setModel(self.ds_model) #list_view.expandAll() list_view.setColumnHidden(DSManagerModel.COLUMN_VISIBILITY, True) list_view.setAlternatingRowColors(True) if hasattr(list_view.header(), "setResizeMode"): # Qt4 list_view.header().setResizeMode(DSManagerModel.COLUMN_GROUP_DS, QHeaderView.ResizeToContents) else: # Qt5 list_view.header().setSectionResizeMode( DSManagerModel.COLUMN_GROUP_DS, QHeaderView.ResizeToContents) list_view.clicked.connect( lambda index: select_data_sources_dialog.accept() \ if not self.ds_model.isGroup(index) and \ index.column() == DSManagerModel.COLUMN_GROUP_DS \ else None ) if select_data_sources_dialog.exec_() == QDialog.Accepted: data_source = self.ds_model.data(list_view.currentIndex(), Qt.UserRole) data_source.id += "_copy" edit_dialog = DsEditDialog() edit_dialog.setWindowTitle(self.tr('Create service from existing')) edit_dialog.fill_ds_info(data_source) if edit_dialog.exec_() == QDialog.Accepted: self.feel_list() self.ds_model.resetModel()
def onConfigureSelectAction(self): dlg = QDialog() dlg.setWindowTitle(self.tr('Selection Options')) dlg.setLayout(QGridLayout()) ww_current_checkbox = QCheckBox(self.tr('Wastewater current')) status, _ = QgsProject.instance().readBoolEntry( 'Qgep', 'FollowWastewaterCurrent', True) ww_current_checkbox.setChecked(status) ww_planned_checkbox = QCheckBox(self.tr('Wastewater planned')) status, _ = QgsProject.instance().readBoolEntry( 'Qgep', 'FollowWastewaterPlanned', True) ww_planned_checkbox.setChecked(status) rw_current_checkbox = QCheckBox(self.tr('Rainwater current')) status, _ = QgsProject.instance().readBoolEntry( 'Qgep', 'FollowRainwaterCurrent', True) rw_current_checkbox.setChecked(status) rw_planned_checkbox = QCheckBox(self.tr('Rainwater planned')) status, _ = QgsProject.instance().readBoolEntry( 'Qgep', 'FollowRainwaterPlanned', True) rw_planned_checkbox.setChecked(status) btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn_box.accepted.connect(dlg.accept) btn_box.rejected.connect(dlg.reject) dlg.layout().addWidget(ww_current_checkbox) dlg.layout().addWidget(ww_planned_checkbox) dlg.layout().addWidget(rw_current_checkbox) dlg.layout().addWidget(rw_planned_checkbox) dlg.layout().addWidget(btn_box) if dlg.exec_(): QgsProject.instance().writeEntry('Qgep', 'FollowWastewaterCurrent', ww_current_checkbox.isChecked()) QgsProject.instance().writeEntry('Qgep', 'FollowWastewaterPlanned', ww_planned_checkbox.isChecked()) QgsProject.instance().writeEntry('Qgep', 'FollowRainwaterCurrent', rw_current_checkbox.isChecked()) QgsProject.instance().writeEntry('Qgep', 'FollowRainwaterPlanned', rw_planned_checkbox.isChecked())
def setupUi(self): self.dlg = QDialog() self.dlg.setWindowTitle("TOMs Export") self.dlg.setWindowModality(Qt.ApplicationModal) self.generalLayout = QVBoxLayout() layerGroup = QGroupBox("Choose layers to export") # add map layer list self.layerList = checkableMapLayerList() vbox1 = QVBoxLayout() vbox1.addWidget(self.layerList) layerGroup.setLayout(vbox1) self.generalLayout.addWidget(layerGroup) # add file chooser outputGroup = QGroupBox("Choose output file") self.fileNameWidget = QgsFileWidget() self.fileNameWidget.setStorageMode(QgsFileWidget.SaveFile) self.fileNameWidget.setFilter( "Geopackage (*.gpkg);;JPEG (*.jpg *.jpeg);;TIFF (*.tif)") self.fileNameWidget.setSelectedFilter("Geopackage (*.gpkg)") vbox2 = QVBoxLayout() vbox2.addWidget(self.fileNameWidget) outputGroup.setLayout(vbox2) self.generalLayout.addWidget(outputGroup) # add buttons self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.dlg.accept) self.buttonBox.rejected.connect(self.dlg.reject) self.generalLayout.addWidget(self.buttonBox) self.dlg.setLayout(self.generalLayout) checkableMapLayerListCtrl(self.layerList)
def setRoundness(self, roundness): self.mRoundness = min(0.0, max(100, roundness)) def setColor(self, color): self.mColor = color def setRevolutionsPerSecond(self, revolutionsPerSecond): self.mRevolutionsPerSecond = revolutionsPerSecond self.updateTimer() def setTrailFadePercentage(self, trail): self.mTrailFadePercentage = trail def setMinimumTrailOpacity(self, minimumTrailOpacity): self.mMinimumTrailOpacity = minimumTrailOpacity if __name__ == '__main__': import sys from PyQt5.QtWidgets import QApplication from qgis.PyQt.QtWidgets import QDialog from qgis.PyQt.QtCore import QRect app = QApplication(sys.argv) dial = QDialog() w = QtWaitingSpinner(dial) dial.show() w.start() QTimer.singleShot(5000, w.stop) sys.exit(app.exec_())
from qgis.PyQt.QtWidgets import QApplication, QDialog, QVBoxLayout @pyqtSlot(float, float) def echo_final_range(low, high): print(f'final... low: {low}, high: {high}') app = QApplication(sys.argv) # app.setStyle(QStyleFactory.create("Macintosh")) app.setStyle(QStyleFactory.create("Fusion")) # app.setStyle(QStyleFactory.create("Windows")) print(f'app styles: {QStyleFactory.keys()}') print(f'app style: {app.style().metaObject().className()}') # wrap in dialog dlg = QDialog() dlg.setWindowTitle('RangeSlider test') layout = QVBoxLayout(dlg) range_slider = PlanetExplorerRangeSlider(parent=dlg, title='My value', filter_key='my_value', prefix='', suffix='˚', minimum=0, maximum=360, low=0, high=360, step=1, precision=1)
def upload_data(self): if self.check_login(): if self.local_data_sources.count() == 0: return if self.db_connections.count() == 0: QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab.")) return if not self.ui.cbUploadDatabase.currentIndex() >= 0: QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data.")) return db_name = self.ui.cbUploadDatabase.currentText() if not self.db_connections.isPortOpen(db_name): uri = self.db_connections.cloud_layer_uri(db_name, "", "") host = str(uri.host()) port = uri.port() QMessageBox.critical(self, self.tr("Network Error"), self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port))) return # disable update of local data sources during upload, as there are # temporary layers added and removed self.do_update_local_data_sources = False self.statusBar().showMessage(self.tr("Uploading data...")) self.setCursor(Qt.WaitCursor) self.ui.btnUploadData.hide() self.ui.spinner.start() self.ui.progressWidget.show() # Map<data_source, {table: table, layers: layers}> data_sources_items = {} for row in range(0, self.ui.tblLocalLayers.rowCount()): data_source = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_DATA_SOURCE).text()) layers = self.local_data_sources.layers(data_source) if layers is not None: table_name = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_TABLE_NAME).text()) data_sources_items[data_source] = { u'table': unicode(table_name), u'layers': layers} login_info = self.api.check_login(version_info=self._version_info()) try: self.maxSize = login_info['max_storage'] self.maxDBs = login_info['max_dbs'] except: self.maxSize = 50 self.maxDBs = 5 try: self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize)) upload_ok = True except Exception as e: ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_() upload_ok = False self.ui.spinner.stop() self.ui.progressWidget.hide() self.ui.btnUploadData.show() self.unsetCursor() self.statusBar().showMessage("") # Refresh local layers self.do_update_local_data_sources = True self.update_local_layers() # Refresh used space after upload self.db_size(self.db_connections) if upload_ok: # Show save project dialog save_dialog = QDialog(self) save_dialog.setWindowTitle(self.tr("Save Project")) save_dialog.setLayout(QVBoxLayout()) header = QWidget() header.setLayout(QVBoxLayout()) label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database.")) label.setWordWrap(True) header.layout().addWidget(label) label = QLabel(self.tr("Choose were to save the modified project:")) label.setWordWrap(True) header.layout().addWidget(label) save_dialog.layout().setContentsMargins(0, 0, 0, 0) save_dialog.layout().addWidget(header) initialPath = QgsProject.instance().fileName() if not initialPath: initialPath = QSettings().value("/UI/lastProjectDir", ".") fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files")) fd.setParent(save_dialog, Qt.Widget) fd.setOption(QFileDialog.DontUseNativeDialog) fd.setAcceptMode(QFileDialog.AcceptSave) save_dialog.layout().addWidget(fd) header.layout().setContentsMargins(fd.layout().contentsMargins()) fd.accepted.connect(save_dialog.accept) fd.rejected.connect(save_dialog.reject) if save_dialog.exec_() == QDialog.Accepted: files = list(fd.selectedFiles()) if files: QgsProject.instance().setFileName(files[0]) self.iface.actionSaveProject().trigger() # Switch to map tab self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
def check_login(self): version_ok = True if not self.api.check_auth(): # res = QMessageBox.information( # self, # self.tr("QGIS 3 message"), # self.tr("""You have started the QGIS Cloud Plugin with QGIS 3. This configuration is not stable and is not intended for productive use. A lot can still change in QGIS before the first QGIS 3 LTR. Therefore, it is possible that the plugin does not work as you expect or terminates with errors. If you need a stable version of QGIS Cloud, please continue working with QGIS 2."""), # QMessageBox.StandardButtons( # QMessageBox.Close)) login_dialog = QDialog(self) login_dialog.ui = Ui_LoginDialog() login_dialog.ui.setupUi(login_dialog) login_dialog.ui.editUser.setText(self.user) login_ok = False while not login_ok and version_ok: self.api.set_url(self.api_url()) if not login_dialog.exec_(): self.api.set_auth( user=login_dialog.ui.editUser.text(), password=None) return login_ok self.api.set_auth( user=login_dialog.ui.editUser.text(), password=login_dialog.ui.editPassword.text()) try: login_info = self.api.check_login( version_info=self._version_info()) # QGIS private Cloud has no tos_accepted try: if not login_info['tos_accepted']: result = QMessageBox.information( None, self.tr("Accept new Privacy Policy"), self.tr("""Due to the GDPR qgiscloud.com has a new <a href='http://qgiscloud.com/en/pages/privacy'> Privacy Policy </a>. To continue using qgiscloud.com, you must accept the new policy. """), QMessageBox.StandardButtons( QMessageBox.No | QMessageBox.Yes)) if result == QMessageBox.No: login_ok = False return else: result = self.api.accept_tos() except: pass self.user = login_dialog.ui.editUser.text() self._update_clouddb_mode(login_info['clouddb']) version_ok = StrictVersion(self.version) >= StrictVersion(login_info['current_plugin']) if not version_ok: self.ui.lblVersionPlugin.setPalette(self.palette_red) QMessageBox.information(None, self.tr('New Version'), self.tr('New plugin release {version} is available! Please upgrade the QGIS Cloud plugin.').format(version=login_info['current_plugin'])) self.store_settings() self.ui.btnLogin.hide() self.ui.lblSignup.hide() self.ui.btnLogout.show() self.ui.widgetDatabases.setEnabled(True) self.ui.widgetMaps.setEnabled(True) self.ui.lblLoginStatus.setText( self.tr("Logged in as {0} ({1})").format(self.user, login_info['plan'])) self.ui.lblLoginStatus.show() self._push_message( self.tr("QGIS Cloud"), self.tr("Logged in as {0}").format(self.user), level=0, duration=2) self.refresh_databases() self.refresh_maps() if not version_ok: self._push_message(self.tr("QGIS Cloud"), self.tr( "Unsupported versions detected. Please check your versions first!"), level=1) version_ok = False self.ui.tabWidget.setCurrentWidget(self.ui.aboutTab) login_ok = True self.update_local_layers() except ForbiddenError: QMessageBox.critical( self, self.tr("Account Disabled"), self.tr("Account {username} is disabled! Please contact [email protected]").format(username=login_dialog.ui.editUser.text())) login_ok = False except UnauthorizedError: QMessageBox.critical( self, self.tr("Login for user {username} failed").format(username=login_dialog.ui.editUser.text()), self.tr("Wrong user name or password")) login_ok = False except (TokenRequiredError, ConnectionException) as e: QMessageBox.critical( self, self.tr("Login failed"), self.tr("Login failed: %s") % str(e)) login_ok = False return version_ok
def installFromZipFile(self, filePath): if not os.path.isfile(filePath): return settings = QgsSettings() settings.setValue(settingsGroup + '/lastZipDirectory', QFileInfo(filePath).absoluteDir().absolutePath()) with zipfile.ZipFile(filePath, 'r') as zf: pluginName = os.path.split(zf.namelist()[0])[0] pluginFileName = os.path.splitext(os.path.basename(filePath))[0] if not pluginName: msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Warning) msg_box.setWindowTitle(self.tr("QGIS Python Install from ZIP Plugin Installer")) msg_box.setText(self.tr("The Zip file is not a valid QGIS python plugin. No root folder was found inside.")) msg_box.setStandardButtons(QMessageBox.Ok) more_info_btn = msg_box.addButton(self.tr("More Information"), QMessageBox.HelpRole) msg_box.exec() if msg_box.clickedButton() == more_info_btn: QgsHelp.openHelp("plugins/plugins.html#the-install-from-zip-tab") return pluginsDirectory = qgis.utils.home_plugin_path if not QDir(pluginsDirectory).exists(): QDir().mkpath(pluginsDirectory) pluginDirectory = QDir.cleanPath(os.path.join(pluginsDirectory, pluginName)) # If the target directory already exists as a link, # remove the link without resolving QFile(pluginDirectory).remove() password = None infoString = None success = False keepTrying = True while keepTrying: try: # Test extraction. If fails, then exception will be raised and no removing occurs unzip(filePath, pluginsDirectory, password) # Removing old plugin files if exist removeDir(pluginDirectory) # Extract new files unzip(filePath, pluginsDirectory, password) keepTrying = False success = True except Exception as e: success = False if 'password' in str(e): infoString = self.tr('Aborted by user') if 'Bad password' in str(e): msg = self.tr('Wrong password. Please enter a correct password to the zip file.') else: msg = self.tr('The zip file is encrypted. Please enter password.') # Display a password dialog with QgsPasswordLineEdit dlg = QDialog() dlg.setWindowTitle(self.tr('Enter password')) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal) buttonBox.rejected.connect(dlg.reject) buttonBox.accepted.connect(dlg.accept) lePass = QgsPasswordLineEdit() layout = QVBoxLayout() layout.addWidget(QLabel(msg)) layout.addWidget(lePass) layout.addWidget(buttonBox) dlg.setLayout(layout) keepTrying = dlg.exec_() password = lePass.text() else: infoString = self.tr("Failed to unzip the plugin package\n{}.\nProbably it is broken".format(filePath)) keepTrying = False if success: updateAvailablePlugins() self.processDependencies(pluginName) loadPlugin(pluginName) plugins.getAllInstalled() plugins.rebuild() if settings.contains('/PythonPlugins/' + pluginName): if settings.value('/PythonPlugins/' + pluginName, False, bool): startPlugin(pluginName) reloadPlugin(pluginName) else: unloadPlugin(pluginName) loadPlugin(pluginName) else: if startPlugin(pluginName): settings.setValue('/PythonPlugins/' + pluginName, True) self.exportPluginsToManager() msg = "<b>%s</b>" % self.tr("Plugin installed successfully") else: msg = "<b>%s:</b> %s" % (self.tr("Plugin installation failed"), infoString) level = Qgis.Info if success else Qgis.Critical iface.pluginManagerInterface().pushMessage(msg, level)
def on_resolve_href(dialog, layer, feature, field): """ @param dialog the dialog where the feature form is opened @param layer the layer on which the href link stands @param feature the current feature @param field the field name storing the href URL @param linked_layer_id the QGIS layer id of the already resolved layer, for update """ from .import_gmlas_panel import ImportGmlasPanel path = feature[field] if not path: return # if parent is a Dialog, we are in a feature form # else in a attribute table is_feature_form = isinstance(dialog.parent, QDialog) # The href is resolved thanks to the OGR GMLAS driver. # We need to determine what is the "root" layer of the imported # href, so that we can connect the xlink:href link to the # newly loaded set of layers. # There seems to be no way to determine what is the "root" layer # of a GMLAS database. # So, we rely on XML parsing to determine the root element # and on layer xpath found in metadata # Download the file so that it is used for XML parsing # and for GMLAS loading from ..core.qgis_urlopener import remote_open_from_qgis from ..core.gml_utils import extract_features from ..core.xml_utils import xml_root_tag, no_ns, no_prefix import tempfile with remote_open_from_qgis(path) as fi: with tempfile.NamedTemporaryFile(delete=False) as fo: fo.write(fi.read()) tmp_file = fo.name with open(tmp_file, 'r') as file_io: root_tag = xml_root_tag(file_io) # reuse the GMLAS import panel widget dlg = QDialog() import_widget = ImportGmlasPanel(dlg, gml_path=tmp_file) path_edit = QLineEdit(path, dlg) path_edit.setEnabled(False) btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dlg) layout = QVBoxLayout() layout.addWidget(path_edit) layout.addWidget(import_widget) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) layout.addWidget(btn) dlg.setLayout(layout) btn.accepted.connect(dlg.accept) btn.rejected.connect(dlg.reject) dlg.resize(400, 300) dlg.setWindowTitle("Options for xlink:href loading") if not dlg.exec_(): return # close the current form w = dialog while not isinstance(w, QDialog): w = w.parent() w.close() import_widget.do_load() # Add a link between the current layer # and the root layer of the newly loaded (complex) features # 1. determine the root layer and pkid of all its features root_layer = None for l in QgsProject.instance().mapLayers().values(): if no_ns(l.customProperty("xpath", "")) == no_prefix(root_tag): root_layer = l break if root_layer is None: raise RuntimeError("Cannot determine the root layer") pkid = layer.customProperty("pkid") pkid_value = feature[pkid] root_layer.startEditing() # 2. add a href_origin_pkid field in the root layer if "parent_href_pkid" not in [f.name() for f in root_layer.fields()]: new_field = QgsField(layer.fields().field(pkid)) new_field.setName("parent_href_pkid") root_layer.addAttribute(new_field) # 3. set its value to the id of current feature ids_to_change = [] for f in root_layer.getFeatures(): if f["parent_href_pkid"] is None: ids_to_change.append(f.id()) idx = root_layer.fields().indexFromName("parent_href_pkid") for fid in ids_to_change: # sets the pkid_value root_layer.changeAttributeValue(fid, idx, pkid_value) root_layer.commitChanges() # 4. declare a new QgsRelation rel_name = "1_n_" + layer.name() + "_" + field rel = QgsProject.instance().relationManager().relations().get(rel_name) if rel is None: rel = QgsRelation() rel.setId(rel_name) rel.setName(field) rel.setReferencedLayer(layer.id()) rel.setReferencingLayer(root_layer.id()) rel.addFieldPair("parent_href_pkid", pkid) QgsProject.instance().relationManager().addRelation(rel) # 5. declare the new relation in the form widgets # new 1:N in the current layer fc = layer.editFormConfig() rel_tab = fc.tabs()[1] rel_tab.addChildElement( QgsAttributeEditorRelation(rel.name(), rel, rel_tab)) # new field in the root layer fc = root_layer.editFormConfig() main_tab = fc.tabs()[0] main_tab.addChildElement( QgsAttributeEditorField("parent_href_pkid", idx, main_tab)) # declare as reference relation widget s = QgsEditorWidgetSetup( "RelationReference", { 'AllowNULL': False, 'ReadOnly': True, 'Relation': rel.id(), 'OrderByValue': False, 'MapIdentification': False, 'AllowAddFeatures': False, 'ShowForm': True }) root_layer.setEditorWidgetSetup(idx, s) # write metadata in layers href_resolved = layer.customProperty("href_resolved", []) if path not in href_resolved: layer.setCustomProperty("href_resolved", href_resolved + [path]) href_linked_layers = layer.customProperty("href_linked_layers", {}) href_linked_layers[field] = root_layer.id() layer.setCustomProperty("href_linked_layers", href_linked_layers) # 6. reload the current form from ..main import get_iface if is_feature_form: get_iface().openFeatureForm(layer, feature) else: get_iface().showAttributeTable(layer)
def run(self): """Run method that loads and starts the plugin""" if not self.pluginIsActive: self.pluginIsActive = True #print "** STARTING MsdcClient" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = MsdcClientDockWidget() self.dockwidget.loginBtn.clicked.connect(self.show_loginDiag) self.dockwidget.importBtn.clicked.connect(self.show_importDiag) self.dockwidget.exportBtn.clicked.connect(self.show_exportDiag) #self.dockwidget.imageryBtn.clicked.connect(self.showImageryDiag) # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # show the dockwidget self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget) self.dockwidget.show() if self.logindiag == None: self.loginDialog = QDialog() self.logindiag = Ui_LoginDialog() self.logindiag.setupUi(self.loginDialog) self.loginbtn = self.logindiag.loginBtn2 self.loginbtn.clicked.connect(self.login_action) self.exitBtn = self.logindiag.exitBtn2 self.exitBtn.clicked.connect(self.exit_logindiag) if self.importdiag == None: self.importDialog = QDialog() self.importdiag = Ui_importDiag() self.importdiag.setupUi(self.importDialog) # browse button self.browsebtn = self.importdiag.browseBtn1 self.browsebtn.clicked.connect(self.browse_imports) # exit button self.closeBtn = self.importdiag.closeBtn2 self.closeBtn.clicked.connect(self.exit_importdiag) # remove selected button self.removeBtn = self.importdiag.removeBtn self.removeBtn.clicked.connect(self.remove_selected) # clear list button self.clearBtn = self.importdiag.clearBtn self.clearBtn.clicked.connect(self.clear_list) # import data button self.importBtn2 = self.importdiag.importBtn2 self.importBtn2.clicked.connect(self.import_mobiledata) if self.exportdiag == None: self.exportDialog = QDialog() self.exportdiag = Ui_exportdataDiag() self.exportdiag.setupUi(self.exportDialog) # browse button self.browseExports = self.exportdiag.browseExports self.browseExports.clicked.connect(self.browse_exports) # exit button self.cancelBtn = self.exportdiag.cancelBtn self.cancelBtn.clicked.connect(self.exit_exportdiag) # clear list button self.clearExports = self.exportdiag.clearExports self.clearExports.clicked.connect(self.clear_export_list) # export data button self.exportBtn = self.exportdiag.exportBtn self.exportBtn.clicked.connect(self.export_mobiledata) if self.imagerydiag == None: self.imageryDialog = QDialog() self.imagerydiag = Ui_imageryDiag() self.imagerydiag.setupUi(self.imageryDialog)