def initGui(self): verticalLayout = QVBoxLayout() verticalLayout.setSpacing(2) verticalLayout.setMargin(0) verticalLayout2 = QVBoxLayout() verticalLayout2.setSpacing(2) verticalLayout2.setMargin(15) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(10) horizontalLayout.setMargin(0) self.branchRadio = QRadioButton('Branch', self) self.branchRadio.toggled.connect(self.branchRadioClicked) self.branchRadio.setMaximumWidth(200) self.branchRadio.setMinimumWidth(200) horizontalLayout.addWidget(self.branchRadio) self.comboBranch = QComboBox() for branch in self.repo.branches(): self.comboBranch.addItem(branch) self.comboBranch.setMinimumWidth(200) horizontalLayout.addWidget(self.comboBranch) verticalLayout2.addLayout(horizontalLayout) horizontalLayout2 = QHBoxLayout() horizontalLayout2.setSpacing(10) horizontalLayout2.setMargin(0) self.tagRadio = QRadioButton('Tag', self) self.tagRadio.toggled.connect(self.tagRadioClicked) self.tagRadio.setMaximumWidth(200) self.tagRadio.setMinimumWidth(200) horizontalLayout2.addWidget(self.tagRadio) self.comboTag = QComboBox() for tag, commitid in self.repo.tags().items(): self.comboTag.addItem(str(tag), commitid) horizontalLayout2.addWidget(self.comboTag) verticalLayout2.addLayout(horizontalLayout2) horizontalLayout3 = QHBoxLayout() horizontalLayout3.setSpacing(10) horizontalLayout3.setMargin(0) self.commitRadio = QRadioButton('Version', self) self.commitRadio.toggled.connect(self.commitRadioClicked) self.commitRadio.setMaximumWidth(200) self.commitRadio.setMinimumWidth(200) horizontalLayout3.addWidget(self.commitRadio) self.comboCommit = QComboBox() log = self.repo.log(limit=100) for commit in log: self.comboCommit.addItem(commit.message.split("\n")[0], commit) horizontalLayout3.addWidget(self.comboCommit) verticalLayout2.addLayout(horizontalLayout3) groupBox = QGroupBox("Reference") groupBox.setLayout(verticalLayout2) verticalLayout.addWidget(groupBox) self.setLayout(verticalLayout) self.branchRadio.setChecked(True)
class UserConfigDialog(QDialog): def __init__(self, parent = None): super(UserConfigDialog, self).__init__(parent) self.user = None self.email = None self.initGui() def initGui(self): self.setWindowTitle('GeoGig user configuration') verticalLayout = QVBoxLayout() horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) usernameLabel = QLabel('Username') self.usernameBox = QLineEdit() horizontalLayout.addWidget(usernameLabel) horizontalLayout.addWidget(self.usernameBox) verticalLayout.addLayout(horizontalLayout) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) emailLabel = QLabel('User email') self.emailBox = QLineEdit() horizontalLayout.addWidget(emailLabel) horizontalLayout.addWidget(self.emailBox) verticalLayout.addLayout(horizontalLayout) self.groupBox = QGroupBox() self.groupBox.setTitle("User data") self.groupBox.setLayout(verticalLayout) layout = QVBoxLayout() layout.addWidget(self.groupBox) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(self.buttonBox) self.setLayout(layout) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.resize(400, 200) def okPressed(self): self.user = str(self.usernameBox.text()) self.email = str(self.emailBox.text()) self.close() def cancelPressed(self): self.user = None self.email = None self.close()
class UserConfigDialog(QDialog): def __init__(self, parent = None): super(UserConfigDialog, self).__init__(parent) self.user = None self.email = None self.initGui() def initGui(self): self.setWindowTitle('GeoGig user configuration') verticalLayout = QVBoxLayout() horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) usernameLabel = QLabel('Username') self.usernameBox = QLineEdit() horizontalLayout.addWidget(usernameLabel) horizontalLayout.addWidget(self.usernameBox) verticalLayout.addLayout(horizontalLayout) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) emailLabel = QLabel('User email') self.emailBox = QLineEdit() horizontalLayout.addWidget(emailLabel) horizontalLayout.addWidget(self.emailBox) verticalLayout.addLayout(horizontalLayout) self.groupBox = QGroupBox() self.groupBox.setTitle("User data") self.groupBox.setLayout(verticalLayout) layout = QVBoxLayout() layout.addWidget(self.groupBox) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(self.buttonBox) self.setLayout(layout) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.resize(400, 200) def okPressed(self): self.user = self.usernameBox.text() self.email = self.emailBox.text() self.close() def cancelPressed(self): self.user = None self.email = None self.close()
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 grupIntervals(self): group = QGroupBox('Definició dels intervals') # group.setMinimumWidth(400) layout = QGridLayout() layout.setSpacing(10) # layout.setColumnMinimumWidth(4, 40) numFilas = len(self.wInterval) for fila, widgets in enumerate(self.wInterval): for col, w in enumerate(widgets): # Primera fila: solo + if fila == 0 and col > 3: w.setVisible(False) # # Ultima fila: no hay + ni - elif fila > 0 and fila == (numFilas - 1) and col > 2: w.setVisible(False) else: w.setVisible(True) # Valor inicial deshabilitado (menos 1a fila) if col == 0 and fila != 0: w.setDisabled(True) w.setProperty('Fila', fila) layout.addWidget(w, fila, col) group.setLayout(layout) return group
class QvFormSimbMapificacio(QvFormBaseMapificacio): def __init__(self, llegenda, capa=None, amplada=500): super().__init__(llegenda, amplada) if capa is None: self.capa = llegenda.currentLayer() else: self.capa = capa self.info = None if not self.iniParams(): return self.setWindowTitle('Modificar mapa simbòlic ' + self.renderParams.tipusMapa.lower()) self.layout = QVBoxLayout() self.layout.setSpacing(14) self.setLayout(self.layout) self.color = QComboBox(self) self.color.setEditable(False) self.comboColors(self.color) self.contorn = QComboBox(self) self.contorn.setEditable(False) self.comboColors(self.contorn, mv.MAP_CONTORNS) self.color.currentIndexChanged.connect(self.canviaContorns) self.metode = QComboBox(self) self.metode.setEditable(False) if self.renderParams.numCategories > 1: self.metode.addItems(mv.MAP_METODES_MODIF.keys()) else: self.metode.addItems(mv.MAP_METODES.keys()) self.metode.setCurrentIndex(-1) self.metode.currentIndexChanged.connect(self.canviaMetode) self.nomIntervals = QLabel("Nombre d'intervals:", self) self.intervals = QSpinBox(self) self.intervals.setMinimum(min(2, self.renderParams.numCategories)) self.intervals.setMaximum(max(mv.MAP_MAX_CATEGORIES, self.renderParams.numCategories)) self.intervals.setSingleStep(1) self.intervals.setValue(4) if self.renderParams.tipusMapa == 'Àrees': self.intervals.setSuffix(" (depèn del mètode)") # self.intervals.valueChanged.connect(self.deselectValue) self.nomTamany = QLabel("Tamany cercle:", self) self.tamany = QSpinBox(self) self.tamany.setMinimum(1) self.tamany.setMaximum(12) self.tamany.setSingleStep(1) self.tamany.setValue(4) self.bInfo = QPushButton('Info') self.bInfo.clicked.connect(self.veureInfo) self.buttons = QDialogButtonBox() self.buttons.addButton(QDialogButtonBox.Ok) self.buttons.accepted.connect(self.accept) self.buttons.addButton(QDialogButtonBox.Cancel) self.buttons.rejected.connect(self.cancel) self.buttons.addButton(self.bInfo, QDialogButtonBox.ResetRole) self.gSimb = QGroupBox('Simbologia del mapa') self.lSimb = QFormLayout() self.lSimb.setSpacing(14) self.gSimb.setLayout(self.lSimb) self.lSimb.addRow('Color base:', self.color) self.lSimb.addRow('Color contorn:', self.contorn) if self.renderParams.tipusMapa == 'Àrees': self.lSimb.addRow('Mètode classificació:', self.metode) self.lSimb.addRow(self.nomIntervals, self.intervals) self.nomTamany.setVisible(False) self.tamany.setVisible(False) else: self.metode.setVisible(False) self.nomIntervals.setVisible(False) self.intervals.setVisible(False) self.lSimb.addRow(self.nomTamany, self.tamany) self.wInterval = [] for w in self.iniIntervals(): self.wInterval.append(w) self.gInter = self.grupIntervals() self.layout.addWidget(self.gSimb) if self.renderParams.tipusMapa == 'Àrees': self.layout.addWidget(self.gInter) self.layout.addWidget(self.buttons) self.valorsInicials() def iniParams(self): self.info = QgsExpressionContextUtils.layerScope(self.capa).variable(mv.MAP_ID) if self.info is None: return False self.renderParams = QvMapRendererParams.fromLayer(self.capa) if self.renderParams.msgError == '': self.custom = (self.renderParams.modeCategories == 'Personalitzat') return True else: self.msgInfo("No s'han pogut recuperar els paràmetres del mapa simbòlic\n\n" + "Error: " + self.renderParams.msgError) return False @pyqtSlot() def veureInfo(self): if self.info is not None: box = QMessageBox(self) box.setWindowTitle('Info del mapa simbòlic') txt = '<table width="600">' params = self.info.split('\n') for param in params: linea = param.strip() if linea.endswith(':'): linea += ' ---' txt += '<tr><td><nobr>· {}</nobr></td></tr>'.format(linea) txt += '</table>' box.setTextFormat(Qt.RichText) box.setText("Paràmetres d'agregació de dades:") box.setInformativeText(txt) box.setIcon(QMessageBox.Information) box.setStandardButtons(QMessageBox.Ok) box.setDefaultButton(QMessageBox.Ok) box.exec() def valorsInicials(self): self.color.setCurrentIndex(self.color.findText(self.renderParams.colorBase)) self.contorn.setCurrentIndex(self.contorn.findText(self.renderParams.colorContorn)) self.intervals.setValue(self.renderParams.numCategories) self.tamany.setValue(self.renderParams.increase) self.metode.setCurrentIndex(self.metode.findText(self.renderParams.modeCategories)) def valorsFinals(self): self.renderParams.colorBase = self.color.currentText() self.renderParams.colorContorn = self.contorn.currentText() self.renderParams.modeCategories = self.metode.currentText() self.renderParams.numCategories = self.intervals.value() self.renderParams.increase = self.tamany.value() if self.custom: self.renderParams.rangsCategories = [] for fila in self.wInterval: self.renderParams.rangsCategories.append((fila[0].text(), fila[2].text())) self.renderParams.numCategories = len(self.renderParams.rangsCategories) def txtRang(self, num): if type(num) == str: return num return QvApp().locale.toString(num, 'f', self.renderParams.numDecimals) def iniFilaInterval(self, iniValor, finValor): maxSizeB = 27 # validator = QDoubleValidator(self) # validator.setLocale(QvApp().locale) # validator.setNotation(QDoubleValidator.StandardNotation) # validator.setDecimals(5) validator = QvVerifNumero(self) ini = QLineEdit(self) ini.setText(self.txtRang(iniValor)) ini.setValidator(validator) sep = QLabel('-', self) fin = QLineEdit(self) fin.setText(self.txtRang(finValor)) fin.setValidator(validator) fin.editingFinished.connect(self.nouTall) add = QPushButton('+', self) add.setMaximumSize(maxSizeB, maxSizeB) add.setToolTip('Afegeix nou interval') add.clicked.connect(self.afegirFila) add.setFocusPolicy(Qt.NoFocus) rem = QPushButton('-', self) rem.setMaximumSize(maxSizeB, maxSizeB) rem.setToolTip('Esborra interval') rem.clicked.connect(self.eliminarFila) rem.setFocusPolicy(Qt.NoFocus) return [ini, sep, fin, add, rem] def iniIntervals(self): for cat in self.renderParams.rangsCategories: yield self.iniFilaInterval(cat.lowerValue(), cat.upperValue()) def grupIntervals(self): group = QGroupBox('Definició dels intervals') # group.setMinimumWidth(400) layout = QGridLayout() layout.setSpacing(10) # layout.setColumnMinimumWidth(4, 40) numFilas = len(self.wInterval) for fila, widgets in enumerate(self.wInterval): for col, w in enumerate(widgets): # Primera fila: solo + if fila == 0 and col > 3: w.setVisible(False) # # Ultima fila: no hay + ni - elif fila > 0 and fila == (numFilas - 1) and col > 2: w.setVisible(False) else: w.setVisible(True) # Valor inicial deshabilitado (menos 1a fila) if col == 0 and fila != 0: w.setDisabled(True) w.setProperty('Fila', fila) layout.addWidget(w, fila, col) group.setLayout(layout) return group def actGrupIntervals(self): self.intervals.setValue(len(self.wInterval)) self.setUpdatesEnabled(False) self.buttons.setVisible(False) self.gInter.setVisible(False) self.layout.removeWidget(self.buttons) self.layout.removeWidget(self.gInter) self.gInter.deleteLater() self.gInter = self.grupIntervals() self.layout.addWidget(self.gInter) self.layout.addWidget(self.buttons) self.gInter.setVisible(True) self.buttons.setVisible(True) self.adjustSize() self.setUpdatesEnabled(True) @pyqtSlot() def afegirFila(self): masFilas = (len(self.wInterval) < mv.MAP_MAX_CATEGORIES) if masFilas: f = self.sender().property('Fila') + 1 ini = self.wInterval[f][0] val = ini.text() ini.setText('') w = self.iniFilaInterval(val, '') self.wInterval.insert(f, w) self.actGrupIntervals() self.wInterval[f][2].setFocus() else: self.msgInfo("S'ha arribat al màxim d'intervals possibles") @pyqtSlot() def eliminarFila(self): f = self.sender().property('Fila') ini = self.wInterval[f][0] val = ini.text() del self.wInterval[f] ini = self.wInterval[f][0] ini.setText(val) self.actGrupIntervals() @pyqtSlot() def nouTall(self): w = self.sender() if w.isModified(): f = w.property('Fila') + 1 if f < len(self.wInterval): ini = self.wInterval[f][0] ini.setText(w.text()) w.setModified(False) @pyqtSlot() def canviaMetode(self): self.custom = (self.metode.currentText() == 'Personalitzat') if self.custom: self.intervals.setValue(len(self.wInterval)) self.intervals.setEnabled(not self.custom) self.gInter.setVisible(self.custom) self.adjustSize() # print('GSIMB -> Ancho:', self.gSimb.size().width(), '- Alto:', self.gSimb.size().height()) # print('FORM -> Ancho:', self.size().width(), '- Alto:', self.size().height()) @pyqtSlot() def canviaContorns(self): self.comboColors(self.contorn, mv.MAP_CONTORNS, mv.MAP_COLORS[self.color.currentText()], True) def leSelectFocus(self, wLineEdit): lon = len(wLineEdit.text()) if lon > 0: wLineEdit.setSelection(0, lon) wLineEdit.setFocus() def validaNum(self, wLineEdit): val = wLineEdit.validator() if val is None: return True res = val.validate(wLineEdit.text(), 0) if res[0] == QValidator.Acceptable: return True else: self.msgInfo("Cal introduir un nombre enter o amb decimals.\n" "Es farà servir la coma (,) per separar els decimals.\n" "I pels milers, opcionalment, el punt (.)") self.leSelectFocus(wLineEdit) return False def validaInterval(self, wLineEdit1, wLineEdit2): num1, _ = QvApp().locale.toFloat(wLineEdit1.text()) num2, _ = QvApp().locale.toFloat(wLineEdit2.text()) if num2 >= num1: return True else: self.msgInfo("El segon nombre de l'interval ha de ser major que el primer") self.leSelectFocus(wLineEdit2) return False def validaFila(self, fila): wLineEdit1 = fila[0] wLineEdit2 = fila[2] if not self.validaNum(wLineEdit1): return False if not self.validaNum(wLineEdit2): return False if not self.validaInterval(wLineEdit1, wLineEdit2): return False return True def valida(self): if self.custom: for fila in self.wInterval: if not self.validaFila(fila): return False return True def procesa(self): self.valorsFinals() try: mapRenderer = self.renderParams.mapRenderer(self.llegenda) if self.custom: self.renderParams.colorBase = mv.MAP_COLORS[self.renderParams.colorBase] self.renderParams.colorContorn = mv.MAP_CONTORNS[self.renderParams.colorContorn] self.renderer = mapRenderer.customRender(self.capa) else: self.renderParams.colorBase = mv.MAP_COLORS[self.renderParams.colorBase] if self.renderParams.colorContorn == 'Base': self.renderParams.colorContorn = self.renderParams.colorBase else: self.renderParams.colorContorn = mv.MAP_CONTORNS[self.renderParams.colorContorn] self.renderParams.modeCategories = \ mv.MAP_METODES_MODIF[self.renderParams.modeCategories] self.renderer = mapRenderer.calcRender(self.capa) if self.renderer is None: return "No s'ha pogut elaborar el mapa simbòlic" err = self.llegenda.saveStyleToGeoPackage(self.capa, mv.MAP_ID) if err != '': return "Hi ha hagut problemes al desar la simbologia\n({})".format(err) # self.llegenda.modificacioProjecte('mapModified') return '' except Exception as e: return "No s'ha pogut modificar el mapa simbòlic\n({})".format(str(e))
def getGroupBox(name, parent, widgets): lyt = getLayout( parent, widgets ) gbx = QGroupBox(name, parent ) gbx.setLayout( lyt ) return gbx
def api_catalog(self, previous_dialog, widget_name, geom_type, feature_type): # Manage if geom_type is gully and set grate if geom_type == 'gully': geom_type == 'grate' form_name = 'upsert_catalog_' + geom_type + '' form = f'"formName":"{form_name}", "tabName":"data", "editable":"TRUE"' feature = f'"feature_type":"{feature_type}"' body = self.create_body(form, feature) sql = f"SELECT gw_fct_getcatalog({body})::text" row = self.controller.get_row(sql, log_sql=True) if not row: self.controller.show_message("NOT ROW FOR: " + sql, 2) return complet_list = [json.loads(row[0], object_pairs_hook=OrderedDict)] groupBox_1 = QGroupBox("Filter") self.filter_form = QGridLayout() self.dlg_catalog = InfoCatalogUi() self.load_settings(self.dlg_catalog) self.dlg_catalog.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_catalog)) self.dlg_catalog.btn_accept.clicked.connect( partial(self.fill_geomcat_id, previous_dialog, widget_name)) main_layout = self.dlg_catalog.widget.findChild( QGridLayout, 'main_layout') result = complet_list[0]['body']['data'] for field in result['fields']: label = QLabel() label.setObjectName('lbl_' + field['label']) label.setText(field['label'].capitalize()) widget = None if field['widgettype'] == 'combo': widget = self.add_combobox(self.dlg_catalog, field) if field['layoutname'] == 'lyt_data_1': self.filter_form.addWidget(label, field['layoutorder'], 0) self.filter_form.addWidget(widget, field['layoutorder'], 1) groupBox_1.setLayout(self.filter_form) main_layout.addWidget(groupBox_1) verticalSpacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) main_layout.addItem(verticalSpacer1) matcat_id = self.dlg_catalog.findChild(QComboBox, 'matcat_id') pnom = None dnom = None if self.controller.get_project_type() == 'ws': pnom = self.dlg_catalog.findChild(QComboBox, 'pnom') dnom = self.dlg_catalog.findChild(QComboBox, 'dnom') elif self.controller.get_project_type() == 'ud': pnom = self.dlg_catalog.findChild(QComboBox, 'shape') dnom = self.dlg_catalog.findChild(QComboBox, 'geom1') id = self.dlg_catalog.findChild(QComboBox, 'id') # Call get_api_catalog first time self.get_api_catalog(matcat_id, pnom, dnom, id, feature_type, geom_type) # Set Listeners matcat_id.currentIndexChanged.connect( partial(self.populate_pn_dn, matcat_id, pnom, dnom, feature_type, geom_type)) pnom.currentIndexChanged.connect( partial(self.get_api_catalog, matcat_id, pnom, dnom, id, feature_type, geom_type)) dnom.currentIndexChanged.connect( partial(self.get_api_catalog, matcat_id, pnom, dnom, id, feature_type, geom_type)) # Open form self.open_dialog(self.dlg_catalog, dlg_name='info_catalog')
def restore_default_values_page(self): """Setup UI for default values setting.""" # Clear parameters so it doesn't add parameters when # restore from changes. if self.default_value_parameters: self.default_value_parameters = [] if self.default_value_parameter_containers: self.default_value_parameter_containers = [] for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) default_fields = all_default_fields() for field_group in all_field_groups: settable_fields = [] for field in field_group['fields']: if field not in default_fields: continue else: settable_fields.append(field) default_fields.remove(field) if not settable_fields: continue # Create group box for each field group group_box = QGroupBox(self) group_box.setTitle(field_group['name']) self.container_layout.addWidget(group_box) parameters = [] for settable_field in settable_fields: parameter = self.default_field_to_parameter(settable_field) if parameter: parameters.append(parameter) parameter_container = ParameterContainer( parameters, description_text=field_group['description'], extra_parameters=extra_parameter ) parameter_container.setup_ui(must_scroll=False) group_box_inner_layout = QVBoxLayout() group_box_inner_layout.addWidget(parameter_container) group_box.setLayout(group_box_inner_layout) # Add to attribute self.default_value_parameter_containers.append(parameter_container) # Only show non-groups default fields if there is one if len(default_fields) > 0: for default_field in default_fields: parameter = self.default_field_to_parameter(default_field) if parameter: self.default_value_parameters.append(parameter) description_text = tr( 'In this options you can change the global default values for ' 'these variables.') parameter_container = ParameterContainer( self.default_value_parameters, description_text=description_text, extra_parameters=extra_parameter ) parameter_container.setup_ui(must_scroll=False) self.other_group_box = QGroupBox(tr('Non-group fields')) other_group_inner_layout = QVBoxLayout() other_group_inner_layout.addWidget(parameter_container) self.other_group_box.setLayout(other_group_inner_layout) self.container_layout.addWidget(self.other_group_box) # Add to attribute self.default_value_parameter_containers.append(parameter_container)
class OptionsDialog(QDialog, FORM_CLASS): """Options dialog for the InaSAFE plugin.""" def __init__(self, iface, parent=None, qsetting=''): """Constructor for the dialog. :param iface: A Quantum GIS QgisAppInterface instance. :type iface: QgisAppInterface :param parent: Parent widget of this dialog :type parent: QWidget :param qsetting: String to specify the QSettings. By default, use empty string. :type qsetting: str """ QDialog.__init__(self, parent) self.setupUi(self) icon = resources_path('img', 'icons', 'configure-inasafe.svg') self.setWindowIcon(QIcon(icon)) self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version())) # Save reference to the QGIS interface and parent self.iface = iface self.parent = parent if qsetting: self.settings = QSettings(qsetting) else: self.settings = QSettings() # InaSAFE default values self.default_value_parameters = [] self.default_value_parameter_containers = [] # Flag for restore default values self.is_restore_default = False # List of setting key and control self.boolean_settings = { 'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly, 'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle, 'setZoomToImpactFlag': self.cbxZoomToImpact, 'set_show_only_impact_on_report': self.cbx_show_only_impact, 'print_atlas_report': self.cbx_print_atlas_report, 'setHideExposureFlag': self.cbxHideExposure, 'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly, 'useSentry': self.cbxUseSentry, 'template_warning_verbose': self.template_warning_checkbox, 'showOrganisationLogoInDockFlag': self.organisation_on_dock_checkbox, 'developer_mode': self.cbxDevMode, 'generate_report': self.checkbox_generate_reports, 'memory_profile': self.check_box_memory, 'always_show_welcome_message': self.welcome_message_check_box } self.text_settings = { 'keywordCachePath': self.leKeywordCachePath, 'ISO19115_ORGANIZATION': self.organisation_line_edit, 'ISO19115_URL': self.website_line_edit, 'ISO19115_EMAIL': self.email_line_edit, 'ISO19115_LICENSE': self.license_line_edit, } # Export and Import button # Export button self.export_button = QPushButton(tr('Export')) # noinspection PyUnresolvedReferences self.export_button.clicked.connect(self.export_setting) self.button_box.addButton(self.export_button, QDialogButtonBox.ActionRole) # Import button self.import_button = QPushButton(tr('Import')) # noinspection PyUnresolvedReferences self.import_button.clicked.connect(self.import_setting) self.button_box.addButton(self.import_button, QDialogButtonBox.ActionRole) # Set up things for context help self.help_button = self.button_box.button(QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) self.main_stacked_widget.setCurrentIndex(1) # Always set first tab to be open, 0-th index self.tabWidget.setCurrentIndex(0) # Hide not implemented group self.grpNotImplemented.hide() self.adjustSize() # Population parameter Tab # Label self.preference_label = QLabel() self.preference_label.setText( tr('Please set parameters for each hazard class below. Affected ' 'status and displacement rates selected on this tab are only ' 'applied to exposed populations. ')) self.preference_layout.addWidget(self.preference_label) # Profile preference widget self.profile_widget = ProfileWidget() self.preference_layout.addWidget(self.profile_widget) # Demographic tab self.demographic_label = QLabel() self.demographic_label.setText( tr('Please set the global default demographic ratio below.')) self.default_values_layout.addWidget(self.demographic_label) self.scroll_area = QScrollArea() self.scroll_area.setWidgetResizable(True) self.widget_container = QWidget() self.scroll_area.setWidget(self.widget_container) self.container_layout = QVBoxLayout() self.widget_container.setLayout(self.container_layout) self.default_values_layout.addWidget(self.scroll_area) # Restore state from setting self.restore_state() # Hide checkbox if not developers if not self.cbxDevMode.isChecked(): self.checkbox_generate_reports.hide() # Connections # Check boxes self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow) self.custom_UseUserDirectory_checkbox.toggled.connect( self.set_user_dir) self.custom_templates_dir_checkbox.toggled.connect( self.set_templates_dir) self.custom_org_disclaimer_checkbox.toggled.connect( self.set_org_disclaimer) self.custom_organisation_logo_check_box.toggled.connect( self.toggle_logo_path) # Buttons self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path) self.toolUserDirectoryPath.clicked.connect( self.open_user_directory_path) self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path) self.open_organisation_logo_path_button.clicked.connect( self.open_organisation_logo_path) self.toolReportTemplatePath.clicked.connect( self.open_report_template_path) # Others self.organisation_logo_path_line_edit.textChanged.connect( self.update_logo_preview) self.earthquake_function.currentIndexChanged.connect( self.update_earthquake_info) # Set up listener for restore defaults button self.demographic_restore_defaults = self.button_box_restore_defaults.\ button(QDialogButtonBox.RestoreDefaults) self.demographic_restore_defaults.setText( self.demographic_restore_defaults.text().capitalize()) self.demographic_restore_defaults.setCheckable(True) self.demographic_restore_defaults.clicked.connect( self.restore_defaults_ratio) # Restore button in population parameter tab self.parameter_population_restore_button = \ self.button_box_restore_preference.button( QDialogButtonBox.RestoreDefaults) self.parameter_population_restore_button.setText( self.parameter_population_restore_button.text().capitalize()) self.parameter_population_restore_button.clicked.connect( partial(self.restore_population_parameters, global_default=True)) # TODO: Hide this until behaviour is defined # hide template warning toggle self.template_warning_checkbox.hide() # hide custom template dir toggle self.custom_templates_dir_checkbox.hide() self.splitter_custom_report.hide() # Welcome message self.set_welcome_message() def save_boolean_setting(self, key, check_box): """Save boolean setting according to check_box state. :param key: Key to retrieve setting value. :type key: str :param check_box: Check box to show and set the setting. :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox """ set_setting(key, check_box.isChecked(), qsettings=self.settings) def restore_boolean_setting(self, key, check_box): """Set check_box according to setting of key. :param key: Key to retrieve setting value. :type key: str :param check_box: Check box to show and set the setting. :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox """ flag = setting(key, expected_type=bool, qsettings=self.settings) check_box.setChecked(flag) def save_text_setting(self, key, line_edit): """Save text setting according to line_edit value. :param key: Key to retrieve setting value. :type key: str :param line_edit: Line edit for user to edit the setting :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit """ set_setting(key, line_edit.text(), self.settings) def restore_text_setting(self, key, line_edit): """Set line_edit text according to setting of key. :param key: Key to retrieve setting value. :type key: str :param line_edit: Line edit for user to edit the setting :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit """ value = setting(key, expected_type=str, qsettings=self.settings) line_edit.setText(value) def restore_state(self): """Reinstate the options based on the user's stored session info.""" # Restore boolean setting as check box. for key, check_box in list(self.boolean_settings.items()): self.restore_boolean_setting(key, check_box) # Restore text setting as line edit. for key, line_edit in list(self.text_settings.items()): self.restore_text_setting(key, line_edit) # User Directory user_directory_path = setting(key='defaultUserDirectory', default=temp_dir('impacts'), expected_type=str, qsettings=self.settings) custom_user_directory_flag = (user_directory_path != temp_dir('impacts')) self.custom_UseUserDirectory_checkbox.setChecked( custom_user_directory_flag) self.splitter_user_directory.setEnabled(custom_user_directory_flag) self.leUserDirectoryPath.setText(user_directory_path) # Currency # Populate the currency list for currency in currencies: self.currency_combo_box.addItem(currency['name'], currency['key']) # Then make selected the default one. default_currency = setting('currency', expected_type=str) keys = [currency['key'] for currency in currencies] if default_currency not in keys: default_currency = currencies[0]['key'] index = self.currency_combo_box.findData(default_currency) self.currency_combo_box.setCurrentIndex(index) # Earthquake function. # Populate the combobox first. for model in EARTHQUAKE_FUNCTIONS: self.earthquake_function.addItem(model['name'], model['key']) # Then make selected the default one. default_earthquake_function = setting('earthquake_function', expected_type=str) keys = [model['key'] for model in EARTHQUAKE_FUNCTIONS] if default_earthquake_function not in keys: default_earthquake_function = EARTHQUAKE_FUNCTIONS[0]['key'] index = self.earthquake_function.findData(default_earthquake_function) self.earthquake_function.setCurrentIndex(index) self.update_earthquake_info() # Restore North Arrow Image Path north_arrow_path = setting(key='north_arrow_path', default=default_north_arrow_path(), expected_type=str, qsettings=self.settings) custom_north_arrow_flag = (north_arrow_path != default_north_arrow_path()) self.custom_north_arrow_checkbox.setChecked(custom_north_arrow_flag) self.splitter_north_arrow.setEnabled(custom_north_arrow_flag) self.leNorthArrowPath.setText(north_arrow_path) # Restore Report Template Directory Path report_template_directory = setting(key='reportTemplatePath', default='', expected_type=str, qsettings=self.settings) custom_templates_dir_flag = (report_template_directory != '') self.custom_templates_dir_checkbox.setChecked( custom_templates_dir_flag) self.leReportTemplatePath.setText(report_template_directory) # Restore Disclaimer org_disclaimer = setting(key='reportDisclaimer', default=disclaimer(), expected_type=str, qsettings=self.settings) custom_org_disclaimer_flag = (org_disclaimer != disclaimer()) self.custom_org_disclaimer_checkbox.setChecked( custom_org_disclaimer_flag) self.txtDisclaimer.setPlainText(org_disclaimer) # Restore Organisation Logo Path org_logo_path = setting(key='organisation_logo_path', default=supporters_logo_path(), expected_type=str, qsettings=self.settings) # Check if the path is default one or not custom_org_logo_flag = org_logo_path != supporters_logo_path() self.organisation_logo_path_line_edit.setText(org_logo_path) self.custom_organisation_logo_check_box.setChecked( custom_org_logo_flag) self.organisation_logo_path_line_edit.setEnabled(custom_org_logo_flag) self.open_organisation_logo_path_button.setEnabled( custom_org_logo_flag) # Manually call here self.update_logo_preview() # Restore InaSAFE default values self.restore_default_values_page() # Restore Population Parameter self.restore_population_parameters(global_default=False) def save_state(self): """Store the options into the user's stored session info.""" # Save boolean settings for key, check_box in list(self.boolean_settings.items()): self.save_boolean_setting(key, check_box) # Save text settings for key, line_edit in list(self.text_settings.items()): self.save_text_setting(key, line_edit) set_setting('north_arrow_path', self.leNorthArrowPath.text(), self.settings) set_setting('organisation_logo_path', self.organisation_logo_path_line_edit.text(), self.settings) set_setting('reportTemplatePath', self.leReportTemplatePath.text(), self.settings) set_setting('reportDisclaimer', self.txtDisclaimer.toPlainText(), self.settings) set_setting('defaultUserDirectory', self.leUserDirectoryPath.text(), self.settings) index = self.earthquake_function.currentIndex() value = self.earthquake_function.itemData(index) set_setting('earthquake_function', value, qsettings=self.settings) currency_index = self.currency_combo_box.currentIndex() currency_key = self.currency_combo_box.itemData(currency_index) set_setting('currency', currency_key, qsettings=self.settings) # Save InaSAFE default values self.save_default_values() # Save population parameters self.save_population_parameters() def accept(self): """Method invoked when OK button is clicked.""" self.save_state() super(OptionsDialog, self).accept() def update_earthquake_info(self): """Update information about earthquake info.""" self.label_earthquake_model() current_index = self.earthquake_function.currentIndex() model = EARTHQUAKE_FUNCTIONS[current_index] notes = '' for note in model['notes']: notes += note + '\n\n' citations = '' for citation in model['citations']: citations += citation['text'] + '\n\n' text = tr( 'Description:\n\n%s\n\n' 'Notes:\n\n%s\n\n' 'Citations:\n\n%s') % (model['description'], notes, citations) self.earthquake_fatality_model_notes.setText(text) def label_earthquake_model(self): model = self.earthquake_function.currentText() help_text = tr( 'Please select your preferred earthquake fatality model. The ' 'default fatality model is the {model}.').format(model=model) self.label_default_earthquake.setText(help_text) def open_keyword_cache_path(self): """Open File dialog to choose the keyword cache path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getSaveFileName( self, self.tr('Set keyword cache file'), self.leKeywordCachePath.text(), self.tr('Sqlite DB File (*.db)')) if file_name: self.leKeywordCachePath.setText(file_name) def open_user_directory_path(self): """Open File dialog to choose the user directory path.""" # noinspection PyCallByClass,PyTypeChecker directory_name = QFileDialog.getExistingDirectory( self, self.tr('Results directory'), self.leUserDirectoryPath.text(), QFileDialog.ShowDirsOnly) if directory_name: self.leUserDirectoryPath.setText(directory_name) def open_north_arrow_path(self): """Open File dialog to choose the north arrow path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getOpenFileName( self, self.tr('Set north arrow image file'), self.leNorthArrowPath.text(), self.tr('Portable Network Graphics files (*.png *.PNG);;' 'JPEG Images (*.jpg *.jpeg);;' 'GIF Images (*.gif *.GIF);;' 'SVG Images (*.svg *.SVG);;')) if file_name: self.leNorthArrowPath.setText(file_name) def open_organisation_logo_path(self): """Open File dialog to choose the organisation logo path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getOpenFileName( self, self.tr('Set organisation logo file'), self.organisation_logo_path_line_edit.text(), self.tr('Portable Network Graphics files (*.png *.PNG);;' 'JPEG Images (*.jpg *.jpeg);;' 'GIF Images (*.gif *.GIF);;' 'SVG Images (*.svg *.SVG);;')) if file_name: self.organisation_logo_path_line_edit.setText(file_name) def open_report_template_path(self): """Open File dialog to choose the report template path.""" # noinspection PyCallByClass,PyTypeChecker directory_name = QFileDialog.getExistingDirectory( self, self.tr('Templates directory'), self.leReportTemplatePath.text(), QFileDialog.ShowDirsOnly) if directory_name: self.leReportTemplatePath.setText(directory_name) def toggle_logo_path(self): """Set state of logo path line edit and button.""" is_checked = self.custom_organisation_logo_check_box.isChecked() if is_checked: # Use previous org logo path path = setting(key='organisation_logo_path', default=supporters_logo_path(), expected_type=str, qsettings=self.settings) else: # Set organisation path line edit to default one path = supporters_logo_path() self.organisation_logo_path_line_edit.setText(path) self.organisation_logo_path_line_edit.setEnabled(is_checked) self.open_organisation_logo_path_button.setEnabled(is_checked) def update_logo_preview(self): """Update logo based on the current logo path.""" logo_path = self.organisation_logo_path_line_edit.text() if os.path.exists(logo_path): icon = QPixmap(logo_path) label_size = self.organisation_logo_label.size() label_size.setHeight(label_size.height() - 2) label_size.setWidth(label_size.width() - 2) scaled_icon = icon.scaled(label_size, Qt.KeepAspectRatio) self.organisation_logo_label.setPixmap(scaled_icon) else: self.organisation_logo_label.setText(tr("Logo not found")) def set_north_arrow(self): """Auto-connect slot activated when north arrow checkbox is toggled.""" is_checked = self.custom_north_arrow_checkbox.isChecked() if is_checked: # Show previous north arrow path path = setting(key='north_arrow_path', default=default_north_arrow_path(), expected_type=str, qsettings=self.settings) else: # Set the north arrow line edit to default one path = default_north_arrow_path() self.leNorthArrowPath.setText(path) self.splitter_north_arrow.setEnabled(is_checked) def set_user_dir(self): """Auto-connect slot activated when user dir checkbox is toggled. """ is_checked = self.custom_UseUserDirectory_checkbox.isChecked() if is_checked: # Show previous templates dir path = setting(key='defaultUserDirectory', default='', expected_type=str, qsettings=self.settings) else: # Set the template report dir to '' path = temp_dir('impacts') self.leUserDirectoryPath.setText(path) self.splitter_user_directory.setEnabled(is_checked) def set_templates_dir(self): """Auto-connect slot activated when templates dir checkbox is toggled. """ is_checked = self.custom_templates_dir_checkbox.isChecked() if is_checked: # Show previous templates dir path = setting(key='reportTemplatePath', default='', expected_type=str, qsettings=self.settings) else: # Set the template report dir to '' path = '' self.leReportTemplatePath.setText(path) self.splitter_custom_report.setEnabled(is_checked) def set_org_disclaimer(self): """Auto-connect slot activated when org disclaimer checkbox is toggled. """ is_checked = self.custom_org_disclaimer_checkbox.isChecked() if is_checked: # Show previous organisation disclaimer org_disclaimer = setting('reportDisclaimer', default=disclaimer(), expected_type=str, qsettings=self.settings) else: # Set the organisation disclaimer to the default one org_disclaimer = disclaimer() self.txtDisclaimer.setPlainText(org_disclaimer) self.txtDisclaimer.setEnabled(is_checked) @pyqtSlot(bool) # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.2.1 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded: 3.2.1 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user.""" # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = options_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def restore_default_values_page(self): """Setup UI for default values setting.""" # Clear parameters so it doesn't add parameters when # restore from changes. if self.default_value_parameters: self.default_value_parameters = [] if self.default_value_parameter_containers: self.default_value_parameter_containers = [] for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) default_fields = all_default_fields() for field_group in all_field_groups: settable_fields = [] for field in field_group['fields']: if field not in default_fields: continue else: settable_fields.append(field) default_fields.remove(field) if not settable_fields: continue # Create group box for each field group group_box = QGroupBox(self) group_box.setTitle(field_group['name']) self.container_layout.addWidget(group_box) parameters = [] for settable_field in settable_fields: parameter = self.default_field_to_parameter(settable_field) if parameter: parameters.append(parameter) parameter_container = ParameterContainer( parameters, description_text=field_group['description'], extra_parameters=extra_parameter) parameter_container.setup_ui(must_scroll=False) group_box_inner_layout = QVBoxLayout() group_box_inner_layout.addWidget(parameter_container) group_box.setLayout(group_box_inner_layout) # Add to attribute self.default_value_parameter_containers.append(parameter_container) # Only show non-groups default fields if there is one if len(default_fields) > 0: for default_field in default_fields: parameter = self.default_field_to_parameter(default_field) if parameter: self.default_value_parameters.append(parameter) description_text = tr( 'In this options you can change the global default values for ' 'these variables.') parameter_container = ParameterContainer( self.default_value_parameters, description_text=description_text, extra_parameters=extra_parameter) parameter_container.setup_ui(must_scroll=False) self.other_group_box = QGroupBox(tr('Non-group fields')) other_group_inner_layout = QVBoxLayout() other_group_inner_layout.addWidget(parameter_container) self.other_group_box.setLayout(other_group_inner_layout) self.container_layout.addWidget(self.other_group_box) # Add to attribute self.default_value_parameter_containers.append(parameter_container) def restore_population_parameters(self, global_default=True): """Setup UI for population parameter page from setting. :param global_default: If True, set to original default (from the value in definitions). :type global_default: bool """ if global_default: data = generate_default_profile() else: data = setting('population_preference', generate_default_profile()) if not isinstance(data, dict): LOGGER.debug( 'population parameter is not a dictionary. InaSAFE will use ' 'the default one.') data = generate_default_profile() try: self.profile_widget.data = data except KeyError as e: LOGGER.debug( 'Population parameter is not in correct format. InaSAFE will ' 'use the default one.') LOGGER.debug(e) data = generate_default_profile() self.profile_widget.data = data @staticmethod def age_ratios(): """Helper to get list of age ratio from the options dialog. :returns: List of age ratio. :rtype: list """ # FIXME(IS) set a correct parameter container parameter_container = None youth_ratio = parameter_container.get_parameter_by_guid( youth_ratio_field['key']).value adult_ratio = parameter_container.get_parameter_by_guid( adult_ratio_field['key']).value elderly_ratio = parameter_container.get_parameter_by_guid( elderly_ratio_field['key']).value ratios = [youth_ratio, adult_ratio, elderly_ratio] return ratios def is_good_age_ratios(self): """Method to check the sum of age ratio is 1. :returns: True if the sum is 1 or the sum less than 1 but there is None. :rtype: bool """ ratios = self.age_ratios() if None in ratios: # If there is None, just check to not exceeding 1 clean_ratios = [x for x in ratios if x is not None] ratios.remove(None) if sum(clean_ratios) > 1: return False else: if sum(ratios) != 1: return False return True def save_default_values(self): """Save InaSAFE default values.""" for parameter_container in self.default_value_parameter_containers: parameters = parameter_container.get_parameters() for parameter in parameters: set_inasafe_default_value_qsetting(self.settings, GLOBAL, parameter.guid, parameter.value) def restore_defaults_ratio(self): """Restore InaSAFE default ratio.""" # Set the flag to true because user ask to. self.is_restore_default = True # remove current default ratio for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) # reload default ratio self.restore_default_values_page() def default_field_to_parameter(self, default_field): """Obtain parameter from default field. :param default_field: A default field definition. :type default_field: dict :returns: A parameter object. :rtype: FloatParameter, IntegerParameter """ if default_field.get('type') == QVariant.Double: parameter = FloatParameter() elif default_field.get('type') in qvariant_whole_numbers: parameter = IntegerParameter() else: return default_value = default_field.get('default_value') if not default_value: message = ('InaSAFE default field %s does not have default value' % default_field.get('name')) LOGGER.exception(message) return parameter.guid = default_field.get('key') parameter.name = default_value.get('name') parameter.is_required = True parameter.precision = default_field.get('precision') parameter.minimum_allowed_value = default_value.get('min_value', 0) parameter.maximum_allowed_value = default_value.get( 'max_value', 100000000) parameter.help_text = default_value.get('help_text') parameter.description = default_value.get('description') # Check if user ask to restore to the most default value. if self.is_restore_default: parameter._value = default_value.get('default_value') else: # Current value qsetting_default_value = get_inasafe_default_value_qsetting( self.settings, GLOBAL, default_field['key']) # To avoid python error if qsetting_default_value > parameter.maximum_allowed_value: qsetting_default_value = parameter.maximum_allowed_value if qsetting_default_value < parameter.minimum_allowed_value: qsetting_default_value = parameter.minimum_allowed_value parameter.value = qsetting_default_value return parameter def save_population_parameters(self): """Helper to save population parameter to QSettings.""" population_parameter = self.profile_widget.data set_setting('population_preference', population_parameter) def set_welcome_message(self): """Create and insert welcome message.""" string = html_header() string += welcome_message().to_html() string += html_footer() self.welcome_message.setHtml(string) def show_option_dialog(self): """Helper to show usual option dialog (without welcome message tab).""" self.tabWidget.removeTab(0) def show_welcome_dialog(self): """Setup for showing welcome message dialog. This method will setup several things: - Only show welcome, organisation profile, and population parameter tab. Currently, they are the first 3 tabs. - Set the title - Move the check box for always showing welcome message. """ self.welcome_layout.addWidget(self.welcome_message_check_box) while self.tabWidget.count() > 3: self.tabWidget.removeTab(self.tabWidget.count() - 1) self.setWindowTitle(self.tr('Welcome to InaSAFE %s' % get_version())) # Hide the export import button self.export_button.hide() self.import_button.hide() def export_setting(self): """Export setting from an existing file.""" LOGGER.debug('Export button clicked') home_directory = os.path.expanduser('~') file_name = self.organisation_line_edit.text().replace(' ', '_') file_path, __ = QFileDialog.getSaveFileName( self, self.tr('Export InaSAFE settings'), os.path.join(home_directory, file_name + '.json'), self.tr('JSON File (*.json)')) if file_path: LOGGER.debug('Exporting to %s' % file_path) export_setting(file_path) def import_setting(self): """Import setting to a file.""" LOGGER.debug('Import button clicked') home_directory = os.path.expanduser('~') file_path, __ = QFileDialog.getOpenFileName( self, self.tr('Import InaSAFE settings'), home_directory, self.tr('JSON File (*.json)')) if file_path: title = tr('Import InaSAFE Settings.') question = tr( 'This action will replace your current InaSAFE settings with ' 'the setting from the file. This action is not reversible. ' 'Are you sure to import InaSAFE Setting?') answer = QMessageBox.question(self, title, question, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: LOGGER.debug('Import from %s' % file_path) import_setting(file_path)
def api_config(self): """ Button 99: Dynamic config form """ # Remove layers name from temp_table sql = "DELETE FROM temp_table WHERE fid = 163 AND cur_user = current_user;" self.controller.execute_sql(sql) # Set layers name in temp_table self.set_layers_name() # Get user and role super_users = self.settings.value('system_variables/super_users') cur_user = self.controller.get_current_user() self.list_update = [] body = self.create_body(form='"formName":"config"') json_result = self.controller.get_json('gw_fct_getconfig', body) if not json_result: return False self.dlg_config = ConfigUi() self.load_settings(self.dlg_config) self.dlg_config.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_config)) self.dlg_config.btn_accept.clicked.connect(partial(self.update_values)) page1_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'page1_layout1') page1_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'page1_layout2') page2_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'page2_layout1') page2_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'page2_layout2') admin_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'admin_layout1') admin_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'admin_layout2') man_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'man_layout1') man_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'man_layout2') addfields_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'addfields_layout1') groupBox_1 = QGroupBox("Basic") groupBox_2 = QGroupBox("O&&M") groupBox_3 = QGroupBox("Inventory") groupBox_4 = QGroupBox("Mapzones") groupBox_5 = QGroupBox("Edit") groupBox_6 = QGroupBox("Epa") groupBox_7 = QGroupBox("MasterPlan") groupBox_8 = QGroupBox("Other") groupBox_9 = QGroupBox("Node") groupBox_10 = QGroupBox("Arc") groupBox_11 = QGroupBox("Utils") groupBox_12 = QGroupBox(f"Connec") groupBox_13 = QGroupBox(f"Gully") groupBox_14 = QGroupBox("Topology") groupBox_15 = QGroupBox("Builder") groupBox_16 = QGroupBox("Review") groupBox_17 = QGroupBox("Analysis") groupBox_18 = QGroupBox("System") groupBox_19 = QGroupBox("Fluid type") groupBox_20 = QGroupBox("Location type") groupBox_21 = QGroupBox("Category type") groupBox_22 = QGroupBox("Function type") groupBox_23 = QGroupBox("Addfields") self.basic_form = QGridLayout() self.om_form = QGridLayout() self.inventory_form = QGridLayout() self.mapzones_form = QGridLayout() self.cad_form = QGridLayout() self.epa_form = QGridLayout() self.masterplan_form = QGridLayout() self.other_form = QGridLayout() self.node_type_form = QGridLayout() self.cat_form = QGridLayout() self.utils_form = QGridLayout() self.connec_form = QGridLayout() self.gully_form = QGridLayout() self.topology_form = QGridLayout() self.builder_form = QGridLayout() self.review_form = QGridLayout() self.analysis_form = QGridLayout() self.system_form = QGridLayout() self.fluid_type_form = QGridLayout() self.location_type_form = QGridLayout() self.category_type_form = QGridLayout() self.function_type_form = QGridLayout() self.addfields_form = QGridLayout() # Construct form for config and admin self.construct_form_param_user(json_result['body']['form']['formTabs'], 0) self.construct_form_param_system( json_result['body']['form']['formTabs'], 1) groupBox_1.setLayout(self.basic_form) groupBox_2.setLayout(self.om_form) groupBox_3.setLayout(self.inventory_form) groupBox_4.setLayout(self.mapzones_form) groupBox_5.setLayout(self.cad_form) groupBox_6.setLayout(self.epa_form) groupBox_7.setLayout(self.masterplan_form) groupBox_8.setLayout(self.other_form) groupBox_9.setLayout(self.node_type_form) groupBox_10.setLayout(self.cat_form) groupBox_11.setLayout(self.utils_form) groupBox_12.setLayout(self.connec_form) groupBox_13.setLayout(self.gully_form) groupBox_14.setLayout(self.topology_form) groupBox_15.setLayout(self.builder_form) groupBox_16.setLayout(self.review_form) groupBox_17.setLayout(self.analysis_form) groupBox_18.setLayout(self.system_form) groupBox_19.setLayout(self.fluid_type_form) groupBox_20.setLayout(self.location_type_form) groupBox_21.setLayout(self.category_type_form) groupBox_22.setLayout(self.function_type_form) groupBox_23.setLayout(self.addfields_form) page1_layout1.addWidget(groupBox_1) page1_layout1.addWidget(groupBox_2) page1_layout1.addWidget(groupBox_3) page1_layout1.addWidget(groupBox_4) page1_layout2.addWidget(groupBox_5) page1_layout2.addWidget(groupBox_6) page1_layout2.addWidget(groupBox_7) page1_layout2.addWidget(groupBox_8) page2_layout1.addWidget(groupBox_9) page2_layout2.addWidget(groupBox_10) page2_layout2.addWidget(groupBox_12) page2_layout2.addWidget(groupBox_13) page2_layout2.addWidget(groupBox_11) admin_layout1.addWidget(groupBox_14) admin_layout2.addWidget(groupBox_15) admin_layout2.addWidget(groupBox_16) admin_layout2.addWidget(groupBox_17) admin_layout2.addWidget(groupBox_18) man_layout1.addWidget(groupBox_19) man_layout1.addWidget(groupBox_20) man_layout2.addWidget(groupBox_21) man_layout2.addWidget(groupBox_22) addfields_layout1.addWidget(groupBox_23) verticalSpacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) page1_layout1.addItem(verticalSpacer1) page1_layout2.addItem(verticalSpacer1) page2_layout1.addItem(verticalSpacer1) page2_layout2.addItem(verticalSpacer1) admin_layout1.addItem(verticalSpacer1) admin_layout2.addItem(verticalSpacer1) man_layout1.addItem(verticalSpacer1) man_layout2.addItem(verticalSpacer1) addfields_layout1.addItem(verticalSpacer1) # Event on change from combo parent self.get_event_combo_parent(json_result['body']['form']['formTabs']) # Set signals Combo parent/child chk_expl = self.dlg_config.tab_main.findChild( QWidget, 'chk_exploitation_vdefault') chk_dma = self.dlg_config.tab_main.findChild(QWidget, 'chk_dma_vdefault') if chk_dma and chk_expl: chk_dma.stateChanged.connect( partial(self.check_child_to_parent, chk_dma, chk_expl)) chk_expl.stateChanged.connect( partial(self.check_parent_to_child, chk_expl, chk_dma)) self.hide_void_groupbox(self.dlg_config) # Check user/role and remove tabs role_admin = self.controller.check_role_user("role_admin", cur_user) if not role_admin and cur_user not in super_users: utils_giswater.remove_tab_by_tabName(self.dlg_config.tab_main, "tab_admin") # Open form self.open_dialog(self.dlg_config, dlg_name='config')
class LoadInputsDialog(QDialog): """ Dialog to browse zipped input files """ loading_canceled = pyqtSignal(QDialog) loading_completed = pyqtSignal(QDialog) def __init__(self, drive_engine_dlg, zip_filepath, iface, parent=None, mode=None): super().__init__(parent) self.drive_engine_dlg = drive_engine_dlg self.zip_filepath = zip_filepath self.iface = iface self.mode = mode ini_str = self.get_ini_str(self.zip_filepath) self.multi_peril_csv_dict = self.get_multi_peril_csv_dict(ini_str) self.setWindowTitle('Load peril data from csv') self.peril_gbx = QGroupBox('Peril') self.peril_vlayout = QVBoxLayout() self.perils = self.multi_peril_csv_dict.keys() self.peril_gbx.setLayout(self.peril_vlayout) for peril in self.perils: chk = QCheckBox(peril) chk.setChecked(True) self.peril_vlayout.addWidget(chk) self.higher_on_top_chk = QCheckBox('Render higher values on top') self.higher_on_top_chk.setChecked(False) self.button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.ok_button = self.button_box.button(QDialogButtonBox.Ok) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) vlayout = QVBoxLayout() vlayout.addWidget(self.peril_gbx) vlayout.addWidget(self.higher_on_top_chk) vlayout.addWidget(self.button_box) self.setLayout(vlayout) @staticmethod def get_ini_str(filepath): zfile = zipfile.ZipFile(filepath) for fname in zfile.namelist(): if os.path.splitext(fname)[1] == '.ini': ini_str = zfile.open( zfile.NameToInfo[fname]).read().decode('utf8') break return ini_str @staticmethod def get_multi_peril_csv_dict(ini_str): config = configparser.ConfigParser(allow_no_value=True) config.read_string(ini_str) multi_peril_csv_str = None for key in config: if 'multi_peril_csv' in config[key]: multi_peril_csv_str = config[key]['multi_peril_csv'] break if multi_peril_csv_str is None: raise KeyError('multi_peril_csv not found in .ini file') multi_peril_csv_dict = json.loads( multi_peril_csv_str.replace('\'', '"')) return multi_peril_csv_dict def load_from_csv(self, csv_path, peril): # extract the name of the csv file and remove the extension layer_name, ext = os.path.splitext(os.path.basename(csv_path)) wkt_field = None headers = get_headers(csv_path) for header in headers: if header.lower() in GEOM_FIELDNAMES: wkt_field = header break if self.mode == 'testing': add_to_legend = False else: add_to_legend = True try: layer = import_layer_from_csv( self, csv_path, layer_name, self.iface, wkt_field=wkt_field, add_to_legend=add_to_legend, add_on_top=True, zoom_to_layer=True) except RuntimeError as exc: log_msg(str(exc), level='C', message_bar=self.iface.messageBar(), exception=exc) raise exc if self.mode == 'testing': root = QgsProject.instance().layerTreeRoot() root.insertLayer(0, layer) self.iface.setActiveLayer(layer) self.iface.zoomToActiveLayer() if 'intensity' in [field.name() for field in layer.fields()]: LoadOutputAsLayerDialog.style_maps( layer, 'intensity', self.iface, 'input', render_higher_on_top=self.higher_on_top_chk.isChecked()) user_params = {'peril': peril} write_metadata_to_layer( self.drive_engine_dlg, 'input', layer, user_params) log_msg('Layer %s was loaded successfully' % layer_name, level='S', message_bar=self.iface.messageBar()) def accept(self): super().accept() for chk in self.peril_gbx.findChildren(QCheckBox): if chk.isChecked(): peril = chk.text() zfile = zipfile.ZipFile(self.zip_filepath) inner_path = 'input/' + self.multi_peril_csv_dict[peril] extracted_csv_path = zfile.extract( inner_path, path=os.path.dirname(self.zip_filepath)) self.load_from_csv(extracted_csv_path, peril) self.loading_completed.emit(self) def reject(self): super().reject() self.loading_canceled.emit(self)
class DistrictSettingsDialog(QDialog): """ A dialog used for plugin settings """ def __init__(self, parent=None): # pylint: disable=too-many-statements super().__init__(parent) self.setWindowTitle(self.tr('Redistrict Plugin | Settings')) layout = QVBoxLayout() self.auth_label = QLabel(self.tr('Authentication configuration')) layout.addWidget(self.auth_label) self.auth_value = QgsAuthConfigSelect() layout.addWidget(self.auth_value) auth_id = get_auth_config_id() if auth_id: self.auth_value.setConfigId(auth_id) layout.addWidget(QLabel(self.tr('API base URL'))) self.base_url_edit = QLineEdit() self.base_url_edit.setText(QgsSettings().value('redistrict/base_url', '', str, QgsSettings.Plugins)) layout.addWidget(self.base_url_edit) h_layout = QHBoxLayout() h_layout.addWidget(QLabel(self.tr('Check for completed requests every'))) self.check_every_spin = QSpinBox() self.check_every_spin.setMinimum(10) self.check_every_spin.setMaximum(600) self.check_every_spin.setSuffix(' ' + self.tr('s')) self.check_every_spin.setValue(QgsSettings().value('redistrict/check_every', '30', int, QgsSettings.Plugins)) h_layout.addWidget(self.check_every_spin) layout.addLayout(h_layout) self.use_mock_checkbox = QCheckBox(self.tr('Use mock Statistics NZ API')) self.use_mock_checkbox.setChecked(get_use_mock_api()) layout.addWidget(self.use_mock_checkbox) self.test_button = QPushButton(self.tr('Test API connection')) self.test_button.clicked.connect(self.test_api) layout.addWidget(self.test_button) self.use_overlays_checkbox = QCheckBox(self.tr('Show updated populations during interactive redistricting')) self.use_overlays_checkbox.setChecked( QgsSettings().value('redistrict/show_overlays', False, bool, QgsSettings.Plugins)) layout.addWidget(self.use_overlays_checkbox) self.use_sound_group_box = QGroupBox(self.tr('Use audio feedback')) self.use_sound_group_box.setCheckable(True) self.use_sound_group_box.setChecked( QgsSettings().value('redistrict/use_audio_feedback', False, bool, QgsSettings.Plugins)) sound_layout = QGridLayout() sound_layout.addWidget(QLabel(self.tr('When meshblock redistricted')), 0, 0) self.on_redistrict_file_widget = QgsFileWidget() self.on_redistrict_file_widget.setDialogTitle(self.tr('Select Audio File')) self.on_redistrict_file_widget.setStorageMode(QgsFileWidget.GetFile) self.on_redistrict_file_widget.setFilePath( QgsSettings().value('redistrict/on_redistrict', '', str, QgsSettings.Plugins)) self.on_redistrict_file_widget.setFilter(self.tr('Wave files (*.wav *.WAV)')) sound_layout.addWidget(self.on_redistrict_file_widget, 0, 1) self.play_on_redistrict_sound_button = QPushButton(self.tr('Test')) self.play_on_redistrict_sound_button.clicked.connect(self.play_on_redistrict_sound) sound_layout.addWidget(self.play_on_redistrict_sound_button, 0, 2) self.use_sound_group_box.setLayout(sound_layout) layout.addWidget(self.use_sound_group_box) button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(button_box) button_box.rejected.connect(self.reject) button_box.accepted.connect(self.accept) self.setLayout(layout) def accept(self): # pylint: disable=missing-docstring super().accept() QgsSettings().setValue('redistrict/auth_config_id', self.auth_value.configId(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/use_mock_api', self.use_mock_checkbox.isChecked(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/base_url', self.base_url_edit.text(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/check_every', self.check_every_spin.value(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/show_overlays', self.use_overlays_checkbox.isChecked(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/use_audio_feedback', self.use_sound_group_box.isChecked(), QgsSettings.Plugins) QgsSettings().setValue('redistrict/on_redistrict', self.on_redistrict_file_widget.filePath(), QgsSettings.Plugins) def test_api(self): """ Tests the API connection (real or mock!) """ connector = get_api_connector(use_mock=self.use_mock_checkbox.isChecked(), authcfg=self.auth_value.configId(), base_url=self.base_url_edit.text()) if connector.check(): QMessageBox.information(self, self.tr('Test API Connection'), self.tr('API responded OK!'), QMessageBox.Ok) else: QMessageBox.critical(self, self.tr('Test API Connection'), self.tr('Could not connect to API!'), QMessageBox.Ok) def play_on_redistrict_sound(self): """ Plays the 'on redistrict' sound """ try: playsound(self.on_redistrict_file_widget.filePath(), block=False) except FileNotFoundError: pass
def __init__(self): QDialog.__init__(self) self.setWindowTitle(tr('DMS Point Tool')) self.lat_D = QLineEdit() self.lat_M = QLineEdit() self.lat_S = QLineEdit() self.lat_DM = QLineEdit() self.lon_D = QLineEdit() self.lon_M = QLineEdit() self.lon_S = QLineEdit() self.lon_DM = QLineEdit() self.lat_M.textEdited.connect(self.lat_MS_edited) self.lat_S.textEdited.connect(self.lat_MS_edited) self.lat_DM.textEdited.connect(self.lat_DM_edited) self.lon_M.textEdited.connect(self.lon_MS_edited) self.lon_S.textEdited.connect(self.lon_MS_edited) self.lon_DM.textEdited.connect(self.lon_DM_edited) int_val = QIntValidator() int_val.setBottom(0) float_val = QDoubleValidator() float_val.setBottom(0) self.lat_D.setValidator(int_val) self.lat_M.setValidator(int_val) self.lat_S.setValidator(float_val) self.lat_DM.setValidator(float_val) self.lon_D.setValidator(int_val) self.lon_M.setValidator(int_val) self.lon_S.setValidator(float_val) self.lon_DM.setValidator(float_val) self.lat_NS = QComboBox() self.lat_NS.addItem("N") self.lat_NS.addItem("S") self.lon_EW = QComboBox() self.lon_EW.addItem("E") self.lon_EW.addItem("W") buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) lat_grp = QGroupBox(tr("Latitude"), self) lat_grp.setStyleSheet( "QGroupBox { font-weight: bold; color: #3c3c3c; } ") lat_grid = QGridLayout() lat_grid.addWidget(QLabel(tr("Degrees")), 0, 0) lat_grid.addWidget(QLabel(tr("Minutes")), 0, 1) lat_grid.addWidget(QLabel(tr("Seconds")), 0, 2) lat_grid.addWidget(QLabel(tr("Direction")), 0, 3) lat_grid.addWidget(self.lat_D, 1, 0) lat_grid.addWidget(self.lat_M, 1, 1) lat_grid.addWidget(self.lat_S, 1, 2) lat_grid.addWidget(self.lat_NS, 1, 3) lat_grid.addWidget(QLabel(tr("Decimal minutes")), 2, 1) lat_grid.addWidget(self.lat_DM, 3, 1, 1, 2) lat_grp.setLayout(lat_grid) lon_grp = QGroupBox(tr("Longitude"), self) lon_grp.setStyleSheet( "QGroupBox { font-weight: bold; color: #3c3c3c; } ") lon_grid = QGridLayout() lon_grid.addWidget(QLabel(tr("Degrees")), 0, 0) lon_grid.addWidget(QLabel(tr("Minutes")), 0, 1) lon_grid.addWidget(QLabel(tr("Seconds")), 0, 2) lon_grid.addWidget(QLabel(tr("Direction")), 0, 3) lon_grid.addWidget(self.lon_D, 1, 0) lon_grid.addWidget(self.lon_M, 1, 1) lon_grid.addWidget(self.lon_S, 1, 2) lon_grid.addWidget(self.lon_EW, 1, 3) lon_grid.addWidget(QLabel(tr("Decimal minutes")), 2, 1) lon_grid.addWidget(self.lon_DM, 3, 1, 1, 2) lon_grp.setLayout(lon_grid) vbox = QVBoxLayout() vbox.addWidget(lat_grp) vbox.addWidget(lon_grp) vbox.addWidget(buttons) self.setLayout(vbox)
class ProjectFromOSMDialog(QtWidgets.QDialog, FORM_CLASS): def __init__(self, iface): QtWidgets.QDialog.__init__(self) self.iface = iface self.setupUi(self) self.path = standard_path() self.error = None self.report = [] self.worker_thread = None self.running = False self.bbox = None self.json = [] self.project = None self.logger = logging.getLogger("aequilibrae") self._run_layout = QGridLayout() # Area to import network for self.choose_place = QRadioButton() self.choose_place.setText("Place name") self.choose_place.toggled.connect(self.change_place_type) self.choose_place.setChecked(False) self.choose_canvas = QRadioButton() self.choose_canvas.setText("Current map canvas area") self.choose_canvas.setChecked(True) self.place = QLineEdit() self.place.setVisible(False) self.source_type_frame = QVBoxLayout() self.source_type_frame.setAlignment(Qt.AlignLeft) self.source_type_frame.addWidget(self.choose_place) self.source_type_frame.addWidget(self.choose_canvas) self.source_type_frame.addWidget(self.place) self.source_type_widget = QGroupBox('Target') self.source_type_widget.setLayout(self.source_type_frame) # Buttons and output self.but_choose_output = QPushButton() self.but_choose_output.setText("Choose file output") self.but_choose_output.clicked.connect(self.choose_output) self.output_path = QLineEdit() self.but_run = QPushButton() self.but_run.setText("Import network and create project") self.but_run.clicked.connect(self.run) self.buttons_frame = QVBoxLayout() self.buttons_frame.addWidget(self.but_choose_output) self.buttons_frame.addWidget(self.output_path) self.buttons_frame.addWidget(self.but_run) self.buttons_widget = QWidget() self.buttons_widget.setLayout(self.buttons_frame) self.progressbar = QProgressBar() self.progress_label = QLabel() self.update_widget = QWidget() self.update_frame = QVBoxLayout() self.update_frame.addWidget(self.progressbar) self.update_frame.addWidget(self.progress_label) self.update_widget.setLayout(self.update_frame) self.update_widget.setVisible(False) self._run_layout.addWidget(self.source_type_widget) self._run_layout.addWidget(self.buttons_widget) self._run_layout.addWidget(self.update_widget) self.setLayout(self._run_layout) self.resize(280, 250) def choose_output(self): new_name, file_type = GetOutputFileName(self, '', ["SQLite database(*.sqlite)"], ".sqlite", self.path) if new_name is not None: self.output_path.setText(new_name) def run(self): self.update_widget.setVisible(True) self.resize(280, 300) if self.choose_canvas.isChecked(): self.report.append( reporter('Chose to download network for canvas area')) e = self.iface.mapCanvas().extent() bbox = [e.xMinimum(), e.yMinimum(), e.xMaximum(), e.yMaximum()] else: self.progress_label.setText('Establishing area for download') self.report.append(reporter('Chose to download network for place')) bbox, r = placegetter(self.place.text()) self.report.extend(r) if bbox is None: self.leave() return west, south, east, north = bbox[0], bbox[1], bbox[2], bbox[3] self.report.append( reporter( 'Downloading network for bounding box ({} {}, {}, {})'.format( west, south, east, north))) self.bbox = bbox surveybox = QgsRectangle(QgsPointXY(west, south), QgsPointXY(east, north)) geom = QgsGeometry().fromRect(surveybox) conv = QgsDistanceArea() area = conv.convertAreaMeasurement(conv.measureArea(geom), QgsUnitTypes.AreaSquareMeters) self.report.append( reporter( 'Area for which we will download a network: {:,} km.sq'.format( area / 1000000))) if area <= max_query_area_size: geometries = [[west, south, east, north]] else: parts = math.ceil(area / max_query_area_size) horizontal = math.ceil(math.sqrt(parts)) vertical = math.ceil(parts / horizontal) dx = east - west dy = north - south geometries = [] for i in range(horizontal): xmin = west + i * dx xmax = west + (i + 1) * dx for j in range(vertical): ymin = south + j * dy ymax = south + (j + 1) * dy box = [xmin, ymin, xmax, ymax] geometries.append(box) p = Parameters().parameters modes = [list(k.keys())[0] for k in p['network']['modes']] self.progress_label.setText('Downloading data') self.downloader = OSMDownloader(geometries, modes) self.run_download_thread() def final_steps(self): self.project = Project(self.output_path.text(), True) self.project.network.create_empty_tables() curr = self.project.conn.cursor() curr.execute("""ALTER TABLE links ADD COLUMN osm_id integer""") curr.execute("""ALTER TABLE nodes ADD COLUMN osm_id integer""") self.project.conn.commit() self.project.conn.close() self.builder = OSMBuilder(self.downloader.json, self.project.source) self.run_thread() def run_download_thread(self): self.downloader.downloading.connect(self.signal_downloader_handler) self.downloader.start() self.exec_() def run_thread(self): self.builder.building.connect(self.signal_handler) self.builder.start() self.exec_() def change_place_type(self): if self.choose_place.isChecked(): self.place.setVisible(True) else: self.place.setVisible(False) def leave(self): self.close() dlg2 = ReportDialog(self.iface, self.report) dlg2.show() dlg2.exec_() def signal_downloader_handler(self, val): if val[0] == "Value": self.progressbar.setValue(val[1]) elif val[0] == "maxValue": self.progressbar.setRange(0, val[1]) elif val[0] == "text": self.progress_label.setText(val[1]) elif val[0] == "FinishedDownloading": self.final_steps() def signal_handler(self, val): if val[0] == "Value": self.progressbar.setValue(val[1]) elif val[0] == "maxValue": self.progressbar.setRange(0, val[1]) elif val[0] == "text": self.progress_label.setText(val[1]) elif val[0] == "finished_threaded_procedure": self.project = Project(self.output_path.text()) self.progress_label.setText('Adding spatial indices') self.project.network.add_spatial_index() self.project.network.add_triggers() l = self.project.network.count_links() n = self.project.network.count_nodes() self.report.append(reporter(f'{l:,} links generated')) self.report.append(reporter(f'{n:,} nodes generated')) self.leave()
class LoadAssetRiskAsLayerDialog(LoadOutputAsLayerDialog): """ Dialog to load asset_risk from an oq-engine output, as layer """ def __init__(self, drive_engine_dlg, iface, viewer_dock, session, hostname, calc_id, output_type='asset_risk', path=None, mode=None, engine_version=None, calculation_mode=None): assert output_type == 'asset_risk' super().__init__(drive_engine_dlg, iface, viewer_dock, session, hostname, calc_id, output_type=output_type, path=path, mode=mode, engine_version=engine_version, calculation_mode=calculation_mode) self.setWindowTitle('Load Exposure/Risk as layer') log_msg( 'Extracting exposure metadata.' ' Watch progress in QGIS task bar', level='I', message_bar=self.iface.messageBar()) self.extract_npz_task = ExtractNpzTask('Extract exposure metadata', QgsTask.CanCancel, self.session, self.hostname, self.calc_id, 'exposure_metadata', self.finalize_init, self.on_extract_error) QgsApplication.taskManager().addTask(self.extract_npz_task) def finalize_init(self, extracted_npz): self.exposure_metadata = extracted_npz self.tag_names = sorted(self.exposure_metadata['tagnames']) self.exposure_categories = sorted(self.exposure_metadata['names']) self.risk_categories = sorted(self.exposure_metadata['multi_risk']) self.perils = set( [cat.rsplit('-', 1)[-1] for cat in self.risk_categories]) self.populate_out_dep_widgets() self.adjustSize() self.taxonomies_gbx.toggled.emit(False) self.tag_gbx.toggled.emit(False) self.set_ok_button() self.show() self.init_done.emit(self) def populate_out_dep_widgets(self): self.visualize_gbx = QGroupBox('Visualize') self.visualize_gbx_h_layout = QHBoxLayout() self.exposure_rbn = QRadioButton('Exposure') self.risk_rbn = QRadioButton('Risk') self.exposure_rbn.toggled.connect(self.on_visualize_changed) self.risk_rbn.toggled.connect(self.on_visualize_changed) self.visualize_gbx_h_layout.addWidget(self.exposure_rbn) self.visualize_gbx_h_layout.addWidget(self.risk_rbn) self.visualize_gbx.setLayout(self.visualize_gbx_h_layout) self.vlayout.addWidget(self.visualize_gbx) self.create_selector("peril", "Peril", filter_ckb=False, on_text_changed=self.on_peril_changed) self.peril_cbx.setDisabled(True) self.peril_lbl.setVisible(False) self.peril_cbx.setVisible(False) self.create_selector("category", "Category", filter_ckb=False) self.peril_cbx.addItems(sorted(self.perils)) self.taxonomies_gbx = QGroupBox() self.taxonomies_gbx.setTitle('Filter by taxonomy') self.taxonomies_gbx.setCheckable(True) self.taxonomies_gbx.setChecked(False) self.taxonomies_gbx_v_layout = QVBoxLayout() self.taxonomies_gbx.setLayout(self.taxonomies_gbx_v_layout) self.taxonomies_lbl = QLabel("Taxonomies") self.taxonomies_multisel = MultiSelectComboBox(self) self.taxonomies_multisel.add_unselected_items( sorted([ taxonomy for taxonomy in self.exposure_metadata['taxonomy'] if taxonomy != '?' ])) self.taxonomies_gbx_v_layout.addWidget(self.taxonomies_lbl) self.taxonomies_gbx_v_layout.addWidget(self.taxonomies_multisel) self.taxonomies_gbx.toggled[bool].connect( self.on_taxonomies_gbx_toggled) self.vlayout.addWidget(self.taxonomies_gbx) self.tag_gbx = QGroupBox() self.tag_gbx.setTitle('Filter by tag') self.tag_gbx.setCheckable(True) self.tag_gbx.setChecked(False) self.tag_gbx_v_layout = QVBoxLayout() self.tag_gbx.setLayout(self.tag_gbx_v_layout) self.tag_values_lbl = QLabel("Tag values") self.tag_values_multisel = MultiSelectComboBox(self) self.create_selector("tag", "Tag", add_to_layout=self.tag_gbx_v_layout, on_text_changed=self.on_tag_changed) self.tag_cbx.addItems([ tag_name for tag_name in self.tag_names if tag_name != 'taxonomy' ]) self.tag_gbx_v_layout.addWidget(self.tag_values_lbl) self.tag_gbx_v_layout.addWidget(self.tag_values_multisel) self.tag_gbx.toggled[bool].connect(self.on_tag_gbx_toggled) self.vlayout.addWidget(self.tag_gbx) self.higher_on_top_chk = QCheckBox('Render higher values on top') self.higher_on_top_chk.setChecked(True) self.vlayout.addWidget(self.higher_on_top_chk) self.create_zonal_layer_selector() if self.zonal_layer_path: zonal_layer = self.load_zonal_layer(self.zonal_layer_path) self.populate_zonal_layer_cbx(zonal_layer) else: self.pre_populate_zonal_layer_cbx() self.exposure_rbn.setChecked(True) def on_taxonomies_gbx_toggled(self, is_checked): for widget in self.taxonomies_gbx.findChildren(QWidget): widget.setVisible(is_checked) def on_tag_gbx_toggled(self, is_checked): for widget in self.tag_gbx.findChildren(QWidget): widget.setVisible(is_checked) def on_visualize_changed(self): self.peril_cbx.setEnabled(self.risk_rbn.isChecked()) self.peril_lbl.setVisible(self.risk_rbn.isChecked()) self.peril_cbx.setVisible(self.risk_rbn.isChecked()) if self.exposure_rbn.isChecked(): self.category_cbx.clear() self.category_cbx.addItems(self.exposure_categories) else: # 'Risk' self.peril_cbx.setCurrentIndex(0) self.peril_cbx.currentTextChanged.emit( self.peril_cbx.currentText()) def on_peril_changed(self, peril): categories = [ category.rsplit('-', 1)[0] for category in self.risk_categories if peril in category ] self.category_cbx.clear() self.category_cbx.addItems(sorted(categories)) def on_tag_changed(self, tag_name): tag_values = sorted([ value for value in self.exposure_metadata[tag_name] if value != '?' ]) self.tag_values_multisel.clear() self.tag_values_multisel.add_unselected_items(tag_values) def set_ok_button(self): self.ok_button.setEnabled(self.category_cbx.currentIndex() != -1) def build_layer_name(self, rlz_or_stat=None, **kwargs): if self.exposure_rbn.isChecked(): self.default_field_name = self.category_cbx.currentText() else: # 'Risk' self.default_field_name = "%s-%s" % ( self.category_cbx.currentText(), self.peril_cbx.currentText()) if self.exposure_rbn.isChecked(): layer_name = 'Exposure: %s' % self.category_cbx.currentText() else: # Risk layer_name = 'Risk: %s %s' % (self.peril_cbx.currentText(), self.category_cbx.currentText()) return layer_name def get_field_types(self, **kwargs): field_types = { name: self.dataset[name].dtype.char for name in self.dataset.dtype.names if name not in ['lon', 'lat'] and name not in self.tag_names } return field_types def read_npz_into_layer(self, field_types, **kwargs): with edit(self.layer): lons = self.dataset['lon'] lats = self.dataset['lat'] feats = [] for row_idx, row in enumerate(self.dataset): # add a feature feat = QgsFeature(self.layer.fields()) for field_name in field_types: value = row[field_name].item() if isinstance(value, bytes): value = value.decode('utf8') feat.setAttribute(field_name, value) feat.setGeometry( QgsGeometry.fromPointXY( QgsPointXY(lons[row_idx], lats[row_idx]))) feats.append(feat) added_ok = self.layer.addFeatures(feats) if not added_ok: msg = 'There was a problem adding features to the layer.' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return self.layer def accept(self): log_msg('Loading output started. Watch progress in QGIS task bar', level='I', message_bar=self.iface.messageBar()) self.iface.layerTreeView().currentLayerChanged.disconnect( self.on_currentLayerChanged) self.hide() extract_params = self.get_extract_params() self.download_asset_risk(extract_params) def get_extract_params(self): params = {} if self.tag_gbx.isChecked(): tag_name = self.tag_cbx.currentText() params[tag_name] = self.tag_values_multisel.get_selected_items() if self.taxonomies_gbx.isChecked(): params['taxonomy'] = self.taxonomies_multisel.get_selected_items() return params def download_asset_risk(self, extract_params): self.extract_npz_task = ExtractNpzTask('Extract asset_risk', QgsTask.CanCancel, self.session, self.hostname, self.calc_id, 'asset_risk', self.on_asset_risk_downloaded, self.on_extract_error, params=extract_params) QgsApplication.taskManager().addTask(self.extract_npz_task) def on_asset_risk_downloaded(self, extracted_npz): self.npz_file = extracted_npz self.dataset = self.npz_file['array'] with WaitCursorManager('Creating layer...', self.iface.messageBar()): self.layer = self.build_layer() self.style_maps( self.layer, self.default_field_name, self.iface, self.output_type, perils=self.perils, render_higher_on_top=self.higher_on_top_chk.isChecked()) if (self.zonal_layer_cbx.currentText() and self.zonal_layer_gbx.isChecked()): self.aggregate_by_zone() else: self.loading_completed.emit(self) QDialog.accept(self)
def api_config(self): """ Button 99: Dynamic config form """ # Remove layers name from temp_table sql = "DELETE FROM temp_table WHERE fprocesscat_id = '63' AND user_name = current_user;" self.controller.execute_sql(sql) # Set layers name in temp_table self.set_layers_name() # Get user and role super_users = self.settings.value('system_variables/super_users') cur_user = self.controller.get_current_user() self.list_update = [] body = '"client":{"device":3, "infoType":100, "lang":"ES"}, ' body += '"form":{"formName":"config"}, ' body += '"feature":{}, ' body += '"data":{}' # Get layers under mouse clicked sql = f"SELECT gw_api_getconfig($${{{body}}}$$)::text" row = self.controller.get_row(sql, log_sql=True) complet_list = [json.loads(row[0], object_pairs_hook=OrderedDict)] self.dlg_config = ApiConfigUi() self.load_settings(self.dlg_config) self.dlg_config.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_config)) self.dlg_config.btn_accept.clicked.connect(partial(self.update_values)) page1_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'page1_layout1') page1_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'page1_layout2') page2_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'page2_layout1') page2_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'page2_layout2') admin_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'admin_layout1') admin_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'admin_layout2') man_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'man_layout1') man_layout2 = self.dlg_config.tab_main.findChild( QGridLayout, 'man_layout2') addfields_layout1 = self.dlg_config.tab_main.findChild( QGridLayout, 'addfields_layout1') groupBox_1 = QGroupBox("Basic") groupBox_2 = QGroupBox("Om") groupBox_3 = QGroupBox("Workcat") groupBox_4 = QGroupBox("Mapzones") groupBox_5 = QGroupBox("Edit") groupBox_6 = QGroupBox("Epa") groupBox_7 = QGroupBox("MasterPlan") groupBox_8 = QGroupBox("Other") groupBox_9 = QGroupBox("Node") groupBox_10 = QGroupBox("Arc") groupBox_11 = QGroupBox("Utils") groupBox_12 = QGroupBox("Connec&Gully") groupBox_13 = QGroupBox("Topology") groupBox_14 = QGroupBox("Builder") groupBox_15 = QGroupBox("Review") groupBox_16 = QGroupBox("Analysis") groupBox_17 = QGroupBox("System") groupBox_18 = QGroupBox("Fluid type") groupBox_19 = QGroupBox("Location type") groupBox_20 = QGroupBox("Category type") groupBox_21 = QGroupBox("Function type") groupBox_22 = QGroupBox("Addfields") self.basic_form = QGridLayout() self.om_form = QGridLayout() self.workcat_form = QGridLayout() self.mapzones_form = QGridLayout() self.cad_form = QGridLayout() self.epa_form = QGridLayout() self.masterplan_form = QGridLayout() self.other_form = QGridLayout() self.node_type_form = QGridLayout() self.cat_form = QGridLayout() self.utils_form = QGridLayout() self.connec_form = QGridLayout() self.topology_form = QGridLayout() self.builder_form = QGridLayout() self.review_form = QGridLayout() self.analysis_form = QGridLayout() self.system_form = QGridLayout() self.node_mantype_form = QGridLayout() self.arc_mantype_form = QGridLayout() self.connec_mantype_form = QGridLayout() self.gully_mantype_form = QGridLayout() self.addfields_form = QGridLayout() # Construct form for config and admin self.construct_form_param_user( complet_list[0]['body']['form']['formTabs'], 0) self.construct_form_param_system( complet_list[0]['body']['form']['formTabs'], 1) groupBox_1.setLayout(self.basic_form) groupBox_2.setLayout(self.om_form) groupBox_3.setLayout(self.workcat_form) groupBox_4.setLayout(self.mapzones_form) groupBox_5.setLayout(self.cad_form) groupBox_6.setLayout(self.epa_form) groupBox_7.setLayout(self.masterplan_form) groupBox_8.setLayout(self.other_form) groupBox_9.setLayout(self.node_type_form) groupBox_10.setLayout(self.cat_form) groupBox_11.setLayout(self.utils_form) groupBox_12.setLayout(self.connec_form) groupBox_13.setLayout(self.topology_form) groupBox_14.setLayout(self.builder_form) groupBox_15.setLayout(self.review_form) groupBox_16.setLayout(self.analysis_form) groupBox_17.setLayout(self.system_form) groupBox_18.setLayout(self.node_mantype_form) groupBox_19.setLayout(self.arc_mantype_form) groupBox_20.setLayout(self.connec_mantype_form) groupBox_21.setLayout(self.gully_mantype_form) groupBox_22.setLayout(self.addfields_form) page1_layout1.addWidget(groupBox_1) page1_layout1.addWidget(groupBox_2) page1_layout1.addWidget(groupBox_3) page1_layout1.addWidget(groupBox_4) page1_layout2.addWidget(groupBox_5) page1_layout2.addWidget(groupBox_6) page1_layout2.addWidget(groupBox_7) page1_layout2.addWidget(groupBox_8) page2_layout1.addWidget(groupBox_9) page2_layout1.addWidget(groupBox_10) page2_layout2.addWidget(groupBox_11) page2_layout2.addWidget(groupBox_12) admin_layout1.addWidget(groupBox_13) admin_layout2.addWidget(groupBox_14) admin_layout2.addWidget(groupBox_15) admin_layout2.addWidget(groupBox_16) admin_layout2.addWidget(groupBox_17) man_layout1.addWidget(groupBox_18) man_layout2.addWidget(groupBox_19) man_layout2.addWidget(groupBox_20) man_layout2.addWidget(groupBox_21) addfields_layout1.addWidget(groupBox_22) verticalSpacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) page1_layout1.addItem(verticalSpacer1) page1_layout2.addItem(verticalSpacer1) page2_layout1.addItem(verticalSpacer1) page2_layout2.addItem(verticalSpacer1) admin_layout1.addItem(verticalSpacer1) admin_layout2.addItem(verticalSpacer1) man_layout1.addItem(verticalSpacer1) man_layout2.addItem(verticalSpacer1) addfields_layout1.addItem(verticalSpacer1) # Event on change from combo parent self.get_event_combo_parent( complet_list[0]['body']['form']['formTabs']) # Set signals Combo parent/child chk_expl = self.dlg_config.tab_main.findChild( QWidget, 'chk_exploitation_vdefault') chk_dma = self.dlg_config.tab_main.findChild(QWidget, 'chk_dma_vdefault') if chk_dma and chk_expl: chk_dma.stateChanged.connect( partial(self.check_child_to_parent, chk_dma, chk_expl)) chk_expl.stateChanged.connect( partial(self.check_parent_to_child, chk_expl, chk_dma)) self.hide_void_groupbox(self.dlg_config) # Check user/role and remove tabs role_admin = self.controller.check_role_user("role_admin", cur_user) if not role_admin and cur_user not in super_users: utils_giswater.remove_tab_by_tabName(self.dlg_config.tab_main, "tab_admin") # Open form self.open_dialog(self.dlg_config)
class RemoteRefDialog(QDialog): def __init__(self, repo, parent = None): super(RemoteRefDialog, self).__init__(parent) self.remote = None self.branch = None self.repo = repo self.initGui() def initGui(self): self.setWindowTitle('Remote connection reference') verticalLayout = QVBoxLayout() horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) remoteLabel = QLabel('Remote connection') self.remoteCombo = QComboBox() self.remotes = self.repo.remotes() self.remoteCombo.addItems(list(self.remotes.keys())) self.remoteCombo.currentIndexChanged.connect(self.currentRemoteChanged) horizontalLayout.addWidget(remoteLabel) horizontalLayout.addWidget(self.remoteCombo) verticalLayout.addLayout(horizontalLayout) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) branchLabel = QLabel('Branch') self.branchCombo = QComboBox() self.branchCombo.addItems(self.repo.branches()) horizontalLayout.addWidget(branchLabel) horizontalLayout.addWidget(self.branchCombo) verticalLayout.addLayout(horizontalLayout) self.groupBox = QGroupBox() self.groupBox.setTitle("Remote connection info") self.groupBox.setLayout(verticalLayout) layout = QVBoxLayout() layout.addWidget(self.groupBox) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(self.buttonBox) self.setLayout(layout) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.resize(400, 200) def currentRemoteChanged(self): self.branchCombo.clear() remote = self.remoteCombo.currentText() try: repo = Repository(self.remotes[remote]) branches = repo.branches() self.branchCombo.addItems(branches) except: QMessageBox.warning(self, "Wrong connection", "The selected remote connection is not available or not supported.\n" "Only http-based connections are supported") return def okPressed(self): remote = self.remoteCombo.currentText().strip() if remote: self.remote = remote else: QMessageBox.warning(self, "Missing value", "Please select a remote connection") return branch = self.branchCombo.currentText().strip() if branch: self.branch = branch else: QMessageBox.warning(self, "Missing value", "Please select a branch") return self.close() def cancelPressed(self): self.remote = None self.branch = None self.close()
def restore_default_values_page(self): """Setup UI for default values setting.""" # Clear parameters so it doesn't add parameters when # restore from changes. if self.default_value_parameters: self.default_value_parameters = [] if self.default_value_parameter_containers: self.default_value_parameter_containers = [] for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) default_fields = all_default_fields() for field_group in all_field_groups: settable_fields = [] for field in field_group['fields']: if field not in default_fields: continue else: settable_fields.append(field) default_fields.remove(field) if not settable_fields: continue # Create group box for each field group group_box = QGroupBox(self) group_box.setTitle(field_group['name']) self.container_layout.addWidget(group_box) parameters = [] for settable_field in settable_fields: parameter = self.default_field_to_parameter(settable_field) if parameter: parameters.append(parameter) parameter_container = ParameterContainer( parameters, description_text=field_group['description'], extra_parameters=extra_parameter) parameter_container.setup_ui(must_scroll=False) group_box_inner_layout = QVBoxLayout() group_box_inner_layout.addWidget(parameter_container) group_box.setLayout(group_box_inner_layout) # Add to attribute self.default_value_parameter_containers.append(parameter_container) # Only show non-groups default fields if there is one if len(default_fields) > 0: for default_field in default_fields: parameter = self.default_field_to_parameter(default_field) if parameter: self.default_value_parameters.append(parameter) description_text = tr( 'In this options you can change the global default values for ' 'these variables.') parameter_container = ParameterContainer( self.default_value_parameters, description_text=description_text, extra_parameters=extra_parameter) parameter_container.setup_ui(must_scroll=False) self.other_group_box = QGroupBox(tr('Non-group fields')) other_group_inner_layout = QVBoxLayout() other_group_inner_layout.addWidget(parameter_container) self.other_group_box.setLayout(other_group_inner_layout) self.container_layout.addWidget(self.other_group_box) # Add to attribute self.default_value_parameter_containers.append(parameter_container)
class RemoteRefDialog(QDialog): def __init__(self, repo, parent=None): super(RemoteRefDialog, self).__init__(parent) self.remote = None self.branch = None self.repo = repo self.initGui() def initGui(self): self.setWindowTitle('Remote reference') verticalLayout = QVBoxLayout() horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) remoteLabel = QLabel('Remote') self.remoteCombo = QComboBox() self.remotes = self.repo.remotes() self.remoteCombo.addItems(list(self.remotes.keys())) self.remoteCombo.currentIndexChanged.connect(self.currentRemoteChanged) horizontalLayout.addWidget(remoteLabel) horizontalLayout.addWidget(self.remoteCombo) verticalLayout.addLayout(horizontalLayout) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) branchLabel = QLabel('Branch') self.branchCombo = QComboBox() self.branchCombo.addItems(self.repo.branches()) horizontalLayout.addWidget(branchLabel) horizontalLayout.addWidget(self.branchCombo) verticalLayout.addLayout(horizontalLayout) self.groupBox = QGroupBox() self.groupBox.setTitle("Remote info") self.groupBox.setLayout(verticalLayout) layout = QVBoxLayout() layout.addWidget(self.groupBox) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(self.buttonBox) self.setLayout(layout) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.resize(400, 200) def currentRemoteChanged(self): remote = self.remoteCombo.currentText() repo = Repository(self.remotes[remote]) #TODO handle case of remote not being available branches = repo.branches() self.branchesCombo.clear() self.branchesCombo.addItems(branches) def okPressed(self): remote = self.remoteCombo.currentText().strip() if remote: self.remote = remote else: QMessageBox.warning(self, "Missing value", "Please select a remote") return branch = self.branchCombo.currentText().strip() if branch: self.branch = branch else: QMessageBox.warning(self, "Missing value", "Please select a branch") return self.close() def cancelPressed(self): self.remote = None self.branch = None self.close()
class OptionsDialog(QDialog, FORM_CLASS): """Options dialog for the InaSAFE plugin.""" def __init__(self, iface, parent=None, qsetting=''): """Constructor for the dialog. :param iface: A Quantum GIS QgisAppInterface instance. :type iface: QgisAppInterface :param parent: Parent widget of this dialog :type parent: QWidget :param qsetting: String to specify the QSettings. By default, use empty string. :type qsetting: str """ QDialog.__init__(self, parent) self.setupUi(self) icon = resources_path('img', 'icons', 'configure-inasafe.svg') self.setWindowIcon(QIcon(icon)) self.setWindowTitle(self.tr('InaSAFE %s Options' % get_version())) # Save reference to the QGIS interface and parent self.iface = iface self.parent = parent if qsetting: self.settings = QSettings(qsetting) else: self.settings = QSettings() # InaSAFE default values self.default_value_parameters = [] self.default_value_parameter_containers = [] # Flag for restore default values self.is_restore_default = False # List of setting key and control self.boolean_settings = { 'visibleLayersOnlyFlag': self.cbxVisibleLayersOnly, 'set_layer_from_title_flag': self.cbxSetLayerNameFromTitle, 'setZoomToImpactFlag': self.cbxZoomToImpact, 'set_show_only_impact_on_report': self.cbx_show_only_impact, 'print_atlas_report': self.cbx_print_atlas_report, 'setHideExposureFlag': self.cbxHideExposure, 'useSelectedFeaturesOnly': self.cbxUseSelectedFeaturesOnly, 'useSentry': self.cbxUseSentry, 'template_warning_verbose': self.template_warning_checkbox, 'showOrganisationLogoInDockFlag': self.organisation_on_dock_checkbox, 'developer_mode': self.cbxDevMode, 'generate_report': self.checkbox_generate_reports, 'memory_profile': self.check_box_memory, 'always_show_welcome_message': self.welcome_message_check_box } self.text_settings = { 'keywordCachePath': self.leKeywordCachePath, 'ISO19115_ORGANIZATION': self.organisation_line_edit, 'ISO19115_URL': self.website_line_edit, 'ISO19115_EMAIL': self.email_line_edit, 'ISO19115_LICENSE': self.license_line_edit, } # Export and Import button # Export button self.export_button = QPushButton(tr('Export')) # noinspection PyUnresolvedReferences self.export_button.clicked.connect(self.export_setting) self.button_box.addButton( self.export_button, QDialogButtonBox.ActionRole) # Import button self.import_button = QPushButton(tr('Import')) # noinspection PyUnresolvedReferences self.import_button.clicked.connect(self.import_setting) self.button_box.addButton( self.import_button, QDialogButtonBox.ActionRole) # Set up things for context help self.help_button = self.button_box.button(QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) self.main_stacked_widget.setCurrentIndex(1) # Always set first tab to be open, 0-th index self.tabWidget.setCurrentIndex(0) # Hide not implemented group self.grpNotImplemented.hide() self.adjustSize() # Population parameter Tab # Label self.preference_label = QLabel() self.preference_label.setText(tr( 'Please set parameters for each hazard class below. Affected ' 'status and displacement rates selected on this tab are only ' 'applied to exposed populations. ' )) self.preference_layout.addWidget(self.preference_label) # Profile preference widget self.profile_widget = ProfileWidget() self.preference_layout.addWidget(self.profile_widget) # Demographic tab self.demographic_label = QLabel() self.demographic_label.setText(tr( 'Please set the global default demographic ratio below.')) self.default_values_layout.addWidget(self.demographic_label) self.scroll_area = QScrollArea() self.scroll_area.setWidgetResizable(True) self.widget_container = QWidget() self.scroll_area.setWidget(self.widget_container) self.container_layout = QVBoxLayout() self.widget_container.setLayout(self.container_layout) self.default_values_layout.addWidget(self.scroll_area) # Restore state from setting self.restore_state() # Hide checkbox if not developers if not self.cbxDevMode.isChecked(): self.checkbox_generate_reports.hide() # Connections # Check boxes self.custom_north_arrow_checkbox.toggled.connect(self.set_north_arrow) self.custom_UseUserDirectory_checkbox.toggled.connect( self.set_user_dir) self.custom_templates_dir_checkbox.toggled.connect( self.set_templates_dir) self.custom_org_disclaimer_checkbox.toggled.connect( self.set_org_disclaimer) self.custom_organisation_logo_check_box.toggled.connect( self.toggle_logo_path) # Buttons self.toolKeywordCachePath.clicked.connect(self.open_keyword_cache_path) self.toolUserDirectoryPath.clicked.connect( self.open_user_directory_path) self.toolNorthArrowPath.clicked.connect(self.open_north_arrow_path) self.open_organisation_logo_path_button.clicked.connect( self.open_organisation_logo_path) self.toolReportTemplatePath.clicked.connect( self.open_report_template_path) # Others self.organisation_logo_path_line_edit.textChanged.connect( self.update_logo_preview) self.earthquake_function.currentIndexChanged.connect( self.update_earthquake_info) # Set up listener for restore defaults button self.demographic_restore_defaults = self.button_box_restore_defaults.\ button(QDialogButtonBox.RestoreDefaults) self.demographic_restore_defaults.setText( self.demographic_restore_defaults.text().capitalize()) self.demographic_restore_defaults.setCheckable(True) self.demographic_restore_defaults.clicked.connect( self.restore_defaults_ratio) # Restore button in population parameter tab self.parameter_population_restore_button = \ self.button_box_restore_preference.button( QDialogButtonBox.RestoreDefaults) self.parameter_population_restore_button.setText( self.parameter_population_restore_button.text().capitalize()) self.parameter_population_restore_button.clicked.connect( partial(self.restore_population_parameters, global_default=True)) # TODO: Hide this until behaviour is defined # hide template warning toggle self.template_warning_checkbox.hide() # hide custom template dir toggle self.custom_templates_dir_checkbox.hide() self.splitter_custom_report.hide() # Welcome message self.set_welcome_message() def save_boolean_setting(self, key, check_box): """Save boolean setting according to check_box state. :param key: Key to retrieve setting value. :type key: str :param check_box: Check box to show and set the setting. :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox """ set_setting(key, check_box.isChecked(), qsettings=self.settings) def restore_boolean_setting(self, key, check_box): """Set check_box according to setting of key. :param key: Key to retrieve setting value. :type key: str :param check_box: Check box to show and set the setting. :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox """ flag = setting(key, expected_type=bool, qsettings=self.settings) check_box.setChecked(flag) def save_text_setting(self, key, line_edit): """Save text setting according to line_edit value. :param key: Key to retrieve setting value. :type key: str :param line_edit: Line edit for user to edit the setting :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit """ set_setting(key, line_edit.text(), self.settings) def restore_text_setting(self, key, line_edit): """Set line_edit text according to setting of key. :param key: Key to retrieve setting value. :type key: str :param line_edit: Line edit for user to edit the setting :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit """ value = setting(key, expected_type=str, qsettings=self.settings) line_edit.setText(value) def restore_state(self): """Reinstate the options based on the user's stored session info.""" # Restore boolean setting as check box. for key, check_box in list(self.boolean_settings.items()): self.restore_boolean_setting(key, check_box) # Restore text setting as line edit. for key, line_edit in list(self.text_settings.items()): self.restore_text_setting(key, line_edit) # User Directory user_directory_path = setting( key='defaultUserDirectory', default=temp_dir('impacts'), expected_type=str, qsettings=self.settings) custom_user_directory_flag = ( user_directory_path != temp_dir('impacts')) self.custom_UseUserDirectory_checkbox.setChecked( custom_user_directory_flag) self.splitter_user_directory.setEnabled(custom_user_directory_flag) self.leUserDirectoryPath.setText(user_directory_path) # Currency # Populate the currency list for currency in currencies: self.currency_combo_box.addItem(currency['name'], currency['key']) # Then make selected the default one. default_currency = setting('currency', expected_type=str) keys = [currency['key'] for currency in currencies] if default_currency not in keys: default_currency = currencies[0]['key'] index = self.currency_combo_box.findData(default_currency) self.currency_combo_box.setCurrentIndex(index) # Earthquake function. # Populate the combobox first. for model in EARTHQUAKE_FUNCTIONS: self.earthquake_function.addItem(model['name'], model['key']) # Then make selected the default one. default_earthquake_function = setting( 'earthquake_function', expected_type=str) keys = [model['key'] for model in EARTHQUAKE_FUNCTIONS] if default_earthquake_function not in keys: default_earthquake_function = EARTHQUAKE_FUNCTIONS[0]['key'] index = self.earthquake_function.findData(default_earthquake_function) self.earthquake_function.setCurrentIndex(index) self.update_earthquake_info() # Restore North Arrow Image Path north_arrow_path = setting( key='north_arrow_path', default=default_north_arrow_path(), expected_type=str, qsettings=self.settings) custom_north_arrow_flag = ( north_arrow_path != default_north_arrow_path()) self.custom_north_arrow_checkbox.setChecked(custom_north_arrow_flag) self.splitter_north_arrow.setEnabled(custom_north_arrow_flag) self.leNorthArrowPath.setText(north_arrow_path) # Restore Report Template Directory Path report_template_directory = setting( key='reportTemplatePath', default='', expected_type=str, qsettings=self.settings) custom_templates_dir_flag = (report_template_directory != '') self.custom_templates_dir_checkbox.setChecked( custom_templates_dir_flag) self.leReportTemplatePath.setText(report_template_directory) # Restore Disclaimer org_disclaimer = setting( key='reportDisclaimer', default=disclaimer(), expected_type=str, qsettings=self.settings) custom_org_disclaimer_flag = (org_disclaimer != disclaimer()) self.custom_org_disclaimer_checkbox.setChecked( custom_org_disclaimer_flag) self.txtDisclaimer.setPlainText(org_disclaimer) # Restore Organisation Logo Path org_logo_path = setting( key='organisation_logo_path', default=supporters_logo_path(), expected_type=str, qsettings=self.settings) # Check if the path is default one or not custom_org_logo_flag = org_logo_path != supporters_logo_path() self.organisation_logo_path_line_edit.setText(org_logo_path) self.custom_organisation_logo_check_box.setChecked( custom_org_logo_flag) self.organisation_logo_path_line_edit.setEnabled( custom_org_logo_flag) self.open_organisation_logo_path_button.setEnabled( custom_org_logo_flag) # Manually call here self.update_logo_preview() # Restore InaSAFE default values self.restore_default_values_page() # Restore Population Parameter self.restore_population_parameters(global_default=False) def save_state(self): """Store the options into the user's stored session info.""" # Save boolean settings for key, check_box in list(self.boolean_settings.items()): self.save_boolean_setting(key, check_box) # Save text settings for key, line_edit in list(self.text_settings.items()): self.save_text_setting(key, line_edit) set_setting( 'north_arrow_path', self.leNorthArrowPath.text(), self.settings) set_setting( 'organisation_logo_path', self.organisation_logo_path_line_edit.text(), self.settings) set_setting( 'reportTemplatePath', self.leReportTemplatePath.text(), self.settings) set_setting( 'reportDisclaimer', self.txtDisclaimer.toPlainText(), self.settings) set_setting( 'defaultUserDirectory', self.leUserDirectoryPath.text(), self.settings) index = self.earthquake_function.currentIndex() value = self.earthquake_function.itemData(index) set_setting('earthquake_function', value, qsettings=self.settings) currency_index = self.currency_combo_box.currentIndex() currency_key = self.currency_combo_box.itemData(currency_index) set_setting('currency', currency_key, qsettings=self.settings) # Save InaSAFE default values self.save_default_values() # Save population parameters self.save_population_parameters() def accept(self): """Method invoked when OK button is clicked.""" self.save_state() super(OptionsDialog, self).accept() def update_earthquake_info(self): """Update information about earthquake info.""" self.label_earthquake_model() current_index = self.earthquake_function.currentIndex() model = EARTHQUAKE_FUNCTIONS[current_index] notes = '' for note in model['notes']: notes += note + '\n\n' citations = '' for citation in model['citations']: citations += citation['text'] + '\n\n' text = tr( 'Description:\n\n%s\n\n' 'Notes:\n\n%s\n\n' 'Citations:\n\n%s') % ( model['description'], notes, citations) self.earthquake_fatality_model_notes.setText(text) def label_earthquake_model(self): model = self.earthquake_function.currentText() help_text = tr( 'Please select your preferred earthquake fatality model. The ' 'default fatality model is the {model}.').format(model=model) self.label_default_earthquake.setText(help_text) def open_keyword_cache_path(self): """Open File dialog to choose the keyword cache path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getSaveFileName( self, self.tr('Set keyword cache file'), self.leKeywordCachePath.text(), self.tr('Sqlite DB File (*.db)')) if file_name: self.leKeywordCachePath.setText(file_name) def open_user_directory_path(self): """Open File dialog to choose the user directory path.""" # noinspection PyCallByClass,PyTypeChecker directory_name = QFileDialog.getExistingDirectory( self, self.tr('Results directory'), self.leUserDirectoryPath.text(), QFileDialog.ShowDirsOnly) if directory_name: self.leUserDirectoryPath.setText(directory_name) def open_north_arrow_path(self): """Open File dialog to choose the north arrow path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getOpenFileName( self, self.tr('Set north arrow image file'), self.leNorthArrowPath.text(), self.tr( 'Portable Network Graphics files (*.png *.PNG);;' 'JPEG Images (*.jpg *.jpeg);;' 'GIF Images (*.gif *.GIF);;' 'SVG Images (*.svg *.SVG);;')) if file_name: self.leNorthArrowPath.setText(file_name) def open_organisation_logo_path(self): """Open File dialog to choose the organisation logo path.""" # noinspection PyCallByClass,PyTypeChecker file_name, __ = QFileDialog.getOpenFileName( self, self.tr('Set organisation logo file'), self.organisation_logo_path_line_edit.text(), self.tr( 'Portable Network Graphics files (*.png *.PNG);;' 'JPEG Images (*.jpg *.jpeg);;' 'GIF Images (*.gif *.GIF);;' 'SVG Images (*.svg *.SVG);;')) if file_name: self.organisation_logo_path_line_edit.setText(file_name) def open_report_template_path(self): """Open File dialog to choose the report template path.""" # noinspection PyCallByClass,PyTypeChecker directory_name = QFileDialog.getExistingDirectory( self, self.tr('Templates directory'), self.leReportTemplatePath.text(), QFileDialog.ShowDirsOnly) if directory_name: self.leReportTemplatePath.setText(directory_name) def toggle_logo_path(self): """Set state of logo path line edit and button.""" is_checked = self.custom_organisation_logo_check_box.isChecked() if is_checked: # Use previous org logo path path = setting( key='organisation_logo_path', default=supporters_logo_path(), expected_type=str, qsettings=self.settings) else: # Set organisation path line edit to default one path = supporters_logo_path() self.organisation_logo_path_line_edit.setText(path) self.organisation_logo_path_line_edit.setEnabled(is_checked) self.open_organisation_logo_path_button.setEnabled(is_checked) def update_logo_preview(self): """Update logo based on the current logo path.""" logo_path = self.organisation_logo_path_line_edit.text() if os.path.exists(logo_path): icon = QPixmap(logo_path) label_size = self.organisation_logo_label.size() label_size.setHeight(label_size.height() - 2) label_size.setWidth(label_size.width() - 2) scaled_icon = icon.scaled( label_size, Qt.KeepAspectRatio) self.organisation_logo_label.setPixmap(scaled_icon) else: self.organisation_logo_label.setText(tr("Logo not found")) def set_north_arrow(self): """Auto-connect slot activated when north arrow checkbox is toggled.""" is_checked = self.custom_north_arrow_checkbox.isChecked() if is_checked: # Show previous north arrow path path = setting( key='north_arrow_path', default=default_north_arrow_path(), expected_type=str, qsettings=self.settings) else: # Set the north arrow line edit to default one path = default_north_arrow_path() self.leNorthArrowPath.setText(path) self.splitter_north_arrow.setEnabled(is_checked) def set_user_dir(self): """Auto-connect slot activated when user dir checkbox is toggled. """ is_checked = self.custom_UseUserDirectory_checkbox.isChecked() if is_checked: # Show previous templates dir path = setting( key='defaultUserDirectory', default='', expected_type=str, qsettings=self.settings) else: # Set the template report dir to '' path = temp_dir('impacts') self.leUserDirectoryPath.setText(path) self.splitter_user_directory.setEnabled(is_checked) def set_templates_dir(self): """Auto-connect slot activated when templates dir checkbox is toggled. """ is_checked = self.custom_templates_dir_checkbox.isChecked() if is_checked: # Show previous templates dir path = setting( key='reportTemplatePath', default='', expected_type=str, qsettings=self.settings) else: # Set the template report dir to '' path = '' self.leReportTemplatePath.setText(path) self.splitter_custom_report.setEnabled(is_checked) def set_org_disclaimer(self): """Auto-connect slot activated when org disclaimer checkbox is toggled. """ is_checked = self.custom_org_disclaimer_checkbox.isChecked() if is_checked: # Show previous organisation disclaimer org_disclaimer = setting( 'reportDisclaimer', default=disclaimer(), expected_type=str, qsettings=self.settings) else: # Set the organisation disclaimer to the default one org_disclaimer = disclaimer() self.txtDisclaimer.setPlainText(org_disclaimer) self.txtDisclaimer.setEnabled(is_checked) @pyqtSlot(bool) # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.2.1 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded: 3.2.1 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user.""" # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = options_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def restore_default_values_page(self): """Setup UI for default values setting.""" # Clear parameters so it doesn't add parameters when # restore from changes. if self.default_value_parameters: self.default_value_parameters = [] if self.default_value_parameter_containers: self.default_value_parameter_containers = [] for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) default_fields = all_default_fields() for field_group in all_field_groups: settable_fields = [] for field in field_group['fields']: if field not in default_fields: continue else: settable_fields.append(field) default_fields.remove(field) if not settable_fields: continue # Create group box for each field group group_box = QGroupBox(self) group_box.setTitle(field_group['name']) self.container_layout.addWidget(group_box) parameters = [] for settable_field in settable_fields: parameter = self.default_field_to_parameter(settable_field) if parameter: parameters.append(parameter) parameter_container = ParameterContainer( parameters, description_text=field_group['description'], extra_parameters=extra_parameter ) parameter_container.setup_ui(must_scroll=False) group_box_inner_layout = QVBoxLayout() group_box_inner_layout.addWidget(parameter_container) group_box.setLayout(group_box_inner_layout) # Add to attribute self.default_value_parameter_containers.append(parameter_container) # Only show non-groups default fields if there is one if len(default_fields) > 0: for default_field in default_fields: parameter = self.default_field_to_parameter(default_field) if parameter: self.default_value_parameters.append(parameter) description_text = tr( 'In this options you can change the global default values for ' 'these variables.') parameter_container = ParameterContainer( self.default_value_parameters, description_text=description_text, extra_parameters=extra_parameter ) parameter_container.setup_ui(must_scroll=False) self.other_group_box = QGroupBox(tr('Non-group fields')) other_group_inner_layout = QVBoxLayout() other_group_inner_layout.addWidget(parameter_container) self.other_group_box.setLayout(other_group_inner_layout) self.container_layout.addWidget(self.other_group_box) # Add to attribute self.default_value_parameter_containers.append(parameter_container) def restore_population_parameters(self, global_default=True): """Setup UI for population parameter page from setting. :param global_default: If True, set to original default (from the value in definitions). :type global_default: bool """ if global_default: data = generate_default_profile() else: data = setting('population_preference', generate_default_profile()) if not isinstance(data, dict): LOGGER.debug( 'population parameter is not a dictionary. InaSAFE will use ' 'the default one.') data = generate_default_profile() try: self.profile_widget.data = data except KeyError as e: LOGGER.debug( 'Population parameter is not in correct format. InaSAFE will ' 'use the default one.') LOGGER.debug(e) data = generate_default_profile() self.profile_widget.data = data @staticmethod def age_ratios(): """Helper to get list of age ratio from the options dialog. :returns: List of age ratio. :rtype: list """ # FIXME(IS) set a correct parameter container parameter_container = None youth_ratio = parameter_container.get_parameter_by_guid( youth_ratio_field['key']).value adult_ratio = parameter_container.get_parameter_by_guid( adult_ratio_field['key']).value elderly_ratio = parameter_container.get_parameter_by_guid( elderly_ratio_field['key']).value ratios = [youth_ratio, adult_ratio, elderly_ratio] return ratios def is_good_age_ratios(self): """Method to check the sum of age ratio is 1. :returns: True if the sum is 1 or the sum less than 1 but there is None. :rtype: bool """ ratios = self.age_ratios() if None in ratios: # If there is None, just check to not exceeding 1 clean_ratios = [x for x in ratios if x is not None] ratios.remove(None) if sum(clean_ratios) > 1: return False else: if sum(ratios) != 1: return False return True def save_default_values(self): """Save InaSAFE default values.""" for parameter_container in self.default_value_parameter_containers: parameters = parameter_container.get_parameters() for parameter in parameters: set_inasafe_default_value_qsetting( self.settings, GLOBAL, parameter.guid, parameter.value ) def restore_defaults_ratio(self): """Restore InaSAFE default ratio.""" # Set the flag to true because user ask to. self.is_restore_default = True # remove current default ratio for i in reversed(list(range(self.container_layout.count()))): widget = self.container_layout.itemAt(i).widget() if widget is not None: widget.setParent(None) # reload default ratio self.restore_default_values_page() def default_field_to_parameter(self, default_field): """Obtain parameter from default field. :param default_field: A default field definition. :type default_field: dict :returns: A parameter object. :rtype: FloatParameter, IntegerParameter """ if default_field.get('type') == QVariant.Double: parameter = FloatParameter() elif default_field.get('type') in qvariant_whole_numbers: parameter = IntegerParameter() else: return default_value = default_field.get('default_value') if not default_value: message = ( 'InaSAFE default field %s does not have default value' % default_field.get('name')) LOGGER.exception(message) return parameter.guid = default_field.get('key') parameter.name = default_value.get('name') parameter.is_required = True parameter.precision = default_field.get('precision') parameter.minimum_allowed_value = default_value.get( 'min_value', 0) parameter.maximum_allowed_value = default_value.get( 'max_value', 100000000) parameter.help_text = default_value.get('help_text') parameter.description = default_value.get('description') # Check if user ask to restore to the most default value. if self.is_restore_default: parameter._value = default_value.get('default_value') else: # Current value qsetting_default_value = get_inasafe_default_value_qsetting( self.settings, GLOBAL, default_field['key']) # To avoid python error if qsetting_default_value > parameter.maximum_allowed_value: qsetting_default_value = parameter.maximum_allowed_value if qsetting_default_value < parameter.minimum_allowed_value: qsetting_default_value = parameter.minimum_allowed_value parameter.value = qsetting_default_value return parameter def save_population_parameters(self): """Helper to save population parameter to QSettings.""" population_parameter = self.profile_widget.data set_setting('population_preference', population_parameter) def set_welcome_message(self): """Create and insert welcome message.""" string = html_header() string += welcome_message().to_html() string += html_footer() self.welcome_message.setHtml(string) def show_option_dialog(self): """Helper to show usual option dialog (without welcome message tab).""" self.tabWidget.removeTab(0) def show_welcome_dialog(self): """Setup for showing welcome message dialog. This method will setup several things: - Only show welcome, organisation profile, and population parameter tab. Currently, they are the first 3 tabs. - Set the title - Move the check box for always showing welcome message. """ self.welcome_layout.addWidget(self.welcome_message_check_box) while self.tabWidget.count() > 3: self.tabWidget.removeTab(self.tabWidget.count() - 1) self.setWindowTitle(self.tr('Welcome to InaSAFE %s' % get_version())) # Hide the export import button self.export_button.hide() self.import_button.hide() def export_setting(self): """Export setting from an existing file.""" LOGGER.debug('Export button clicked') home_directory = os.path.expanduser('~') file_name = self.organisation_line_edit.text().replace(' ', '_') file_path, __ = QFileDialog.getSaveFileName( self, self.tr('Export InaSAFE settings'), os.path.join(home_directory, file_name + '.json'), self.tr('JSON File (*.json)')) if file_path: LOGGER.debug('Exporting to %s' % file_path) export_setting(file_path) def import_setting(self): """Import setting to a file.""" LOGGER.debug('Import button clicked') home_directory = os.path.expanduser('~') file_path, __ = QFileDialog.getOpenFileName( self, self.tr('Import InaSAFE settings'), home_directory, self.tr('JSON File (*.json)')) if file_path: title = tr('Import InaSAFE Settings.') question = tr( 'This action will replace your current InaSAFE settings with ' 'the setting from the file. This action is not reversible. ' 'Are you sure to import InaSAFE Setting?') answer = QMessageBox.question( self, title, question, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: LOGGER.debug('Import from %s' % file_path) import_setting(file_path)
def open_catalog(self, previous_dialog, widget_name, feature_type, child_type): """ Main function of catalog """ # Manage if feature_type is gully and set grate if feature_type == 'gully': feature_type = 'grate' form_name = 'upsert_catalog_' + feature_type + '' form = f'"formName":"{form_name}", "tabName":"data", "editable":"TRUE"' feature = f'"feature_type":"{child_type}"' body = tools_gw.create_body(form, feature) json_result = tools_gw.execute_procedure('gw_fct_getcatalog', body, log_sql=True) if json_result is None: return group_box_1 = QGroupBox("Filter") self.filter_form = QGridLayout() self.dlg_catalog = GwInfoCatalogUi() tools_gw.load_settings(self.dlg_catalog) self.dlg_catalog.btn_cancel.clicked.connect( partial(tools_gw.close_dialog, self.dlg_catalog)) self.dlg_catalog.btn_accept.clicked.connect( partial(self._fill_geomcat_id, previous_dialog, widget_name)) main_layout = self.dlg_catalog.widget.findChild( QGridLayout, 'main_layout') result = json_result['body']['data'] for field in result['fields']: label = QLabel() label.setObjectName('lbl_' + field['label']) label.setText(field['label'].capitalize()) widget = None if field['widgettype'] == 'combo': widget = self._add_combobox(field) if field['layoutname'] == 'lyt_data_1': self.filter_form.addWidget(label, field['layoutorder'], 0) self.filter_form.addWidget(widget, field['layoutorder'], 1) group_box_1.setLayout(self.filter_form) main_layout.addWidget(group_box_1) vertical_spacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) main_layout.addItem(vertical_spacer1) matcat_id = self.dlg_catalog.findChild(QComboBox, 'matcat_id') pnom = None dnom = None if tools_gw.get_project_type() == 'ws': pnom = self.dlg_catalog.findChild(QComboBox, 'pnom') dnom = self.dlg_catalog.findChild(QComboBox, 'dnom') elif tools_gw.get_project_type() == 'ud': pnom = self.dlg_catalog.findChild(QComboBox, 'shape') dnom = self.dlg_catalog.findChild(QComboBox, 'geom1') id = self.dlg_catalog.findChild(QComboBox, 'id') # Call _get_catalog first time self._get_catalog(matcat_id, pnom, dnom, id, feature_type, child_type) # Set Listeners if matcat_id: matcat_id.currentIndexChanged.connect( partial(self._populate_pn_dn, matcat_id, pnom, dnom, feature_type, child_type)) if pnom: pnom.currentIndexChanged.connect( partial(self._get_catalog, matcat_id, pnom, dnom, id, feature_type, child_type)) if dnom: dnom.currentIndexChanged.connect( partial(self._get_catalog, matcat_id, pnom, dnom, id, feature_type, child_type)) # Set shortcut keys self.dlg_catalog.key_escape.connect( partial(tools_gw.close_dialog, self.dlg_catalog)) # Open form tools_gw.open_dialog(self.dlg_catalog, dlg_name='info_catalog')
def getGroupBox(name, parent, widgets): lyt = getLayout(parent, widgets) gbx = QGroupBox(name, parent) gbx.setLayout(lyt) return gbx
class LoadOutputAsLayerDialog(QDialog, FORM_CLASS): """ Dialog to load an oq-engine output as layer """ init_done = pyqtSignal(QDialog) loading_completed = pyqtSignal(QDialog) loading_exception = pyqtSignal(QDialog, Exception) def __init__(self, drive_engine_dlg, iface, viewer_dock, session, hostname, calc_id, output_type=None, path=None, mode=None, zonal_layer_path=None, engine_version=None, calculation_mode=None): # sanity check if output_type not in OQ_TO_LAYER_TYPES: raise NotImplementedError(output_type) self.drive_engine_dlg = drive_engine_dlg self.iface = iface self.viewer_dock = viewer_dock self.path = path self.session = session self.hostname = hostname self.calc_id = calc_id self.output_type = output_type self.mode = mode # if 'testing' it will avoid some user interaction self.zonal_layer_path = zonal_layer_path self.engine_version = engine_version self.calculation_mode = calculation_mode QDialog.__init__(self) # Set up the user interface from Designer. self.setupUi(self) # Disable ok_button until all user options are set self.ok_button = self.buttonBox.button(QDialogButtonBox.Ok) self.ok_button.setDisabled(True) self.oqparam = self.drive_engine_dlg.get_oqparam() def on_extract_error(self, exception): if isinstance(exception, TaskCanceled): msg = 'Data extraction canceled' log_msg(msg, level='W', message_bar=self.iface.messageBar()) else: log_msg('Unable to complete data extraction', level='C', message_bar=self.iface.messageBar(), exception=exception) self.reject() def finalize_init(self, extracted_npz): self.npz_file = extracted_npz self.populate_out_dep_widgets() self.adjustSize() self.set_ok_button() self.show() self.init_done.emit(self) def create_num_sites_indicator(self): self.num_sites_msg = 'Number of sites: %s' self.num_sites_lbl = QLabel(self.num_sites_msg % '') self.vlayout.addWidget(self.num_sites_lbl) def create_file_size_indicator(self): self.file_size_msg = 'File size: %s' self.file_size_lbl = QLabel(self.file_size_msg % '') self.vlayout.addWidget(self.file_size_lbl) def create_single_layer_ckb(self): self.load_single_layer_ckb = QCheckBox( 'Load one layer containing all hazard maps') self.vlayout.addWidget(self.load_single_layer_ckb) def create_load_one_layer_per_stat_ckb(self): self.load_one_layer_per_stat_ckb = QCheckBox( 'Load one layer per realization or statistic') self.vlayout.addWidget(self.load_one_layer_per_stat_ckb) def create_min_mag_dsb(self, min_mag=4.0): self.min_mag_lbl = QLabel() self.min_mag_dsb = QDoubleSpinBox(self) self.min_mag_dsb.setRange(0, 10) self.min_mag_dsb.setDecimals(1) self.min_mag_dsb.setSingleStep(0.1) self.min_mag_dsb.setValue(min_mag) self.vlayout.addWidget(self.min_mag_lbl) self.vlayout.addWidget(self.min_mag_dsb) # NOTE: if we don't modify the text of the label after adding the # widget to the layout, the adjustSize does not work properly, for some # unknown reason self.min_mag_lbl.setText('Minimum magnitude') def create_rlz_or_stat_selector(self, all_ckb=False, label='Realization'): self.rlz_or_stat_lbl = QLabel(label) self.rlz_or_stat_cbx = QComboBox() self.rlz_or_stat_cbx.setEnabled(False) self.rlz_or_stat_cbx.currentIndexChanged['QString'].connect( self.on_rlz_or_stat_changed) if all_ckb: self.load_all_rlzs_or_stats_chk = QCheckBox( 'Load all realizations') self.load_all_rlzs_or_stats_chk.stateChanged[int].connect( self.on_load_all_rlzs_or_stats_chk_stateChanged) self.vlayout.addWidget(self.load_all_rlzs_or_stats_chk) self.vlayout.addWidget(self.rlz_or_stat_lbl) self.vlayout.addWidget(self.rlz_or_stat_cbx) def on_load_all_rlzs_or_stats_chk_stateChanged(self, state): self.rlz_or_stat_cbx.setEnabled(state == Qt.Unchecked) def create_selector(self, name, label_text, filter_ckb=False, add_to_layout=None, on_text_changed=None): if add_to_layout is not None: layout = add_to_layout else: layout = self.vlayout setattr(self, "%s_lbl" % name, QLabel(label_text)) setattr(self, "%s_cbx" % name, QComboBox()) lbl = getattr(self, "%s_lbl" % name) cbx = getattr(self, "%s_cbx" % name) cbx.setDisabled(filter_ckb) if on_text_changed is not None: cbx.currentTextChanged['QString'].connect(on_text_changed) if filter_ckb: setattr(self, "filter_by_%s_ckb" % name, QCheckBox('Filter by %s' % name)) filter_ckb = getattr(self, "filter_by_%s_ckb" % name) def on_load_all_ckb_changed(): cbx.setEnabled(filter_ckb.isChecked()) filter_ckb.stateChanged[int].connect(on_load_all_ckb_changed) filter_ckb.setChecked(False) layout.addWidget(filter_ckb) layout.addWidget(lbl) layout.addWidget(cbx) def create_imt_selector(self, all_ckb=False): self.imt_lbl = QLabel('Intensity Measure Type') self.imt_cbx = QComboBox() self.imt_cbx.setEnabled(False) self.imt_cbx.currentIndexChanged['QString'].connect( self.on_imt_changed) if all_ckb: self.load_all_imts_chk = QCheckBox('Load all IMTs') self.load_all_imts_chk.stateChanged[int].connect( self.on_load_all_imts_chk_stateChanged) self.vlayout.addWidget(self.load_all_imts_chk) self.vlayout.addWidget(self.imt_lbl) self.vlayout.addWidget(self.imt_cbx) def on_load_all_imts_chk_stateChanged(self, state): self.imt_cbx.setEnabled(state == Qt.Unchecked) def create_poe_selector(self, all_ckb=False): self.poe_lbl = QLabel('Probability of Exceedance') self.poe_cbx = QComboBox() self.poe_cbx.setEnabled(False) self.poe_cbx.currentIndexChanged['QString'].connect( self.on_poe_changed) if all_ckb: self.load_all_poes_chk = QCheckBox('Load all PoEs') self.load_all_poes_chk.stateChanged[int].connect( self.on_load_all_poes_chk_stateChanged) self.vlayout.addWidget(self.load_all_poes_chk) self.vlayout.addWidget(self.poe_lbl) self.vlayout.addWidget(self.poe_cbx) def on_load_all_poes_chk_stateChanged(self, state): self.poe_cbx.setEnabled(state == Qt.Unchecked) def create_loss_type_selector(self): self.loss_type_lbl = QLabel('Loss Type') self.loss_type_cbx = QComboBox() self.loss_type_cbx.setEnabled(False) self.loss_type_cbx.currentIndexChanged['QString'].connect( self.on_loss_type_changed) self.vlayout.addWidget(self.loss_type_lbl) self.vlayout.addWidget(self.loss_type_cbx) def create_eid_selector(self): self.eid_lbl = QLabel('Event ID') self.eid_sbx = QSpinBox() self.eid_sbx.setEnabled(False) self.vlayout.addWidget(self.eid_lbl) self.vlayout.addWidget(self.eid_sbx) def create_dmg_state_selector(self): self.dmg_state_lbl = QLabel('Damage state') self.dmg_state_cbx = QComboBox() self.dmg_state_cbx.setEnabled(False) self.dmg_state_cbx.currentIndexChanged['QString'].connect( self.on_dmg_state_changed) self.vlayout.addWidget(self.dmg_state_lbl) self.vlayout.addWidget(self.dmg_state_cbx) def create_taxonomy_selector(self): self.taxonomy_lbl = QLabel('Taxonomy') self.taxonomy_cbx = QComboBox() self.taxonomy_cbx.setEnabled(False) self.vlayout.addWidget(self.taxonomy_lbl) self.vlayout.addWidget(self.taxonomy_cbx) def create_style_by_selector(self): self.style_by_lbl = QLabel('Style by') self.style_by_cbx = QComboBox() self.vlayout.addWidget(self.style_by_lbl) self.vlayout.addWidget(self.style_by_cbx) def create_load_selected_only_ckb(self): self.load_selected_only_ckb = QCheckBox("Load only the selected items") self.load_selected_only_ckb.setChecked(True) self.vlayout.addWidget(self.load_selected_only_ckb) def create_show_return_period_ckb(self): self.show_return_period_chk = QCheckBox( "Show the return period in layer names") self.show_return_period_chk.setChecked(False) self.vlayout.addWidget(self.show_return_period_chk) def create_aggregate_by_site_ckb(self): self.aggregate_by_site_ckb = QCheckBox("Aggregate by site") self.aggregate_by_site_ckb.setChecked(True) self.vlayout.addWidget(self.aggregate_by_site_ckb) def create_zonal_layer_selector(self, discard_nonmatching=True): self.added_zonal_layer = None self.zonal_layer_gbx = QGroupBox() self.zonal_layer_gbx.setTitle('Aggregate by zone') self.zonal_layer_gbx.setCheckable(True) self.zonal_layer_gbx.setChecked(False) self.zonal_layer_gbx_v_layout = QVBoxLayout() self.zonal_layer_gbx.setLayout(self.zonal_layer_gbx_v_layout) self.zonal_layer_cbx = QComboBox() self.zonal_layer_cbx.addItem('') self.zonal_layer_lbl = QLabel('Zonal layer') self.zonal_layer_tbn = QToolButton() self.zonal_layer_tbn.setText('...') self.discard_nonmatching_chk = QCheckBox( 'Discard zones with no points') self.discard_nonmatching_chk.setChecked(discard_nonmatching) self.zonal_layer_h_layout = QHBoxLayout() self.zonal_layer_h_layout.addWidget(self.zonal_layer_cbx) self.zonal_layer_h_layout.addWidget(self.zonal_layer_tbn) self.zonal_layer_gbx_v_layout.addWidget(self.zonal_layer_lbl) self.zonal_layer_gbx_v_layout.addLayout(self.zonal_layer_h_layout) self.zonal_layer_gbx_v_layout.addWidget(self.discard_nonmatching_chk) self.vlayout.addWidget(self.zonal_layer_gbx) self.zonal_layer_tbn.clicked.connect(self.open_load_zonal_layer_dialog) self.zonal_layer_cbx.currentIndexChanged[int].connect( self.on_zonal_layer_cbx_currentIndexChanged) self.zonal_layer_gbx.toggled[bool].connect( self.on_zonal_layer_gbx_toggled) self.iface.layerTreeView().currentLayerChanged.connect( self.on_currentLayerChanged) def on_currentLayerChanged(self): self.pre_populate_zonal_layer_cbx() def pre_populate_zonal_layer_cbx(self): # populate cbx only with vector layers containing polygons self.zonal_layer_cbx.clear() for key, layer in QgsProject.instance().mapLayers().items(): if layer.type() != QgsMapLayer.VectorLayer: continue if layer.geometryType() == QgsWkbTypes.PolygonGeometry: self.zonal_layer_cbx.addItem(layer.name()) self.zonal_layer_cbx.setItemData( self.zonal_layer_cbx.count() - 1, layer.id()) if self.added_zonal_layer is not None: self.zonal_layer_cbx.setCurrentIndex( self.zonal_layer_cbx.findData(self.added_zonal_layer.id())) self.zonal_layer_gbx.setChecked( self.zonal_layer_cbx.currentIndex() != -1) def on_zonal_layer_cbx_currentIndexChanged(self, new_index): self.zonal_layer = None if not self.zonal_layer_cbx.currentText(): if self.zonal_layer_gbx.isChecked(): self.ok_button.setEnabled(False) return zonal_layer_id = self.zonal_layer_cbx.itemData(new_index) self.zonal_layer = QgsProject.instance().mapLayer(zonal_layer_id) self.set_ok_button() def on_zonal_layer_gbx_toggled(self, is_checked): if is_checked and not self.zonal_layer_cbx.currentText(): self.ok_button.setEnabled(False) else: self.set_ok_button() def on_output_type_changed(self): if self.output_type in OQ_TO_LAYER_TYPES: self.create_load_selected_only_ckb() self.set_ok_button() def on_rlz_or_stat_changed(self): self.dataset = self.npz_file[self.rlz_or_stat_cbx.currentText()] self.set_ok_button() def on_loss_type_changed(self): self.set_ok_button() def on_imt_changed(self): self.set_ok_button() def on_poe_changed(self): self.set_ok_button() def on_eid_changed(self): self.set_ok_button() def on_dmg_state_changed(self): self.set_ok_button() def populate_out_dep_widgets(self): self.populate_rlz_or_stat_cbx() self.show_num_sites() def get_taxonomies(self): raise NotImplementedError() def populate_rlz_or_stat_cbx(self): self.rlzs_or_stats = [ key for key in sorted(self.npz_file) if key not in ('imtls', 'array') ] self.rlz_or_stat_cbx.clear() self.rlz_or_stat_cbx.setEnabled(True) self.rlz_or_stat_cbx.addItems(self.rlzs_or_stats) def populate_loss_type_cbx(self, loss_types): self.loss_type_cbx.clear() self.loss_type_cbx.setEnabled(True) self.loss_type_cbx.addItems(loss_types) def show_num_sites(self): # NOTE: we are assuming all realizations have the same number of sites, # which currently is always true. # If different realizations have a different number of sites, we # need to move this block of code inside on_rlz_or_stat_changed() rlz_or_stat_data = self.npz_file[self.rlz_or_stat_cbx.currentText()] self.num_sites_lbl.setText(self.num_sites_msg % rlz_or_stat_data.shape) def set_ok_button(self): raise NotImplementedError() def build_layer_name(self, *args, **kwargs): raise NotImplementedError() def get_field_types(self, **kwargs): raise NotImplementedError() def read_npz_into_layer(self, field_types, **kwargs): raise NotImplementedError() def load_from_npz(self): raise NotImplementedError() def add_field_to_layer(self, field_name, field_type): # NOTE: add_attribute use the native qgis editing manager added_field_name = add_attribute(field_name, field_type, self.layer) return added_field_name def get_investigation_time(self): if self.output_type in ('hcurves', 'uhs', 'hmaps', 'ruptures'): try: investigation_time = self.npz_file['investigation_time'] except KeyError as exc: msg = ('investigation_time not found. It is mandatory for %s.' ' Please check if the ouptut was produced by an' ' obsolete version of the OpenQuake Engine' ' Server.') % self.output_type log_msg(msg, level='C', message_bar=self.iface.messageBar(), exception=exc) else: # We must cast to 'str' to keep numerical padding # after saving the project return str(investigation_time) else: # some outputs do not need the investigation time return None def build_layer(self, rlz_or_stat=None, taxonomy=None, poe=None, loss_type=None, dmg_state=None, gsim=None, imt=None, boundaries=None, geometry_type='point', wkt_geom_type=None, row_wkt_geom_types=None, add_to_group=None, add_to_map=True): layer_name = self.build_layer_name(rlz_or_stat=rlz_or_stat, taxonomy=taxonomy, poe=poe, loss_type=loss_type, dmg_state=dmg_state, gsim=gsim, imt=imt, geometry_type=geometry_type) field_types = self.get_field_types(rlz_or_stat=rlz_or_stat, taxonomy=taxonomy, poe=poe, loss_type=loss_type, dmg_state=dmg_state, imt=imt) # create layer self.layer = QgsVectorLayer("%s?crs=epsg:4326" % geometry_type, layer_name, "memory") modified_field_types = copy.copy(field_types) for field_name, field_type in field_types.items(): if field_name in ['lon', 'lat', 'boundary']: continue added_field_name = self.add_field_to_layer(field_name, field_type) if field_name != added_field_name: if field_name == self.default_field_name: self.default_field_name = added_field_name # replace field_name with the actual added_field_name del modified_field_types[field_name] modified_field_types[added_field_name] = field_type field_types = copy.copy(modified_field_types) self.layer = self.read_npz_into_layer( field_types, rlz_or_stat=rlz_or_stat, taxonomy=taxonomy, poe=poe, loss_type=loss_type, dmg_state=dmg_state, imt=imt, boundaries=boundaries, geometry_type=geometry_type, wkt_geom_type=wkt_geom_type, row_wkt_geom_types=row_wkt_geom_types) if (self.output_type == 'damages-rlzs' and not self.aggregate_by_site_ckb.isChecked()): self.layer.setCustomProperty('output_type', 'recovery_curves') else: self.layer.setCustomProperty('output_type', self.output_type) investigation_time = self.get_investigation_time() if investigation_time is not None: self.layer.setCustomProperty('investigation_time', investigation_time) if self.engine_version is not None: self.layer.setCustomProperty('engine_version', self.engine_version) irmt_version = get_irmt_version() self.layer.setCustomProperty('irmt_version', irmt_version) self.layer.setCustomProperty('calc_id', self.calc_id) if poe is not None: self.layer.setCustomProperty('poe', poe) user_params = { 'rlz_or_stat': rlz_or_stat, 'taxonomy': taxonomy, 'poe': poe, 'loss_type': loss_type, 'dmg_state': dmg_state, 'gsim': gsim, 'imt': imt } write_metadata_to_layer(self.drive_engine_dlg, self.output_type, self.layer, user_params) try: if (self.zonal_layer_cbx.currentText() and self.zonal_layer_gbx.isChecked()): return except AttributeError: # the aggregation stuff might not exist for some loaders pass if add_to_map: if add_to_group: tree_node = add_to_group else: tree_node = QgsProject.instance().layerTreeRoot() if self.mode != 'testing': # NOTE: the following commented line would cause (unexpectedly) # "QGIS died on signal 11" and double creation of some # layers during integration tests QgsProject.instance().addMapLayer(self.layer, False) tree_node.insertLayer(0, self.layer) self.iface.setActiveLayer(self.layer) if add_to_group: # NOTE: zooming to group from caller function, to avoid # repeating it once per layer pass else: self.iface.zoomToActiveLayer() log_msg('Layer %s was created successfully' % layer_name, level='S', message_bar=self.iface.messageBar()) return self.layer @staticmethod def style_maps(layer, style_by, iface, output_type='damages-rlzs', perils=None, add_null_class=False, render_higher_on_top=False, repaint=True, use_sgc_style=False): symbol = QgsSymbol.defaultSymbol(layer.geometryType()) # see properties at: # https://qgis.org/api/qgsmarkersymbollayerv2_8cpp_source.html#l01073 symbol.setOpacity(1) if isinstance(symbol, QgsMarkerSymbol): # do it only for the layer with points symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) style = get_style(layer, iface.messageBar()) # this is the default, as specified in the user settings ramp = QgsGradientColorRamp(style['color_from'], style['color_to']) style_mode = style['style_mode'] # in most cases, we override the user-specified setting, and use # instead a setting that was required by scientists if output_type in OQ_TO_LAYER_TYPES: default_qgs_style = QgsStyle().defaultStyle() default_color_ramp_names = default_qgs_style.colorRampNames() if output_type in ( 'damages-rlzs', 'avg_losses-rlzs', 'avg_losses-stats', ): # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Jenks else: style_mode = 'Jenks' ramp_type_idx = default_color_ramp_names.index('Reds') symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top'])) inverted = False elif (output_type in ('gmf_data', 'ruptures') or (output_type == 'hmaps' and not use_sgc_style)): # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if output_type == 'ruptures': if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Pretty else: style_mode = 'PrettyBreaks' else: if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.EqualInterval else: style_mode = 'EqualInterval' ramp_type_idx = default_color_ramp_names.index('Spectral') inverted = True symbol.setColor(QColor(RAMP_EXTREME_COLORS['Reds']['top'])) elif output_type == 'hmaps' and use_sgc_style: # FIXME: for SGC they were using size 10000 map units # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.Pretty else: style_mode = 'PrettyBreaks' try: ramp_type_idx = default_color_ramp_names.index( 'SGC_Green2Red_Hmap_Color_Ramp') except ValueError: raise ValueError( 'Color ramp SGC_Green2Red_Hmap_Color_Ramp was ' 'not found. Please import it from ' 'Settings -> Style Manager, loading ' 'svir/resources/sgc_green2red_hmap_color_ramp.xml') inverted = False registry = QgsApplication.symbolLayerRegistry() symbol_props = { 'name': 'square', 'color': '0,0,0', 'color_border': '0,0,0', 'offset': '0,0', 'size': '1.5', # FIXME 'angle': '0', } square = registry.symbolLayerMetadata( "SimpleMarker").createSymbolLayer(symbol_props) symbol = QgsSymbol.defaultSymbol(layer.geometryType()).clone() symbol.deleteSymbolLayer(0) symbol.appendSymbolLayer(square) symbol.symbolLayer(0).setStrokeStyle(Qt.PenStyle(Qt.NoPen)) elif output_type in ['asset_risk', 'input']: # options are EqualInterval, Quantile, Jenks, StdDev, Pretty # jenks = natural breaks if Qgis.QGIS_VERSION_INT < 31000: style_mode = QgsGraduatedSymbolRenderer.EqualInterval else: style_mode = 'EqualInterval' # exposure_strings = ['number', 'occupants', 'value'] # setting exposure colors by default colors = { 'single': RAMP_EXTREME_COLORS['Blues']['top'], 'ramp_name': 'Blues' } inverted = False if output_type == 'asset_risk': damage_strings = perils for damage_string in damage_strings: if damage_string in style_by: colors = { 'single': RAMP_EXTREME_COLORS['Spectral']['top'], 'ramp_name': 'Spectral' } inverted = True break else: # 'input' colors = { 'single': RAMP_EXTREME_COLORS['Greens']['top'], 'ramp_name': 'Greens' } symbol.symbolLayer(0).setShape( QgsSimpleMarkerSymbolLayerBase.Square) single_color = colors['single'] ramp_name = colors['ramp_name'] ramp_type_idx = default_color_ramp_names.index(ramp_name) symbol.setColor(QColor(single_color)) else: raise NotImplementedError( 'Undefined color ramp for output type %s' % output_type) ramp = default_qgs_style.colorRamp( default_color_ramp_names[ramp_type_idx]) if inverted: ramp.invert() # get unique values fni = layer.fields().indexOf(style_by) unique_values = layer.dataProvider().uniqueValues(fni) num_unique_values = len(unique_values - {NULL}) if num_unique_values > 2: if Qgis.QGIS_VERSION_INT < 31000: renderer = QgsGraduatedSymbolRenderer.createRenderer( layer, style_by, min(num_unique_values, style['classes']), style_mode, symbol.clone(), ramp) else: renderer = QgsGraduatedSymbolRenderer(style_by, []) # NOTE: the following returns an instance of one of the # subclasses of QgsClassificationMethod classification_method = \ QgsApplication.classificationMethodRegistry().method( style_mode) renderer.setClassificationMethod(classification_method) renderer.updateColorRamp(ramp) renderer.updateSymbols(symbol.clone()) renderer.updateClasses( layer, min(num_unique_values, style['classes'])) if not use_sgc_style: if Qgis.QGIS_VERSION_INT < 31000: label_format = renderer.labelFormat() # NOTE: the following line might be useful # label_format.setTrimTrailingZeroes(True) label_format.setPrecision(2) renderer.setLabelFormat(label_format, updateRanges=True) else: renderer.classificationMethod().setLabelPrecision(2) renderer.calculateLabelPrecision() elif num_unique_values == 2: categories = [] for unique_value in unique_values: symbol = symbol.clone() try: symbol.setColor( QColor(RAMP_EXTREME_COLORS[ramp_name] ['bottom' if unique_value == min(unique_values) else 'top'])) except Exception: symbol.setColor( QColor(style['color_from'] if unique_value == min(unique_values) else style['color_to'])) category = QgsRendererCategory(unique_value, symbol, str(unique_value)) # entry for the list of category items categories.append(category) renderer = QgsCategorizedSymbolRenderer(style_by, categories) else: renderer = QgsSingleSymbolRenderer(symbol.clone()) if add_null_class and NULL in unique_values: # add a class for NULL values rule_renderer = QgsRuleBasedRenderer(symbol.clone()) root_rule = rule_renderer.rootRule() not_null_rule = root_rule.children()[0].clone() # strip parentheses from stringified color HSL not_null_rule.setFilterExpression( '%s IS NOT NULL' % QgsExpression.quotedColumnRef(style_by)) not_null_rule.setLabel('%s:' % style_by) root_rule.appendChild(not_null_rule) null_rule = root_rule.children()[0].clone() null_rule.setSymbol( QgsFillSymbol.createSimple({ 'color': '160,160,160', 'style': 'diagonal_x' })) null_rule.setFilterExpression( '%s IS NULL' % QgsExpression.quotedColumnRef(style_by)) null_rule.setLabel(tr('No points')) root_rule.appendChild(null_rule) if isinstance(renderer, QgsGraduatedSymbolRenderer): # create value ranges rule_renderer.refineRuleRanges(not_null_rule, renderer) # remove default rule elif isinstance(renderer, QgsCategorizedSymbolRenderer): rule_renderer.refineRuleCategoris(not_null_rule, renderer) for rule in rule_renderer.rootRule().children()[1].children(): label = rule.label() # by default, labels are like: # ('"collapse-structural-ASH_DRY_sum" >= 0.0000 AND # "collapse-structural-ASH_DRY_sum" <= 2.3949') first, second = label.split(" AND ") bottom = first.rsplit(" ", 1)[1] top = second.rsplit(" ", 1)[1] simplified = "%s - %s" % (bottom, top) rule.setLabel(simplified) root_rule.removeChildAt(0) renderer = rule_renderer if render_higher_on_top: renderer.setUsingSymbolLevels(True) symbol_items = [item for item in renderer.legendSymbolItems()] for i in range(len(symbol_items)): sym = symbol_items[i].symbol().clone() key = symbol_items[i].ruleKey() for lay in range(sym.symbolLayerCount()): sym.symbolLayer(lay).setRenderingPass(i) renderer.setLegendSymbolItem(key, sym) layer.setRenderer(renderer) if not use_sgc_style: layer.setOpacity(0.7) if repaint: layer.triggerRepaint() iface.setActiveLayer(layer) iface.zoomToActiveLayer() # NOTE QGIS3: probably not needed # iface.layerTreeView().refreshLayerSymbology(layer.id()) iface.mapCanvas().refresh() def style_categorized(self, layer=None, style_by=None): if layer is None: layer = self.layer if style_by is None: style_by = self.default_field_name # get unique values fni = layer.fields().indexOf(style_by) unique_values = layer.dataProvider().uniqueValues(fni) # define categories categories = [] for unique_value in unique_values: # initialize the default symbol for this geometry type symbol = QgsSymbol.defaultSymbol(layer.geometryType()) # configure a symbol layer layer_style = {} layer_style['color'] = '%d, %d, %d' % (randrange( 0, 256), randrange(0, 256), randrange(0, 256)) layer_style['outline'] = '#000000' symbol_layer = QgsSimpleFillSymbolLayer.create(layer_style) # replace default symbol layer with the configured one if symbol_layer is not None: symbol.changeSymbolLayer(0, symbol_layer) # create renderer object category = QgsRendererCategory(unique_value, symbol, str(unique_value)) # entry for the list of category items categories.append(category) # create renderer object renderer = QgsCategorizedSymbolRenderer(style_by, categories) # assign the created renderer to the layer if renderer is not None: layer.setRenderer(renderer) layer.triggerRepaint() # NOTE QGIS3: probably not needed # self.iface.layerTreeView().refreshLayerSymbology(layer.id()) self.iface.mapCanvas().refresh() def style_curves(self): registry = QgsApplication.symbolLayerRegistry() symbol_props = { 'name': 'cross2', 'color': '0,0,0', 'color_border': '0,0,0', 'offset': '0,0', 'size': '1.5', 'angle': '0', } opacity = 0.7 cross = registry.symbolLayerMetadata("SimpleMarker").createSymbolLayer( symbol_props) # NOTE: Cross symbols rendered for OQ-Engine disaggregation outputs are # opaque, wider and thicker than those used for other outputs (e.g. # hcurves) if self.output_type == 'disagg': cross.setSize(3) cross.setStrokeWidth(0.5) opacity = 1 symbol = QgsSymbol.defaultSymbol(self.layer.geometryType()).clone() symbol.deleteSymbolLayer(0) symbol.appendSymbolLayer(cross) renderer = QgsSingleSymbolRenderer(symbol) effect = QgsOuterGlowEffect() effect.setSpread(0.5) effect.setOpacity(opacity) effect.setColor(QColor(255, 255, 255)) effect.setBlurLevel(1) renderer.paintEffect().appendEffect(effect) renderer.paintEffect().setEnabled(True) self.layer.setRenderer(renderer) self.layer.setOpacity(opacity) self.layer.triggerRepaint() # NOTE QGIS3: probably not needed # self.iface.layerTreeView().refreshLayerSymbology(self.layer.id()) self.iface.mapCanvas().refresh() def open_load_zonal_layer_dialog(self): """ Open a file dialog to select the zonal layer to be loaded :returns: the zonal layer """ text = self.tr('Select zonal layer to import') filters = self.tr('All files (*.*);;' 'GeoPackages (*.gpkg);;' 'Vector shapefiles (*.shp);;' 'SQLite (*.sqlite);;') default_dir = QSettings().value('irmt/select_layer_dir', QDir.homePath()) file_name, _ = QFileDialog.getOpenFileName(self, text, default_dir, filters) if not file_name: return None selected_dir = QFileInfo(file_name).dir().path() QSettings().setValue('irmt/select_layer_dir', selected_dir) zonal_layer = self.load_zonal_layer(file_name) return zonal_layer def load_zonal_layer(self, zonal_layer_path): self.added_zonal_layer = zonal_layer = None zonal_layer_basename, zonal_layer_ext = os.path.splitext( os.path.basename(zonal_layer_path)) if zonal_layer_ext == '.gpkg': dlg = QgsSublayersDialog(QgsSublayersDialog.Ogr, 'Select zonal layer') conn = ogr.Open(zonal_layer_path) layer_defs = [] for idx, c in enumerate(conn): ld = QgsSublayersDialog.LayerDefinition() ld.layerId = idx ld.layerName = c.GetDescription() ld.count = c.GetFeatureCount() ld.type = ogr.GeometryTypeToName(c.GetGeomType()) layer_defs.append(ld) dlg.populateLayerTable(layer_defs) dlg.exec_() if not dlg.selection(): return None for sel in dlg.selection(): # NOTE: the last one will be chosen as zonal layer zonal_layer = QgsVectorLayer( zonal_layer_path + "|layername=" + sel.layerName, sel.layerName, 'ogr') if zonal_layer.isValid(): root = QgsProject.instance().layerTreeRoot() QgsProject.instance().addMapLayer(zonal_layer, False) root.insertLayer(0, zonal_layer) else: msg = 'Invalid layer' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return None else: zonal_layer = QgsVectorLayer(zonal_layer_path, zonal_layer_basename, 'ogr') if not zonal_layer.geometryType() == QgsWkbTypes.PolygonGeometry: msg = 'Zonal layer must contain zone polygons' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return None if zonal_layer_ext != '.gpkg': # Add zonal layer to registry if zonal_layer.isValid(): root = QgsProject.instance().layerTreeRoot() QgsProject.instance().addMapLayer(zonal_layer, False) root.insertLayer(0, zonal_layer) else: msg = 'Invalid zonal layer' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return None self.added_zonal_layer = zonal_layer self.pre_populate_zonal_layer_cbx() return zonal_layer def populate_zonal_layer_cbx(self, zonal_layer): cbx = self.zonal_layer_cbx cbx.addItem(zonal_layer.name()) last_index = cbx.count() - 1 cbx.setItemData(last_index, zonal_layer.id()) cbx.setCurrentIndex(last_index) def show_file_size(self): file_size = get_file_size(self.path) self.file_size_lbl.setText(self.file_size_msg % file_size) def accept(self): log_msg('Loading output started. Watch progress in QGIS task bar', level='I', message_bar=self.iface.messageBar()) try: self.iface.layerTreeView().currentLayerChanged.disconnect( self.on_currentLayerChanged) except Exception: # it's connected only for some loaders pass self.hide() if self.output_type in OQ_EXTRACT_TO_LAYER_TYPES: self.load_from_npz() if self.output_type in ('avg_losses-rlzs', 'damages-rlzs', 'avg_losses-stats'): # check if also aggregating by zone or not if (not self.zonal_layer_cbx.currentText() or not self.zonal_layer_gbx.isChecked()): super().accept() return self.aggregate_by_zone() else: super().accept() elif self.output_type in OQ_CSV_TO_LAYER_TYPES: self.load_from_csv() super().accept() def aggregate_by_zone(self): loss_layer = self.layer zonal_layer_id = self.zonal_layer_cbx.itemData( self.zonal_layer_cbx.currentIndex()) zonal_layer = QgsProject.instance().mapLayer(zonal_layer_id) QgsProject.instance().layerTreeRoot().findLayer( zonal_layer.id()).setItemVisibilityChecked(False) # if the two layers have different projections, display a # warning, but try proceeding anyway have_same_projection, check_projection_msg = ProcessLayer( loss_layer).has_same_projection_as(zonal_layer) if not have_same_projection: log_msg(check_projection_msg, level='W', message_bar=self.iface.messageBar()) try: [self.loss_attr_name ] = [field.name() for field in loss_layer.fields()] except ValueError: self.loss_attr_name = self.default_field_name zonal_layer_plus_sum_name = "%s: %s_sum" % (zonal_layer.name(), self.loss_attr_name) discard_nonmatching = self.discard_nonmatching_chk.isChecked() try: calculate_zonal_stats(self.on_calculate_zonal_stats_completed, zonal_layer, loss_layer, [self.loss_attr_name], zonal_layer_plus_sum_name, discard_nonmatching=discard_nonmatching, predicates=('intersects', ), summaries=('sum', )) except Exception as exc: log_msg(str(exc), level='C', message_bar=self.iface.messageBar(), exception=exc) def on_calculate_zonal_stats_completed(self, zonal_layer_plus_sum): if zonal_layer_plus_sum is None: msg = 'The calculation of zonal statistics was not completed' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return None # Add zonal layer to registry if zonal_layer_plus_sum.isValid(): root = QgsProject.instance().layerTreeRoot() QgsProject.instance().addMapLayer(zonal_layer_plus_sum, False) root.insertLayer(0, zonal_layer_plus_sum) else: msg = 'The layer aggregating data by zone is invalid.' log_msg(msg, level='C', message_bar=self.iface.messageBar()) return None # NOTE: in scenario damage, keys are like # u'structural_no_damage_mean', and not just # u'structural', therefore we can't just use the selected # loss type, but we must use the actual only key in the # dict added_loss_attr = "%s_sum" % self.loss_attr_name style_by = added_loss_attr try: perils = self.perils except AttributeError: perils = None self.style_maps(zonal_layer_plus_sum, style_by, self.iface, self.output_type, perils=perils, add_null_class=True) super().accept() def reject(self): try: self.iface.layerTreeView().currentLayerChanged.disconnect( self.on_currentLayerChanged) except Exception: # it's connected only for some loaders pass super().reject()
def stream(self): # Avoid auth exception if you reopen the project and don't open the search if self.mySearch == None: self.mySearch = MySearch(self.iface) # Get selected feature of active layer service = self.selectedFeature['service'] # Setup raster params isWcs = False if service == 'BaseMap': if self.mySearch.bmAuth is None: try: self.mySearch.bmSetAuth() except: return username = self.mySearch.bmUsernameInput.text() password = self.mySearch.bmPasswordInput.text() layers = self.mySearch.bmGetLayer(self.selectedFeature['wmts']) styles = 'default' tileMatrixSet = '4326' urlAttr = 'wmts' elif service == 'Data': if self.mySearch.dtHeaders is None: try: self.mySearch.dtSetAuth() except: return username = '******' password = self.mySearch.dtApikeyInput.text() # Dialog for image choice (panchro/multi & wmts/wcs) self.msgBox = QMessageBox() self.msgBox.setWindowTitle('Airbus') protocolGroup = QGroupBox('Protocol') protocolGrid = QGridLayout() wmtsRadio = QRadioButton('WMTS') wcsRadio = QRadioButton('WCS') protocolGrid.addWidget(wmtsRadio, 0, 0) protocolGrid.addWidget(wcsRadio, 0, 1) protocolGroup.setLayout(protocolGrid) styleGroup = QGroupBox('Style') styleGrid = QGridLayout() multispectralRadio = QRadioButton('multispectral') panchromaticRadio = QRadioButton('panchromatic') styleGrid.addWidget(multispectralRadio, 0, 0) styleGrid.addWidget(panchromaticRadio, 0, 1) styleGroup.setLayout(styleGrid) self.msgBox.layout().addWidget(protocolGroup, 0, 0) self.msgBox.layout().addWidget(styleGroup, 1, 0) wmtsRadio.setChecked(True) if type(self.selectedFeature['wcs_multispectral']) != str: protocolGroup.setEnabled(False) multispectralRadio.setChecked(True) self.msgBox.setStandardButtons(QMessageBox.Abort | QMessageBox.Ok) reply = self.msgBox.exec_() if reply == QMessageBox.Abort: return if wmtsRadio.isChecked(): urlAttr = 'wmts_' layers = 'default' styles = 'rgb' tileMatrixSet = 'EPSG4326' else: urlAttr = 'wcs_' isWcs = True if multispectralRadio.isChecked(): urlAttr += 'multispectral' else: urlAttr += 'panchromatic' else: self.error( f'Service "{service}" of the feature ocg_fid={self.selectedFeature.id()} isn\'t recognized\nIt should be "Basemap" or "Data"' ) return # Add a WMTS raster layer # Order of url parameters are important ! # Why layers is required, maybe is an internal id for wmts gesture ? # What is styles ? try: url = self.selectedFeature[urlAttr] name = f'{service} {self.selectedFeature["id"]}' if isWcs: rlayer = QgsRasterLayer( f'dpiMode=7&identifier=default&password={password}&url={url}&username={username}', name, 'wcs') else: rlayer = QgsRasterLayer( f'crs=EPSG:4326&dpiMode=7&format=image/png&layers={layers}&password={password}&styles={styles}&tileMatrixSet={tileMatrixSet}&url={url}&username={username}', name, 'wms') except Exception as e: self.error(f'Error in protocol connection\n\n{str(e)}') return if rlayer.isValid() == False: self.error(f'Raster layer is invalid\n\n{rlayer.error()}') return QgsProject.instance().addMapLayer(rlayer)
class QvFormNovaMapificacio(QvFormBaseMapificacio): def __init__(self, llegenda, amplada=500, mapificacio=None, simple=True): super().__init__(llegenda, amplada) self.fCSV = mapificacio self.simple = simple self.taulaMostra = None self.setWindowTitle('Afegir capa amb mapa simbòlic') self.layout = QVBoxLayout() self.layout.setSpacing(14) self.setLayout(self.layout) if self.fCSV is None: self.arxiu = QgsFileWidget() self.arxiu.setStorageMode(QgsFileWidget.GetFile) self.arxiu.setDialogTitle('Selecciona fitxer de dades…') self.arxiu.setDefaultRoot(RUTA_LOCAL) self.arxiu.setFilter('Arxius CSV (*.csv)') self.arxiu.setSelectedFilter('Arxius CSV (*.csv)') self.arxiu.lineEdit().setReadOnly(True) self.arxiu.fileChanged.connect(self.arxiuSeleccionat) self.zona = QComboBox(self) self.zona.setEditable(False) self.zona.addItem('Selecciona zona…') self.zona.currentIndexChanged.connect(self.canviaZona) self.mapa = QComboBox(self) self.mapa.setEditable(False) self.mapa.setIconSize(QSize(126, 126)) self.mapa.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.mapa.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.mapa.addItem(QIcon(os.path.join(imatgesDir, 'Àrees.PNG')), 'Àrees') self.mapa.addItem(QIcon(os.path.join(imatgesDir, 'Cercles.PNG')), 'Cercles') self.capa = QLineEdit(self) self.capa.setMaxLength(40) self.tipus = QComboBox(self) self.tipus.setEditable(False) self.tipus.addItem('Selecciona tipus…') self.tipus.addItems(mv.MAP_AGREGACIO.keys()) self.tipus.currentIndexChanged.connect(self.canviaTipus) self.distribucio = QComboBox(self) self.distribucio.setEditable(False) self.distribucio.addItem(next(iter(mv.MAP_DISTRIBUCIO.keys()))) self.calcul = QvComboBoxCamps(self) self.filtre = QvComboBoxCamps(self, multiple=True) self.color = QComboBox(self) self.color.setEditable(False) self.comboColors(self.color) self.metode = QComboBox(self) self.metode.setEditable(False) self.metode.addItems(mv.MAP_METODES.keys()) self.intervals = QSpinBox(self) self.intervals.setMinimum(2) self.intervals.setMaximum(mv.MAP_MAX_CATEGORIES) self.intervals.setSingleStep(1) self.intervals.setValue(4) self.intervals.setSuffix(" (depèn del mètode)") # self.intervals.valueChanged.connect(self.deselectValue) self.bTaula = QPushButton('Veure arxiu') self.bTaula.setEnabled(False) self.bTaula.clicked.connect(self.veureArxiu) self.buttons = QDialogButtonBox() self.buttons.addButton(QDialogButtonBox.Ok) self.buttons.accepted.connect(self.accept) self.buttons.addButton(QDialogButtonBox.Cancel) self.buttons.rejected.connect(self.cancel) self.buttons.addButton(self.bTaula, QDialogButtonBox.ResetRole) self.gDades = QGroupBox('Agregació de dades') self.lDades = QFormLayout() self.lDades.setSpacing(14) self.gDades.setLayout(self.lDades) if self.fCSV is None: self.lDades.addRow('Arxiu de dades:', self.arxiu) self.lDades.addRow('Zona:', self.zona) self.lDades.addRow("Tipus d'agregació:", self.tipus) self.lDades.addRow('Camp de càlcul:', self.calcul) if self.simple: self.filtre.setVisible(False) self.distribucio.setVisible(False) else: self.lDades.addRow('Filtre:', self.filtre) self.lDades.addRow('Distribució:', self.distribucio) self.gMapa = QGroupBox('Definició del mapa simbòlic') self.lMapa = QFormLayout() self.lMapa.setSpacing(14) self.gMapa.setLayout(self.lMapa) self.lMapa.addRow('Nom de capa:', self.capa) self.lMapa.addRow('Tipus de mapa:', self.mapa) self.gSimb = QGroupBox('Simbologia del mapa') self.lSimb = QFormLayout() self.lSimb.setSpacing(14) self.gSimb.setLayout(self.lSimb) self.lSimb.addRow('Color base:', self.color) self.lSimb.addRow('Mètode classificació:', self.metode) self.lSimb.addRow("Nombre d'intervals:", self.intervals) self.layout.addWidget(self.gDades) self.layout.addWidget(self.gMapa) if self.simple: self.gSimb.setVisible(False) else: self.layout.addWidget(self.gSimb) self.layout.addWidget(self.buttons) self.adjustSize() self.nouArxiu() def exec(self): # La mapificación solo funciona si está instalado el módulo pandas if PANDAS_ENABLED: return super().exec() else: self.msgError(PANDAS_ERROR) return QDialog.Rejected @pyqtSlot() def veureArxiu(self): if self.taulaMostra is not None: self.taulaMostra.show() self.taulaMostra.activateWindow() def campsDB(self, nom): res = [] if nom != '': fich = RUTA_DADES + mv.MAP_ZONES_DB if os.path.isfile(fich): conn = sqlite3.connect('file:' + fich + '?mode=ro', uri=True) conn.row_factory = sqlite3.Row c = conn.cursor() c.execute('select * from ' + nom) # nom.split('.')[0]) row = c.fetchone() # res = [i[0].upper() for i in c.description] res = [i.upper() for i in row.keys()] conn.close() return res def soloPrimerItem(self, combo): combo.setCurrentIndex(0) ultimo = combo.count() - 1 for n in range(ultimo, 0, -1): combo.removeItem(n) @pyqtSlot() def canviaZona(self): self.distribucio.setCurrentIndex(0) self.soloPrimerItem(self.distribucio) if self.zona.currentIndex() > 0: z = self.zona.currentText() campsZona = self.campsDB(mv.MAP_ZONES[z][1]) # Carga combo con distribuciones si el campo correspondiente está en la BBDD for dist, campo in mv.MAP_DISTRIBUCIO.items(): if campo != '' and campo in campsZona: self.distribucio.addItem(dist) @pyqtSlot() def canviaTipus(self): if self.tipus.currentText() == 'Recompte': self.calcul.setCurrentIndex(-1) self.calcul.setEnabled(False) else: self.calcul.setEnabled(True) def borrarArxiu(self): if self.taulaMostra is not None: self.taulaMostra.hide() self.taulaMostra = None self.bTaula.setEnabled(False) self.tipus.setCurrentIndex(0) self.soloPrimerItem(self.zona) self.calcul.clear() self.filtre.clear() def nouArxiu(self): if self.fCSV is None: return # Carga combo con zonas si el campo correspondiente está en el fichero CSV num = 0 for zona, val in mv.MAP_ZONES.items(): if val[1] != '' and self.fCSV.prefixe + QvSqlite.getAlias(val[0]) in self.fCSV.camps: self.zona.addItem(zona) num = num + 1 # Comprobar si la extensión del mapa está limitada if num > 0: extensio = self.fCSV.testExtensioArxiu(mv.MAP_EXTENSIO) if extensio: # Mapa limitado self.comboDelete(self.zona, mv.MAP_TRUE_EXTENSIO) else: # Mapa completo self.comboDelete(self.zona, mv.MAP_FALSE_EXTENSIO) # Ajustar combo de zonas if num == 0: self.msgInfo("El fitxer " + self.fCSV.fZones + " no té cap camp de zona") if hasattr(self, 'arxiu'): self.arxiu.lineEdit().clear() self.arxiu.setFocus() return if num == 1: self.zona.setCurrentIndex(1) self.capa.setFocus() else: self.zona.setFocus() self.taulaMostra = QvEditorCsv(self.fCSV.fZones, [], 'utf-8', self.fCSV.separador, self) self.taulaMostra.setWindowTitle("Vista prèvia d'arxiu geocodificat") self.taulaMostra.setReadOnly(True) self.bTaula.setEnabled(True) self.calcul.setItems(self.fCSV.camps, primer='') self.filtre.setItems(self.fCSV.camps) @pyqtSlot(str) def arxiuSeleccionat(self, nom): if nom == '': return self.borrarArxiu() self.fCSV = QvMapificacio(nom) self.nouArxiu() def validaSortida(self, nom): fSalida = self.fCSV.nomArxiuSortida(self.fCSV.netejaString(nom, True)) return self.msgSobreescriure(fSalida) def valida(self): ok = False if hasattr(self, 'arxiu') and self.arxiu.filePath() == '': self.msgInfo("S'ha de seleccionar un arxiu de dades") self.arxiu.setFocus() elif self.zona.currentIndex() <= 0: self.msgInfo("S'ha de seleccionar una zona") self.zona.setFocus() elif self.capa.text().strip() == '': self.msgInfo("S'ha de introduir un nom de capa") self.capa.setFocus() elif self.tipus.currentIndex() <= 0: self.msgInfo("S'ha de seleccionar un tipus d'agregació") self.tipus.setFocus() elif self.calcul.currentText().strip() == '' and self.tipus.currentText() != 'Recompte': self.msgInfo("S'ha de introduir un cálcul per fer l'agregació") self.calcul.setFocus() elif self.fCSV is None: return self.msgInfo("No hi ha cap fitxer seleccionat") elif not self.validaSortida(self.capa.text().strip()): self.capa.setFocus() else: ok = True return ok def setRenderParams(self): self.renderParams = QvMapRendererParams(self.mapa.currentText()) if self.simple: self.renderParams.colorBase = mv.MAP_COLORS[self.renderParams.colorBase] else: self.renderParams.colorBase = mv.MAP_COLORS[self.color.currentText()] if self.renderParams.colorContorn is None or self.renderParams.colorContorn == 'Base': self.renderParams.colorContorn = self.renderParams.colorBase else: self.renderParams.colorContorn = mv.MAP_CONTORNS[self.renderParams.colorContorn] if self.tipus.currentText().startswith('Recompte') and \ self.distribucio.currentText() == "Total": self.renderParams.numDecimals = 0 else: self.renderParams.numDecimals = 2 if self.renderParams.tipusMapa == 'Àrees': self.renderParams.modeCategories = mv.MAP_METODES[self.metode.currentText()] self.renderParams.numCategories = self.intervals.value() if self.renderParams.tipusMapa == 'Cercles': zona = self.zona.currentText() if zona == 'Districte': self.renderParams.increase = 8 elif zona == 'Barri': self.renderParams.increase = 4 elif zona == 'Àrea estadística bàsica': self.renderParams.increase = 3 elif zona == 'Secció censal': self.renderParams.increase = 2 else: self.renderParams.increase = 1 def procesa(self): if self.taulaMostra is not None: self.taulaMostra.hide() self.setRenderParams() ok = self.fCSV.agregacio(self.llegenda, self.capa.text().strip(), self.zona.currentText(), self.tipus.currentText(), self.renderParams, campAgregat=self.calcul.currentText().strip(), simple=self.simple, filtre=self.filtre.currentText().strip(), tipusDistribucio=self.distribucio.currentText(), form=self) if ok: return '' else: return self.fCSV.msgError