def __init__(self, order, dialog): super().__init__() self.dialog = dialog self.order = order txt = (f'<b>Order {order.name()}<br>({order.date()})</b><br>' f'{order.assets_count()} assets - state: {order.state()}') label = QLabel(txt) if not order.is_zipped(): label.setStyleSheet("color: gray") button = QPushButton( 'Re-Download' if order.downloaded() else 'Download') button.clicked.connect(self.download) button.setEnabled(order.state() == 'success' and order.is_zipped()) vlayout = QVBoxLayout() vlayout.addWidget(button) if order.downloaded(): labelOpenFolder = QLabel("<a href='#'>Open order folder</a>") vlayout.addWidget(labelOpenFolder) labelOpenFolder.setOpenExternalLinks(False) labelOpenFolder.linkActivated.connect( lambda: QDesktopServices.openUrl( QUrl.fromLocalFile(self.order.download_folder()))) layout = QHBoxLayout() layout.addWidget(label) layout.addStretch() layout.addLayout(vlayout) self.setLayout(layout)
def __init__(self, order, dialog): super().__init__() self.dialog = dialog self.order = order txt = (f'<b>Order {order.name()}<br>({order.date()})</b><br>' f'{order.assets_count()} assets - state: {order.state()}') label = QLabel(txt) if not order.is_zipped(): label.setStyleSheet("color: gray") button = QPushButton('Download') button.clicked.connect(self.download) button.setEnabled(order.state() == 'success' and order.is_zipped()) layout = QHBoxLayout() layout.addWidget(label) layout.addStretch() layout.addWidget(button) self.setLayout(layout)
def attributeNameWidget(self, fieldName, isNotNull): """ Retrieves a widget to be used into field table to expose field's name. :param fieldName: (str) fieldName to be exhibited. :param isNotNull: (bool) whether field is a mandatory attribute. :return: (QPushButton) a button ready to be setup to GUI. """ pb = QPushButton() pb.setText(fieldName) pb.setFlat(True) pb.setEnabled(False) if isNotNull: pb.setStyleSheet( "*{ color:rgb(150, 10, 25); "\ "background-color:rgba(255, 88, 116, 1.00); }" ) pb.setToolTip(self.tr("Field cannot be empty")) else: pb.setStyleSheet("color: black;") return pb
def __init__(self, order, dialog): super().__init__() self.dialog = dialog self.order = order txt = ( '<style>h3{margin-bottom: 0px;}</style>' f'<b><h3>Order {order.name()}</h3></b>' f'<b>Placed on</b>: {order.date()}<br>' f'<b>Id</b>: {order.id()}<br>' f'<b>Imagery source</b>: {order.item_type()}<br>' #f'<b>Assets ordered</b>: {order.assets_ordered()}<br>' #f'<b>File format</b>: {order.file_format()}<br>' f'<b>Asset count</b>: {order.assets_count()}<br>') label = QLabel(txt) if not order.is_zipped(): label.setStyleSheet("color: gray") button = QPushButton( 'Re-Download' if order.downloaded() else 'Download') button.clicked.connect(self.download) button.setEnabled(order.state() == 'success' and order.is_zipped()) vlayout = QVBoxLayout() vlayout.addWidget(button) if order.downloaded(): labelOpenFolder = QLabel("<a href='#'>Open order folder</a>") vlayout.addWidget(labelOpenFolder) labelOpenFolder.setOpenExternalLinks(False) labelOpenFolder.linkActivated.connect( lambda: QDesktopServices.openUrl( QUrl.fromLocalFile(self.order.download_folder()))) layout = QHBoxLayout() layout.addWidget(label) layout.addStretch() layout.addLayout(vlayout) self.setLayout(layout)
class AlgorithmDialog(QgsProcessingAlgorithmDialogBase): def __init__(self, alg, in_place=False, parent=None): super().__init__(parent) self.feedback_dialog = None self.in_place = in_place self.active_layer = iface.activeLayer() if self.in_place else None self.context = None self.feedback = None self.history_log_id = None self.history_details = {} self.setAlgorithm(alg) self.setMainWidget(self.getParametersPanel(alg, self)) if not self.in_place: self.runAsBatchButton = QPushButton( QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…")) self.runAsBatchButton.clicked.connect(self.runAsBatch) self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole ) # reset role to ensure left alignment else: in_place_input_parameter_name = 'INPUT' if hasattr(alg, 'inputParameterName'): in_place_input_parameter_name = alg.inputParameterName() self.mainWidget().setParameters( {in_place_input_parameter_name: self.active_layer}) self.runAsBatchButton = None has_selection = self.active_layer and ( self.active_layer.selectedFeatureCount() > 0) self.buttonBox().button(QDialogButtonBox.Ok).setText( QCoreApplication. translate("AlgorithmDialog", "Modify Selected Features" ) if has_selection else QCoreApplication. translate("AlgorithmDialog", "Modify All Features")) self.setWindowTitle(self.windowTitle() + ' | ' + self.active_layer.name()) self.updateRunButtonVisibility() def getParametersPanel(self, alg, parent): panel = ParametersPanel(parent, alg, self.in_place, self.active_layer) return panel def runAsBatch(self): self.close() dlg = BatchAlgorithmDialog(self.algorithm().create(), parent=iface.mainWindow()) dlg.show() dlg.exec_() def resetAdditionalGui(self): if not self.in_place: self.runAsBatchButton.setEnabled(True) def blockAdditionalControlsWhileRunning(self): if not self.in_place: self.runAsBatchButton.setEnabled(False) def setParameters(self, parameters): self.mainWidget().setParameters(parameters) def flag_invalid_parameter_value(self, message: str, widget): """ Highlights a parameter with an invalid value """ try: self.buttonBox().accepted.connect( lambda w=widget: w.setPalette(QPalette())) palette = widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) widget.setPalette(palette) except: pass self.messageBar().clearWidgets() self.messageBar().pushMessage( "", self.tr("Wrong or missing parameter value: {0}").format(message), level=Qgis.Warning, duration=5) def flag_invalid_output_extension(self, message: str, widget): """ Highlights a parameter with an invalid output extension """ try: self.buttonBox().accepted.connect( lambda w=widget: w.setPalette(QPalette())) palette = widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) widget.setPalette(palette) except: pass self.messageBar().clearWidgets() self.messageBar().pushMessage("", message, level=Qgis.Warning, duration=5) def createProcessingParameters( self, flags=QgsProcessingParametersGenerator.Flags()): if self.mainWidget() is None: return {} try: return self.mainWidget().createProcessingParameters(flags) except AlgorithmDialogBase.InvalidParameterValue as e: self.flag_invalid_parameter_value(e.parameter.description(), e.widget) except AlgorithmDialogBase.InvalidOutputExtension as e: self.flag_invalid_output_extension(e.message, e.widget) return {} def processingContext(self): if self.context is None: self.feedback = self.createFeedback() self.context = dataobjects.createContext(self.feedback) self.context.setLogLevel(self.logLevel()) return self.context def runAlgorithm(self): self.feedback = self.createFeedback() self.context = dataobjects.createContext(self.feedback) self.context.setLogLevel(self.logLevel()) checkCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_CRS) try: # messy as all heck, but we don't want to call the dialog's implementation of # createProcessingParameters as we want to catch the exceptions raised by the # parameter panel instead... parameters = {} if self.mainWidget() is None else self.mainWidget( ).createProcessingParameters() if checkCRS and not self.algorithm().validateInputCrs( parameters, self.context): reply = QMessageBox.question( self, self.tr("Unmatching CRS's"), self.tr('Parameters do not all use the same CRS. This can ' 'cause unexpected results.\nDo you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return ok, msg = self.algorithm().checkParameterValues( parameters, self.context) if not ok: QMessageBox.warning(self, self.tr('Unable to execute algorithm'), msg) return self.blockControlsWhileRunning() self.setExecutedAnyResult(True) self.cancelButton().setEnabled(False) self.iterateParam = None for param in self.algorithm().parameterDefinitions(): if isinstance( parameters.get(param.name(), None), QgsProcessingFeatureSourceDefinition ) and parameters[param.name( )].flags & QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature: self.iterateParam = param.name() break self.clearProgress() self.feedback.pushVersionInfo(self.algorithm().provider()) if self.algorithm().provider().warningMessage(): self.feedback.reportError( self.algorithm().provider().warningMessage()) self.feedback.pushInfo( QCoreApplication.translate('AlgorithmDialog', 'Algorithm started at: {}').format( datetime.datetime.now().replace( microsecond=0).isoformat())) self.setInfo(QCoreApplication.translate( 'AlgorithmDialog', '<b>Algorithm \'{0}\' starting…</b>').format( self.algorithm().displayName()), escapeHtml=False) self.feedback.pushInfo(self.tr('Input parameters:')) display_params = [] for k, v in parameters.items(): display_params.append("'" + k + "' : " + self.algorithm( ).parameterDefinition(k).valueAsPythonString(v, self.context)) self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }') self.feedback.pushInfo('') start_time = time.time() def elapsed_time(start_time, result): delta_t = time.time() - start_time hours = int(delta_t / 3600) minutes = int((delta_t % 3600) / 60) seconds = delta_t - hours * 3600 - minutes * 60 str_hours = [self.tr("hour"), self.tr("hours")][hours > 1] str_minutes = [self.tr("minute"), self.tr("minutes")][minutes > 1] str_seconds = [self.tr("second"), self.tr("seconds")][seconds != 1] if hours > 0: elapsed = '{0} {1:0.2f} {2} ({3} {4} {5} {6} {7:0.0f} {2})'.format( result, delta_t, str_seconds, hours, str_hours, minutes, str_minutes, seconds) elif minutes > 0: elapsed = '{0} {1:0.2f} {2} ({3} {4} {5:0.0f} {2})'.format( result, delta_t, str_seconds, minutes, str_minutes, seconds) else: elapsed = '{0} {1:0.2f} {2}'.format( result, delta_t, str_seconds) return (elapsed) if self.iterateParam: # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) if executeIterating(self.algorithm(), parameters, self.iterateParam, self.context, self.feedback): self.feedback.pushInfo( self.tr( elapsed_time(start_time, 'Execution completed in'))) self.cancelButton().setEnabled(False) self.finish(True, parameters, self.context, self.feedback) else: self.cancelButton().setEnabled(False) self.resetGui() else: self.history_details = { 'python_command': self.algorithm().asPythonCommand(parameters, self.context), 'algorithm_id': self.algorithm().id(), 'parameters': self.algorithm().asMap(parameters, self.context) } process_command, command_ok = self.algorithm( ).asQgisProcessCommand(parameters, self.context) if command_ok: self.history_details['process_command'] = process_command self.history_log_id, _ = QgsGui.historyProviderRegistry( ).addEntry('processing', self.history_details) QgsGui.instance().processingRecentAlgorithmLog().push( self.algorithm().id()) self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) def on_complete(ok, results): if ok: self.feedback.pushInfo( self.tr( elapsed_time(start_time, 'Execution completed in'))) self.feedback.pushInfo(self.tr('Results:')) r = { k: v for k, v in results.items() if k not in ('CHILD_RESULTS', 'CHILD_INPUTS') } self.feedback.pushCommandInfo(pformat(r)) else: self.feedback.reportError( self.tr( elapsed_time(start_time, 'Execution failed after'))) self.feedback.pushInfo('') if self.history_log_id is not None: self.history_details['results'] = results QgsGui.historyProviderRegistry().updateEntry( self.history_log_id, self.history_details) if self.feedback_dialog is not None: self.feedback_dialog.close() self.feedback_dialog.deleteLater() self.feedback_dialog = None self.cancelButton().setEnabled(False) self.finish(ok, results, self.context, self.feedback, in_place=self.in_place) self.feedback = None self.context = None if not self.in_place and not ( self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading): # Make sure the Log tab is visible before executing the algorithm self.showLog() task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, self.context, self.feedback) if task.isCanceled(): on_complete(False, {}) else: task.executed.connect(on_complete) self.setCurrentTask(task) else: self.proxy_progress = QgsProxyProgressTask( QCoreApplication.translate( "AlgorithmDialog", "Executing “{}”").format( self.algorithm().displayName())) QgsApplication.taskManager().addTask(self.proxy_progress) self.feedback.progressChanged.connect( self.proxy_progress.setProxyProgress) self.feedback_dialog = self.createProgressDialog() self.feedback_dialog.show() if self.in_place: ok, results = execute_in_place(self.algorithm(), parameters, self.context, self.feedback) else: ok, results = execute(self.algorithm(), parameters, self.context, self.feedback) self.feedback.progressChanged.disconnect() self.proxy_progress.finalize(ok) on_complete(ok, results) except AlgorithmDialogBase.InvalidParameterValue as e: self.flag_invalid_parameter_value(e.parameter.description(), e.widget) except AlgorithmDialogBase.InvalidOutputExtension as e: self.flag_invalid_output_extension(e.message, e.widget) def finish(self, successful, result, context, feedback, in_place=False): keepOpen = not successful or ProcessingConfig.getSetting( ProcessingConfig.KEEP_DIALOG_OPEN) if not in_place and self.iterateParam is None: # add html results to results dock for out in self.algorithm().outputDefinitions(): if isinstance(out, QgsProcessingOutputHtml) and out.name( ) in result and result[out.name()]: resultsList.addResult(icon=self.algorithm().icon(), name=out.description(), timestamp=time.localtime(), result=result[out.name()]) if not handleAlgorithmResults(self.algorithm(), context, feedback, not keepOpen, result): self.resetGui() return self.setExecuted(True) self.setResults(result) self.setInfo(self.tr('Algorithm \'{0}\' finished').format( self.algorithm().displayName()), escapeHtml=False) self.algorithmFinished.emit(successful, result) if not in_place and not keepOpen: self.close() else: self.resetGui() if self.algorithm().hasHtmlOutputs(): self.setInfo(self.tr( 'HTML output has been generated by this algorithm.' '\nOpen the results dialog to check it.'), escapeHtml=False)
def setup_left_panel(self): """Setup the UI for left panel. Generate all exposure, combobox, and edit button. """ hazard = self.parent.step_kw_subcategory.selected_subcategory() left_panel_heading = QLabel(tr('Classifications')) left_panel_heading.setFont(big_font) self.left_layout.addWidget(left_panel_heading) inner_left_layout = QGridLayout() row = 0 for exposure in exposure_all: special_case = False if not setting('developer_mode'): # Filter out unsupported exposure for the hazard if exposure in hazard['disabled_exposures']: # Remove from the storage if the exposure is disabled if self.layer_mode == layer_mode_continuous: if exposure['key'] in self.thresholds: self.thresholds.pop(exposure['key']) else: if exposure['key'] in self.value_maps: self.value_maps.pop(exposure['key']) continue # Trick for EQ raster for population #3853 if exposure == exposure_population and hazard == hazard_earthquake: if is_raster_layer(self.parent.layer): if self.layer_mode == layer_mode_continuous: self.use_default_thresholds = True special_case = True # Set classification for EQ Raster for Population self.thresholds[exposure_population['key']] = { earthquake_mmi_scale['key']: { 'classes': default_classification_thresholds( earthquake_mmi_scale), 'active': True } } # Add label # Hazard on Exposure Classifications label = tr( '{hazard_name} on {exposure_name} Classifications').format( hazard_name=hazard['name'], exposure_name=exposure['name'] ) exposure_label = QLabel(label) # Add combo box exposure_combo_box = QComboBox() hazard_classifications = hazard.get('classifications') exposure_combo_box.addItem(tr('No classifications')) exposure_combo_box.setItemData( 0, None, Qt.UserRole) current_index = 0 i = 0 # Iterate through all available hazard classifications for hazard_classification in hazard_classifications: # Skip if the classification is not for the exposure if 'exposures' in hazard_classification: if exposure not in hazard_classification['exposures']: continue exposure_combo_box.addItem(hazard_classification['name']) exposure_combo_box.setItemData( i + 1, hazard_classification, Qt.UserRole) if self.layer_mode == layer_mode_continuous: current_hazard_classifications = self.thresholds.get( exposure['key']) else: current_hazard_classifications = self.value_maps.get( exposure['key']) if current_hazard_classifications: current_hazard_classification = \ current_hazard_classifications.get( hazard_classification['key']) if current_hazard_classification: is_active = current_hazard_classification.get('active') if is_active: current_index = i + 1 i += 1 # Set current classification exposure_combo_box.setCurrentIndex(current_index) # Add edit button exposure_edit_button = QPushButton(tr('Edit')) # For special case. Raster EQ on Population. if special_case: mmi_index = exposure_combo_box.findText( earthquake_mmi_scale['name']) exposure_combo_box.setCurrentIndex(mmi_index) exposure_combo_box.setEnabled(False) exposure_edit_button.setEnabled(False) tool_tip_message = tr( 'InaSAFE use default classification for Raster Earthquake ' 'hazard on population.') exposure_label.setToolTip(tool_tip_message) exposure_combo_box.setToolTip(tool_tip_message) exposure_edit_button.setToolTip(tool_tip_message) else: if current_index == 0: # Disable if there is no classification chosen. exposure_edit_button.setEnabled(False) exposure_edit_button.clicked.connect( partial( self.edit_button_clicked, edit_button=exposure_edit_button, exposure_combo_box=exposure_combo_box, exposure=exposure)) exposure_combo_box.currentIndexChanged.connect( partial( self.classifications_combo_box_changed, exposure=exposure, exposure_combo_box=exposure_combo_box, edit_button=exposure_edit_button)) # Arrange in layout inner_left_layout.addWidget(exposure_label, row, 0) inner_left_layout.addWidget(exposure_combo_box, row, 1) inner_left_layout.addWidget(exposure_edit_button, row, 2) # Adding to step's attribute self.exposures.append(exposure) self.exposure_combo_boxes.append(exposure_combo_box) self.exposure_edit_buttons.append(exposure_edit_button) self.exposure_labels.append(label) if special_case: self.special_case_index = len(self.exposures) - 1 row += 1 self.left_layout.addLayout(inner_left_layout) # To push the inner_left_layout up self.left_layout.addStretch(1)
class PackageDialog(QDialog, DialogUi): def __init__(self, iface, project, offline_editing, parent=None): """Constructor.""" super(PackageDialog, self).__init__(parent=parent) self.setupUi(self) self.iface = iface self.offline_editing = offline_editing self.project = project self.qfield_preferences = Preferences() self.project_lbl.setText(get_project_title(self.project)) self.push_btn = QPushButton(self.tr('Create')) self.push_btn.clicked.connect(self.package_project) self.button_box.addButton(self.push_btn, QDialogButtonBox.ActionRole) self.iface.mapCanvas().extentsChanged.connect(self.extent_changed) self.extent_changed() self.devices = None # self.refresh_devices() self.setup_gui() self.offline_editing.warning.connect(self.show_warning) def update_progress(self, sent, total): progress = float(sent) / total * 100 self.progress_bar.setValue(progress) def setup_gui(self): """Populate gui and connect signals of the push dialog""" export_folder_path = self.qfield_preferences.value( 'exportDirectoryProject') if not export_folder_path: project_fn = QgsProject.instance().fileName() export_folder_name = fileparts(project_fn)[1] export_folder_path = os.path.join( self.qfield_preferences.value('exportDirectory'), export_folder_name) self.manualDir.setText(export_folder_path) self.manualDir_btn.clicked.connect(make_folder_selector( self.manualDir)) self.update_info_visibility() self.infoLabel.setTextInteractionFlags(Qt.TextBrowserInteraction) self.infoLabel.linkActivated.connect(lambda: self.show_settings()) def get_export_folder_from_dialog(self): """Get the export folder according to the inputs in the selected""" # manual return self.manualDir.text() def package_project(self): self.push_btn.setEnabled(False) self.informationStack.setCurrentWidget(self.progressPage) export_folder = self.get_export_folder_from_dialog() self.qfield_preferences.set_value('exportDirectoryProject', export_folder) offline_convertor = OfflineConverter(self.project, export_folder, self.iface.mapCanvas().extent(), self.offline_editing) # progress connections offline_convertor.total_progress_updated.connect(self.update_total) offline_convertor.task_progress_updated.connect(self.update_task) offline_convertor.convert() self.do_post_offline_convert_action() self.close() self.progress_group.setEnabled(False) def do_post_offline_convert_action(self): """ Show an information label that the project has been copied with a nice link to open the result folder. """ export_folder = self.get_export_folder_from_dialog() result_label = QLabel( self. tr('Finished creating the project at {result_folder}. Please copy this folder to ' 'your QField device.').format( result_folder='<a href="{folder}">{folder}</a>'.format( folder=export_folder))) result_label.setTextFormat(Qt.RichText) result_label.setTextInteractionFlags(Qt.TextBrowserInteraction) result_label.linkActivated.connect(lambda: open_folder(export_folder)) result_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) self.iface.messageBar().pushWidget(result_label, Qgis.Info, 0) def update_info_visibility(self): """ Show the info label if there are unconfigured layers """ self.infoGroupBox.hide() for layer in list(self.project.mapLayers().values()): if not LayerSource(layer).is_configured: self.infoGroupBox.show() project_configuration = ProjectConfiguration(self.project) if project_configuration.offline_copy_only_aoi or project_configuration.create_base_map: self.informationStack.setCurrentWidget(self.selectExtentPage) else: self.informationStack.setCurrentWidget(self.progressPage) def show_settings(self): dlg = ProjectConfigurationDialog(self.iface, self.iface.mainWindow()) dlg.exec_() self.update_info_visibility() @pyqtSlot(int, int, str) def update_total(self, current, layer_count, message): self.totalProgressBar.setMaximum(layer_count) self.totalProgressBar.setValue(current) self.statusLabel.setText(message) @pyqtSlot(int, int) def update_task(self, progress, max_progress): self.layerProgressBar.setMaximum(max_progress) self.layerProgressBar.setValue(progress) @pyqtSlot() def extent_changed(self): extent = self.iface.mapCanvas().extent() self.xMinLabel.setText(str(extent.xMinimum())) self.xMaxLabel.setText(str(extent.xMaximum())) self.yMinLabel.setText(str(extent.yMinimum())) self.yMaxLabel.setText(str(extent.yMaximum())) @pyqtSlot(str, str) def show_warning(self, _, message): # Most messages from the offline editing plugin are not important enough to show in the message bar. # In case we find important ones in the future, we need to filter them. QgsApplication.instance().messageLog().logMessage( message, 'QFieldSync')
class ElementTableGUI(QWidget): """Create the periodic element gui with toggleble buttons for element selection and preview signal triggered with mouse hover events and right click for optional menu/ window. Initialisation can take python list with elements for which buttons is pre-toggled: ----------- args: prechecked -- python list with elements (abbrevations), the buttons which should be initially pushed. state_list = python list -- list of elements (abbrevations) for buttons which should be disabled (by default) or enabled (if state_list_enables is True. state_list_enables = False (default) -- set interpretation of state_list silent_disabled = False (default) -- controls the behaviour of disabled element buttons if True, then disabled buttons do not emit any signal disable_fancy = False (default) -- controls if do button geometry changes with hover over/off events buttons_auto_depress = False (Default) -- controls if element buttons hold its state or only triggers when pushed (and automatically depresses). ----------- additionally to native QtGui.QWidget provides such signals: elementConsidered -- signal which emits element abbrevation when mouse hovers over the button, or the coresponding button gets focus, or is emitted by text input interface. elementUnconsidered -- emits element abrevation at moment mouse leaves the button area elementChecked -- emits the element abbrevation when button changes to checked possition. elementUnchecked -- emits the element abbrevation when button changes to unchecked possition. elementRightClicked -- emits the element abbrevation when button gets right clicked. elementTriggered -- emits the element abbrevation when button gets triggered (intended to be used with buttons_auto_depress=True) allElementsCleared -- emits, when the clear all button clicked. Alternatively the element by element could be dissabled, however this signal can be much faster. """ # preview slots: elementConsidered = QtCore.pyqtSignal(str) elementUnconsidered = QtCore.pyqtSignal(str) # button press slots: elementChecked = QtCore.pyqtSignal(str) elementUnchecked = QtCore.pyqtSignal(str) elementTriggered = QtCore.pyqtSignal(str) # right_mouse_button_press_slot: elementRightClicked = QtCore.pyqtSignal(str) allElementsCleared = QtCore.pyqtSignal() def __init__(self, parent=None, prechecked=[], state_list=[], state_list_enables=False, silent_disabled=False, disable_fancy=False, buttons_auto_depress=False): super().__init__() if type(state_list) == str: state_list = parse_elements(state_list) if (len(prechecked) > 0) and buttons_auto_depress: warnings.warn( "element table is initialised with opposite" " arguements - seting buttons to auto depress rules out" " using prechecked element list. The list is ignored") prechecked = [] self.setWindowTitle('Element Table') layout = QGridLayout(self) self.setLayout(layout) layout.setSpacing(0) layout.setContentsMargins(4, 4, 4, 4) partly_disabled = not silent_disabled self._setup_table(prechecked, state_list, state_list_enables, partly_disabled, disable_fancy, buttons_auto_depress) self._setup_text_interface() self._setup_clear_all() if not buttons_auto_depress: self.set_table_mode('multi') # default else: self.set_table_mode('single') self.resize(400, 250) def _setup_clear_all(self): self.clear_all_button = QPushButton('Clear all') self.layout().addWidget(self.clear_all_button, 7, 0, 2, 3) self.clear_all_button.pressed.connect(self.clear_all) self.clear_all_button.setMinimumSize(32, 32) self.clear_all_button.setMaximumSize(512, 512) def _setup_text_interface(self): self.textInterface = QLineEdit() self.textInterface.setMinimumSize(16, 16) self.layout().addWidget(self.textInterface, 8, 9, 1, 9) self.textInterface.returnPressed.connect(self.toggle_elements) self.textInterface.textChanged.connect(self.consider_element) self.textInterface.setMaximumSize(512, 1024) def set_extended_completer(self): completer = QCompleter( list(pt_indexes.keys()) + list(geo_groups.keys()) + list(names_abbrv.keys())) self.textInterface.setCompleter(completer) def set_simple_completer(self): completer = QCompleter(list(pt_indexes.keys())) self.textInterface.setCompleter(completer) def set_table_mode(self, mode): if mode == 'multi': self.textInterface.setEnabled(True) self.set_extended_completer() self.textInterface.setToolTip( "text interface.\n" "Input abbrevations of elements:\n" " without any space:\n" " AlSiNaK\n" " with any separators like comma/space:\n" " Al;Br K,La\n" "abbrevations of element groups (in all caps):\n" " HFSE, REE, REE_SEM, LILE, MAJOR\n" "Use '-' (minus) sign to disable elements:\n" " -AlCa, K; P -> toggles off Al, Ca, K, P\n" "HFSE - Nb -> toggles on HFSE elements, but switches off Nb") self.clear_all_button.setEnabled(True) self.textInterface.setInputMask("") elif mode == 'single': self.textInterface.setEnabled(False) # self.set_simple_completer() # self.textInterface.setToolTip( # "Enter a single element abbreviation") self.clear_all_button.setEnabled(False) # self.textInterface.setInputMask(">A<a") for i in geo_groups['ALL']: self.getButton_by_name(i).change_mode(mode) def getButton(self, index): """helper function to get button by position index - tuple (row, column)""" item = self.layout().itemAtPosition(*index) return item.widget() def getButton_by_name(self, name): """helper function to get button by abbrevation of the element""" item = self.layout().itemAtPosition(*pt_indexes[name]) return item.widget() def toggle_elements(self): ptext = self.textInterface.text() positive_text, negative_text = separate_text(ptext) # clear text interface: self.textInterface.clear() # parse what to add first: positive_list = parse_elements(positive_text) self.toggle_on(positive_list) # parse what to remove: negative_list = parse_elements(negative_text) self.toggle_off(negative_list) def consider_element(self, text): positive_text = separate_text(text)[0] positive_list = parse_elements(positive_text) self.elementUnconsidered.emit('') for i in positive_list: self.elementConsidered.emit(i) def toggle_on(self, toggle_list): for i in toggle_list: button = self.getButton(pt_indexes[i]) if button.isEnabled(): button.setChecked(True) def toggle_off(self, toggle_list): for i in toggle_list: button = self.getButton(pt_indexes[i]) if button.isEnabled(): button.setChecked(False) def clear_all(self): """uncheck all buttons, and send single signal instead of many per button, which allows to do related action in more snappy maner.""" self.blockSignals(True) self.toggle_off(geo_groups['ALL']) self.blockSignals(False) self.allElementsCleared.emit() def _setup_table(self, prechecked_elements, state_list, state_list_enables, partly_disabled, disable_fancy, auto_depresso): self.signalMapper = QtCore.QSignalMapper(self) self.signalMapper.mapped[QWidget].connect(self.previewToggler) self.signalMapper2 = QtCore.QSignalMapper(self) self.signalMapper2.mapped[QWidget].connect(self.elementToggler) self.signalMapper3 = QtCore.QSignalMapper(self) self.signalMapper3.mapped[QWidget].connect(self.emit_right_clicked) self.signalMapper4 = QtCore.QSignalMapper(self) self.signalMapper4.mapped[QWidget].connect(self.focus_on_toggler) self.signalMapper5 = QtCore.QSignalMapper(self) self.signalMapper5.mapped[QWidget].connect(self.focus_off_toggler) self.signalMapper6 = QtCore.QSignalMapper(self) self.signalMapper6.mapped[QWidget].connect(self.emit_triggered) is_checkable = not auto_depresso for i in pt_indexes: pt_button = HoverableButton(i, partly_disabled=partly_disabled, disable_fancy=disable_fancy, is_checkable=is_checkable) pt_button.setMinimumSize(16, 16) pt_button.setMaximumSize(512, 512) if i in prechecked_elements: pt_button.setChecked(True) self.layout().addWidget(pt_button, pt_indexes[i][0], pt_indexes[i][1]) # pt_button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) pt_button.hoverChanged.connect(self.signalMapper.map) pt_button.toggled.connect(self.signalMapper2.map) pt_button.rightClicked.connect(self.signalMapper3.map) pt_button.gainedFocus.connect(self.signalMapper4.map) pt_button.lostFocus.connect(self.signalMapper5.map) pt_button.pressed.connect(self.signalMapper6.map) self.signalMapper.setMapping(pt_button, pt_button) self.signalMapper2.setMapping(pt_button, pt_button) self.signalMapper3.setMapping(pt_button, pt_button) self.signalMapper4.setMapping(pt_button, pt_button) self.signalMapper5.setMapping(pt_button, pt_button) self.signalMapper6.setMapping(pt_button, pt_button) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) line.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.layout().addWidget(line, 6, 3, 1, 15) # dissable elements/buttons for provided list: if state_list_enables: disabled_elements = set(pt_indexes).difference(state_list) else: disabled_elements = state_list for i in disabled_elements: self.getButton(pt_indexes[i]).setEnabled(False) lant_text = QLabel('Lan') act_text = QLabel('Act') lant_text.setAlignment(QtCore.Qt.AlignCenter) act_text.setAlignment(QtCore.Qt.AlignCenter) self.layout().addWidget(lant_text, 5, 2) self.layout().addWidget(act_text, 6, 2) lant_text.setEnabled(False) act_text.setEnabled(False) def update_state(self, element, enable=True): """update state of button for given element (enable, disable); this method is intended to be used when model containing element list is updated (new element added or removed)""" self.signalMapper2.blockSignals(True) button = self.getButton_by_name(element) if not enable and button.isChecked(): button.setChecked(False) button.setEnabled(enable) self.signalMapper2.blockSignals(False) def keyPressEvent(self, event): """Jump to text interface at shift key press""" if event.key() == QtCore.Qt.Key_Shift: self.textInterface.setFocus() # @QtCore.pyqtSlot(QtCore.QObject) # NOTE decorators are commented out # as pyQt5.7 made regression with using QObject or QWidget in signals # or is it the problem with mapping of signals? def previewToggler(self, button): # if button.isEnabled(): if button.hover_state: self.elementConsidered.emit(button.text()) else: self.elementUnconsidered.emit(button.text()) def focus_on_toggler(self, button): """this is for sending same signal as with hovering, but by "Tab" jumping through buttons""" self.elementConsidered.emit(button.text()) def focus_off_toggler(self, button): """this is for sending same signal as with hovering, but by "Tab" jumping through buttons""" self.elementUnconsidered.emit(button.text()) # @QtCore.pyqtSlot(QtCore.QObject) def elementToggler(self, button): if button.isChecked(): self.elementChecked.emit(button.text()) if button.hover_state and button.fancy: button.setGeometry(button.orig_size) else: self.elementUnchecked.emit(button.text()) # @QtCore.pyqtSlot(QtCore.QObject) def emit_right_clicked(self, button): self.elementRightClicked.emit(button.text()) def emit_triggered(self, button): self.elementTriggered.emit(button.text()) def switch_button_wo_trigger(self, elements, press=True): """This method is intended to be connected with list model signal; it blocks signal so that there would be no loop of triggering back and forth between button and list model if state of checkbox in list is bined with state of button.""" self.signalMapper2.blockSignals(True) if press: self.toggle_on(elements) else: self.toggle_off(elements) self.signalMapper2.blockSignals(False)
class ProfileManager(BASE, WIDGET): def __init__(self, parent): super(ProfileManager, self).__init__(parent) self.setupUi(self) self.profilesTree.currentItemChanged.connect(self.currentItemChanged) self.profilesTree.itemSelectionChanged.connect(self.toggleButtons) self.btnApply = self.buttonBox.button(QDialogButtonBox.Apply) self.btnApply.clicked.connect(self.activateProfile) self.btnSave = QPushButton( self.tr('Save current configuration as profile')) self.btnSave.clicked.connect(self.saveCurrent) self.btnRemove = QPushButton(self.tr('Remove profile')) self.btnRemove.clicked.connect(self.removeProfile) self.buttonBox.addButton(self.btnSave, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ActionRole) self.fillTree() self.setInfoText() self.toggleButtons() def fillTree(self): self.profilesTree.clear() allProfiles = defaultdict(list) for v in list(profiles.values()): allProfiles[v.group].append(v) profileIcon = QIcon( os.path.join(os.path.dirname(__file__), os.pardir, 'icons', 'profile.png')) for group, groupProfiles in allProfiles.items(): groupItem = QTreeWidgetItem() groupItem.setText(0, group) for profile in groupProfiles: profileItem = QTreeWidgetItem() profileItem.profile = profile profileItem.isCustom = False profileItem.setText(0, profile.name) profileItem.setIcon(0, profileIcon) groupItem.addChild(profileItem) self.profilesTree.addTopLevelItem(groupItem) groupItem = QTreeWidgetItem() groupItem.setText(0, self.tr("User profiles")) for profile in customProfiles(): profileItem = QTreeWidgetItem() profileItem.profile = profile profileItem.isCustom = True profileItem.setText(0, profile.name) profileItem.setIcon(0, profileIcon) groupItem.addChild(profileItem) self.profilesTree.addTopLevelItem(groupItem) self.profilesTree.expandAll() def saveCurrent(self): storeCurrentConfiguration() self.fillTree() def createDescription(self, profile, isCustom): if profile.plugins: plugins = self.tr( "<p><b>This profile requires the following plugins</b>: %s</p>" ) % ", ".join(profile.plugins) else: plugins = "" return (self.tr('''<h2>%s</h2>%s<br>%s''') % (profile.name, profile.description, plugins)) def setInfoText(self): self.webView.setHtml( self.tr("Click on a profile to display its description.")) def currentItemChanged(self): item = self.profilesTree.currentItem() if item: if hasattr(item, "profile"): self.webView.setHtml( self.createDescription(item.profile, item.isCustom)) else: self.setInfoText() else: self.setInfoText() def toggleButtons(self): self.btnApply.setEnabled(False) self.btnRemove.setEnabled(False) if len(self.profilesTree.selectedItems()) > 0: item = self.profilesTree.selectedItems()[0] if not hasattr(item, 'isCustom'): return self.btnApply.setEnabled(True) if item.isCustom: self.btnRemove.setEnabled(True) def activateProfile(self): if len(self.profilesTree.selectedItems()) > 0: item = self.profilesTree.selectedItems()[0] if hasattr(item, "profile"): applyProfile(item.profile) self.fillTree() def removeProfile(self): if len(self.profilesTree.selectedItems()) > 0: item = self.profilesTree.selectedItems()[0] if hasattr(item, "profile"): os.remove(item.profile._filename) self.fillTree()
class BatchAlgorithmDialog(QgsProcessingAlgorithmDialogBase): def __init__(self, alg, parent=None): super().__init__( parent, mode=QgsProcessingAlgorithmDialogBase.DialogMode.Batch) self.setAlgorithm(alg) self.setWindowTitle( self.tr('Batch Processing - {0}').format( self.algorithm().displayName())) self.setMainWidget(BatchPanel(self, self.algorithm())) self.hideShortHelp() self.btnRunSingle = QPushButton( QCoreApplication.translate('BatchAlgorithmDialog', "Run as Single Process…")) self.btnRunSingle.clicked.connect(self.runAsSingle) self.buttonBox().addButton( self.btnRunSingle, QDialogButtonBox.ResetRole) # reset role to ensure left alignment self.context = None self.updateRunButtonVisibility() def runAsSingle(self): self.close() from processing.gui.AlgorithmDialog import AlgorithmDialog dlg = AlgorithmDialog(self.algorithm().create(), parent=iface.mainWindow()) dlg.show() dlg.exec_() def resetAdditionalGui(self): self.btnRunSingle.setEnabled(True) def blockAdditionalControlsWhileRunning(self): self.btnRunSingle.setEnabled(False) def processingContext(self): if self.context is None: self.feedback = self.createFeedback() self.context = dataobjects.createContext(self.feedback) self.context.setLogLevel(self.logLevel()) return self.context def runAlgorithm(self): alg_parameters = [] feedback = self.createFeedback() load_layers = self.mainWidget().checkLoadLayersOnCompletion.isChecked() project = QgsProject.instance() if load_layers else None for row in range(self.mainWidget().batchRowCount()): parameters, ok = self.mainWidget().parametersForRow( row, destinationProject=project, warnOnInvalid=True) if ok: alg_parameters.append(parameters) if not alg_parameters: return task = QgsScopedProxyProgressTask( self.tr('Batch Processing - {0}').format( self.algorithm().displayName())) multi_feedback = BatchFeedback(len(alg_parameters), feedback) feedback.progressChanged.connect(task.setProgress) algorithm_results = [] errors = [] with OverrideCursor(Qt.WaitCursor): self.blockControlsWhileRunning() self.setExecutedAnyResult(True) self.cancelButton().setEnabled(True) # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except Exception: # FIXME which one? pass start_time = time.time() for count, parameters in enumerate(alg_parameters): if feedback.isCanceled(): break self.setProgressText( QCoreApplication.translate( 'BatchAlgorithmDialog', '\nProcessing algorithm {0}/{1}…').format( count + 1, len(alg_parameters))) self.setInfo( self.tr('<b>Algorithm {0} starting…</b>').format( self.algorithm().displayName()), escapeHtml=False) multi_feedback.setCurrentStep(count) parameters = self.algorithm().preprocessParameters(parameters) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') # important - we create a new context for each iteration # this avoids holding onto resources and layers from earlier iterations, # and allows batch processing of many more items then is possible # if we hold on to these layers context = dataobjects.createContext(feedback) alg_start_time = time.time() multi_feedback.errors = [] results, ok = self.algorithm().run(parameters, context, multi_feedback) if ok: self.setInfo(QCoreApplication.translate( 'BatchAlgorithmDialog', 'Algorithm {0} correctly executed…').format( self.algorithm().displayName()), escapeHtml=False) feedback.pushInfo( self.tr( 'Execution completed in {0:0.2f} seconds'.format( time.time() - alg_start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) feedback.pushInfo('') algorithm_results.append({ 'parameters': parameters, 'results': results }) handleAlgorithmResults(self.algorithm(), context, multi_feedback, False, parameters) else: err = [e for e in multi_feedback.errors] self.setInfo(QCoreApplication.translate( 'BatchAlgorithmDialog', 'Algorithm {0} failed…').format( self.algorithm().displayName()), escapeHtml=False) feedback.reportError(self.tr( 'Execution failed after {0:0.2f} seconds'.format( time.time() - alg_start_time)), fatalError=False) errors.append({'parameters': parameters, 'errors': err}) feedback.pushInfo( self.tr('Batch execution completed in {0:0.2f} seconds'.format( time.time() - start_time))) if errors: feedback.reportError(self.tr( '{} executions failed. See log for further details.').format( len(errors)), fatalError=True) task = None self.finish(algorithm_results, errors) self.cancelButton().setEnabled(False) def finish(self, algorithm_results, errors): for count, results in enumerate(algorithm_results): self.loadHTMLResults(results['results'], count) self.createSummaryTable(algorithm_results, errors) self.resetGui() def loadHTMLResults(self, results, num): for out in self.algorithm().outputDefinitions(): if isinstance(out, QgsProcessingOutputHtml) and out.name( ) in results and results[out.name()]: resultsList.addResult(icon=self.algorithm().icon(), name='{} [{}]'.format( out.description(), num), result=results[out.name()]) def createSummaryTable(self, algorithm_results, errors): createTable = False for out in self.algorithm().outputDefinitions(): if isinstance( out, (QgsProcessingOutputNumber, QgsProcessingOutputString, QgsProcessingOutputBoolean)): createTable = True break if not createTable and not errors: return outputFile = getTempFilename('html') with codecs.open(outputFile, 'w', encoding='utf-8') as f: if createTable: for i, res in enumerate(algorithm_results): results = res['results'] params = res['parameters'] if i > 0: f.write('<hr>\n') f.write(self.tr('<h3>Parameters</h3>\n')) f.write('<table>\n') for param in self.algorithm().parameterDefinitions(): if not param.isDestination(): if param.name() in params: f.write( '<tr><th>{}</th><td>{}</td></tr>\n'.format( param.description(), params[param.name()])) f.write('</table>\n') f.write(self.tr('<h3>Results</h3>\n')) f.write('<table>\n') for out in self.algorithm().outputDefinitions(): if out.name() in results: f.write('<tr><th>{}</th><td>{}</td></tr>\n'.format( out.description(), results[out.name()])) f.write('</table>\n') if errors: f.write('<h2 style="color: red">{}</h2>\n'.format( self.tr('Errors'))) for i, res in enumerate(errors): errors = res['errors'] params = res['parameters'] if i > 0: f.write('<hr>\n') f.write(self.tr('<h3>Parameters</h3>\n')) f.write('<table>\n') for param in self.algorithm().parameterDefinitions(): if not param.isDestination(): if param.name() in params: f.write('<tr><th>{}</th><td>{}</td></tr>\n'.format( param.description(), params[param.name()])) f.write('</table>\n') f.write('<h3>{}</h3>\n'.format(self.tr('Error'))) f.write('<p style="color: red">{}</p>\n'.format( '<br>'.join(errors))) resultsList.addResult(icon=self.algorithm().icon(), name='{} [summary]'.format( self.algorithm().name()), timestamp=time.localtime(), result=outputFile)
class RemotesDialog(QDialog): def __init__(self, parent, repo): QDialog.__init__(self, parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint) self.changed = False self.repo = repo self.remotes = repo.remotes() self.setupUi() def setupUi(self): self.resize(500, 350) self.setWindowTitle("Remotes manager") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Vertical) self.buttonBox.setStandardButtons(QDialogButtonBox.Close) self.table = QTableWidget() self.table.verticalHeader().setVisible(False) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.addRowButton = QPushButton() self.addRowButton.setText("Add remote") self.editRowButton = QPushButton() self.editRowButton.setText("Edit remote") self.removeRowButton = QPushButton() self.removeRowButton.setText("Remove remote") self.buttonBox.addButton(self.addRowButton, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.editRowButton, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.removeRowButton, QDialogButtonBox.ActionRole) self.setTableContent() self.horizontalLayout.addWidget(self.table) self.horizontalLayout.addWidget(self.buttonBox) self.setLayout(self.horizontalLayout) self.buttonBox.rejected.connect(self.close) self.editRowButton.clicked.connect(self.editRow) self.addRowButton.clicked.connect(self.addRow) self.removeRowButton.clicked.connect(self.removeRow) QMetaObject.connectSlotsByName(self) self.editRowButton.setEnabled(False) self.removeRowButton.setEnabled(False) def setTableContent(self): self.table.clear() self.table.setColumnCount(2) self.table.setColumnWidth(0, 200) self.table.setColumnWidth(1, 200) self.table.setHorizontalHeaderLabels(["Name", "URL"]) self.table.horizontalHeader().setResizeMode(QHeaderView.Stretch) self.table.setRowCount(len(self.remotes)) for i, name in enumerate(self.remotes): url = self.remotes[name] self.table.setRowHeight(i, 22) item = QTableWidgetItem(name, 0) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self.table.setItem(i, 0, item) item = QTableWidgetItem(url, 0) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self.table.setItem(i, 1, item) self.table.itemSelectionChanged.connect(self.selectionChanged) def selectionChanged(self): enabled = len(self.table.selectedItems()) > 0 self.editRowButton.setEnabled(enabled) self.removeRowButton.setEnabled(enabled) def editRow(self): item = self.table.item(self.table.currentRow(), 0) if item is not None: name = item.text() url = self.table.item(self.table.currentRow(), 1).text() dlg = NewRemoteDialog(name, url, self) dlg.exec_() if dlg.ok: self.repo.removeremote(name) self.repo.addremote(dlg.name, dlg.url) del self.remotes[name] self.remotes[dlg.name] = dlg.url self.setTableContent() self.changed = True def removeRow(self): item = self.table.item(self.table.currentRow(), 0) if item is not None: name = item.text() self.repo.removeremote(name) del self.remotes[name] self.setTableContent() self.changed = True def addRow(self): dlg = NewRemoteDialog(parent=self) dlg.exec_() if dlg.ok: self.repo.addremote(dlg.name, dlg.url) self.remotes[dlg.name] = dlg.url self.setTableContent() self.changed = True
class FixedTableDialog(BASE, WIDGET): def __init__(self, param, table): """ Constructor for FixedTableDialog :param param: linked processing parameter :param table: initial table contents - squashed to 1-dimensional! """ super().__init__(None) self.setupUi(self) QgsGui.instance().enableAutoGeometryRestore(self) self.tblView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tblView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.param = param self.rettable = None # Additional buttons self.btnAdd = QPushButton(self.tr('Add row')) self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ActionRole) self.btnRemove = QPushButton(self.tr('Remove row(s)')) self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ActionRole) self.btnRemoveAll = QPushButton(self.tr('Remove all')) self.buttonBox.addButton(self.btnRemoveAll, QDialogButtonBox.ActionRole) self.btnAdd.clicked.connect(self.addRow) self.btnRemove.clicked.connect(lambda: self.removeRows()) self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True)) if self.param.hasFixedNumberRows(): self.btnAdd.setEnabled(False) self.btnRemove.setEnabled(False) self.btnRemoveAll.setEnabled(False) self.populateTable(table) def populateTable(self, table): cols = len(self.param.headers()) rows = len(table) // cols model = QStandardItemModel(rows, cols) # Set headers model.setHorizontalHeaderLabels(self.param.headers()) # Populate table for row in range(rows): for col in range(cols): item = QStandardItem(str(table[row * cols + col])) model.setItem(row, col, item) self.tblView.setModel(model) def accept(self): cols = self.tblView.model().columnCount() rows = self.tblView.model().rowCount() # Table MUST BE 1-dimensional to match core QgsProcessingParameterMatrix expectations self.rettable = [] for row in range(rows): for col in range(cols): self.rettable.append(str(self.tblView.model().item(row, col).text())) QDialog.accept(self) def reject(self): QDialog.reject(self) def removeRows(self, removeAll=False): if removeAll: self.tblView.model().clear() self.tblView.model().setHorizontalHeaderLabels(self.param.headers()) else: indexes = sorted(self.tblView.selectionModel().selectedRows()) self.tblView.setUpdatesEnabled(False) for i in reversed(indexes): self.tblView.model().removeRows(i.row(), 1) self.tblView.setUpdatesEnabled(True) def addRow(self): items = [QStandardItem('0') for i in range(self.tblView.model().columnCount())] self.tblView.model().appendRow(items)
class InspectionForm(FeatureForm): def __init__(self, *args, **kwargs): super(InspectionForm, self).__init__(*args, **kwargs) self.inspectionforms = [] self.joinkey = 'insp_loc_id' self.mapkeycolumn = 'mapkey' self.inspectionformname = 'inspection_data' self.countcolum = 'number' def uisetup(self): """ Called when the UI is fully constructed. You should connect any signals here. """ if self.formconfig['type'] == 'auto': self.AddInspectionButton = QPushButton() self.inspectiontabs = QTabWidget() self.layout().addRow(self.AddInspectionButton) self.layout().addRow(self.inspectiontabs) self.AddInspectionButton.pressed.connect(self.create_new_inspection) def load(self, feature, layers, values): """ Called before the form is loaded. This method can be used to do pre checks and halt the loading of the form if needed. Calling self.cnacelload("Your message") will stop the opening of the form and show the message to the user. >>> self.cancelload("Sorry you can't load this form now") You may alter the values given in the values dict. It will be passed to the form after this method returns. """ project = self.form.project self.inspectionform = project.form_by_name(self.inspectionformname) inspectionlayer = self.inspectionform.QGISLayer self.AddInspectionButton.setText("Add {}".format( self.inspectionform.label)) self.AddInspectionButton.setIcon(QIcon(self.inspectionform.icon)) if not self.is_capturing: inspections = self.find_inspections(self.feature) self.load_inspections(inspections, mapkeycolumn=self.mapkeycolumn) def find_inspections(self, feature): """ Override to return the inspections for this form forms feature. :param feature: :return: """ return [] def load_inspections(self, inspections, mapkeycolumn): """ Load the given inspections into the form :param inspections: :param mapkeycolumn: :return: """ inspectionlayer = self.inspectionform.QGISLayer for inspection in inspections: mapkey = inspection['mapkey'] inspectionfeature = feature_by_key(inspectionlayer, mapkey) self._add_inspectionform(inspectionfeature, editing=True, label=self.inspectionform.label) def create_new_inspection(self): """ Create a new inspection feature and add it to the form :return: """ feature = self.inspectionform.new_feature() # Give the new feature the key from the parent feature[self.joinkey] = self.bindingvalues[self.joinkey] self._add_inspectionform(feature, editing=False, label=self.inspectionform.label) def _add_inspectionform(self, feature, editing=False, label=''): """ Add a new inspection form for the given feature. :param feature: The feature to bind to the form :param editing: True to set the form into edit mode. False edit mode will add a new feature on save. """ count = len(self.inspectionforms) + 1 # Increase the inspection count for this feature feature[self.countcolum] = count # Create a new inspection form widget featureform = self.inspectionform.create_featureform(feature, editmode=editing) featureform.helprequest.connect(self.helprequest.emit) # Extract the values from the feature values = self.inspectionform.values_from_feature(feature) # Bind the values to the feature form featureform.bindvalues(values) # Add the tab and set the icon icon = QIcon(self.inspectionform.icon) self._add_tab(featureform, "{label} {count}".format(label=label, count=count), icon) # If the current count is over the max number of inspections then set the # button to disabled so we can't add anymore if count >= self.formconfig.get('maxinspections', 2): self.AddInspectionButton.setText("Max Inspections") self.AddInspectionButton.setEnabled(False) def _add_tab(self, widget, name, icon): """ Adds a tab to the tab widget with the given widget, name, and icon. :param widget: The widget to add to the tab :param name: The name of the tab :param icon: The icon of the tab """ index = self.inspectiontabs.addTab(widget, name) self.inspectionforms.append(widget) self.inspectiontabs.setCurrentIndex(index) self.inspectiontabs.setTabIcon(index, icon) def save(self): """ Override of the save logic for the feature form We override the save logic because we are not saving to the property layer but to the InspectionLocation table """ # Save all sub forms for subform in self.inspectionforms: subform.save()
class GraphDialog(QDialog): edit_patterns = 0 edit_curves = 1 titles = {edit_patterns: 'Pattern editor', edit_curves: 'Curve editor'} labels = {edit_patterns: 'Patterns', edit_curves: 'Curves'} def __init__(self, dockwidget, parent, params, edit_type): QDialog.__init__(self, parent) main_lay = QVBoxLayout(self) self.dockwidget = dockwidget self.params = params self.edit_type = edit_type self.x_label = '' self.y_label = '' self.setMinimumWidth(600) self.setMinimumHeight(400) self.setWindowTitle(self.titles[edit_type]) # TODO: softcode self.setWindowModality(QtCore.Qt.ApplicationModal) self.current = None self.current_saved = False # File self.lbl_file = QLabel('File:') self.fra_file = QFrame() self.fra_file.setContentsMargins(0, 0, 0, 0) fra_file_lay = QHBoxLayout(self.fra_file) if edit_type == self.edit_patterns: self.txt_file = QLineEdit(self.params.patterns_file) elif edit_type == self.edit_curves: self.txt_file = QLineEdit(self.params.curves_file) self.txt_file.setReadOnly(True) self.txt_file.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) self.txt_file.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) fra_file_lay.addWidget(self.txt_file) self.btn_file = QPushButton('Change') # TODO: softcode self.btn_file.clicked.connect(self.import_file) fra_file_lay.addWidget(self.btn_file) fra_file_lay.setContentsMargins(0, 0, 0, 0) self.lbl_list = QLabel(self.labels[edit_type]) self.lst_list = QListWidget() self.lst_list.currentItemChanged.connect(self.list_item_changed) # Form self.fra_form = QFrame() fra_form1_lay = QFormLayout(self.fra_form) fra_form1_lay.setContentsMargins(0, 0, 0, 0) fra_form1_lay.addRow(self.lbl_list, self.lst_list) # Buttons self.fra_buttons = QFrame() fra_buttons_lay = QHBoxLayout(self.fra_buttons) fra_buttons_lay.setContentsMargins(0, 0, 0, 0) if self.edit_type == self.edit_patterns: ele_name = 'pattern' elif self.edit_type == self.edit_curves: ele_name = 'curve' self.btn_new = QPushButton('New ' + ele_name) # TODO: softcode self.btn_new.clicked.connect(self.new_element) fra_buttons_lay.addWidget(self.btn_new) self.btn_import = QPushButton('Import ' + ele_name + 's') # TODO: softcode self.btn_import.clicked.connect(self.import_file) fra_buttons_lay.addWidget(self.btn_import) self.btn_save = QPushButton('Save current ' + ele_name) # TODO: softcode self.btn_save.clicked.connect(self.save) fra_buttons_lay.addWidget(self.btn_save) self.btn_del = QPushButton('Delete current ' + ele_name) # TODO: softcode self.btn_del.clicked.connect(self.del_item) fra_buttons_lay.addWidget(self.btn_del) # ID self.lbl_id = QLabel('ID:') self.txt_id = QLineEdit() self.txt_id.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.MinimumExpanding) self.lbl_desc = QLabel('Desc.:') self.txt_desc = QLineEdit() self.fra_id = QFrame() fra_id_lay = QHBoxLayout(self.fra_id) fra_id_lay.addWidget(self.lbl_id) fra_id_lay.addWidget(self.txt_id) fra_id_lay.addWidget(self.lbl_desc) fra_id_lay.addWidget(self.txt_desc) # Table form self.table = QTableWidget(self) self.rows_nr = 24 self.cols_nr = 2 self.table.setRowCount(self.rows_nr) self.table.setColumnCount(self.cols_nr) self.table.verticalHeader().setVisible(False) # Initialize empty table self.clear_table() self.table.itemChanged.connect(self.data_changed) self.fra_table = QFrame() fra_table_lay = QVBoxLayout(self.fra_table) fra_table_lay.setContentsMargins(0, 0, 0, 0) if edit_type == self.edit_curves: self.fra_pump_type = QFrame() fra_pump_type_lay = QFormLayout(self.fra_pump_type) self.lbl_pump_type = QLabel('Curve type:') # TODO: softcode self.cbo_pump_type = QComboBox() for key, name in Curve.type_names.items(): self.cbo_pump_type.addItem(name, key) fra_pump_type_lay.addRow(self.lbl_pump_type, self.cbo_pump_type) fra_table_lay.addWidget(self.fra_pump_type) self.cbo_pump_type.activated.connect(self.cbo_pump_type_activated) fra_table_lay.addWidget(self.table) self.btn_add_row = QPushButton('Add row') self.btn_add_row.clicked.connect(self.add_row) fra_table_lay.addWidget(self.btn_add_row) # Graph canvas self.fra_graph = QFrame() self.static_canvas = StaticMplCanvas(self.fra_graph, width=5, height=4, dpi=100) fra_graph_lay = QVBoxLayout(self.fra_graph) fra_graph_lay.addWidget(self.static_canvas) # Top frame self.fra_top = QFrame() fra_top_lay = QVBoxLayout(self.fra_top) fra_top_lay.addWidget(self.fra_form) fra_top_lay.addWidget(self.fra_id) fra_top_lay.addWidget(self.fra_buttons) # Bottom frame self.fra_bottom = QFrame() fra_bottom_lay = QHBoxLayout(self.fra_bottom) fra_bottom_lay.addWidget(self.fra_table) fra_bottom_lay.addWidget(self.fra_graph) # Main main_lay.addWidget(self.fra_top) main_lay.addWidget(self.fra_bottom) # Get existing patterns/curves self.need_to_update_graph = False if self.edit_type == self.edit_patterns: for pattern_id, pattern in self.params.patterns.items(): self.lst_list.addItem(pattern.id) elif self.edit_type == self.edit_curves: for curve_id, curve in self.params.curves.items(): self.lst_list.addItem(curve.id) if self.lst_list.count() > 0: self.lst_list.setCurrentRow(0) self.txt_id.setEnabled(True) self.txt_desc.setEnabled(True) self.btn_save.setEnabled(True) self.btn_del.setEnabled(True) self.table.setEnabled(True) self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) else: self.txt_id.setEnabled(False) self.txt_desc.setEnabled(False) self.btn_save.setEnabled(False) self.btn_del.setEnabled(False) self.table.setEnabled(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.new_dialog = None self.need_to_update_graph = True def cbo_pump_type_activated(self): self.update_table_headers() self.update_graph() def add_row(self): row_pos = self.table.rowCount() self.table.insertRow(row_pos) col = 0 item = QTableWidgetItem(str(row_pos)) if self.edit_type == self.edit_patterns: self.table.setItem(row_pos, col, item) item.setFlags(QtCore.Qt.ItemIsSelectable) def setVisible(self, bool): QDialog.setVisible(self, bool) self.update_table_headers() self.update_graph() def list_item_changed(self): p_index = self.lst_list.currentRow() flags = Qt.ItemFlags() flags != Qt.ItemIsEnabled # Clear table self.clear_table() self.need_to_update_graph = False if p_index >= 0: self.table.setRowCount(0) if self.edit_type == self.edit_patterns: self.current = self.params.patterns[ self.lst_list.currentItem().text()] for v in range(len(self.current.values)): row_pos = self.table.rowCount() self.table.insertRow(row_pos) item = QTableWidgetItem(str(v)) item.setFlags(flags) self.table.setItem(v, 0, item) self.table.setItem( v, 1, QTableWidgetItem(str(self.current.values[v]))) elif self.edit_type == self.edit_curves: self.current = self.params.curves[ self.lst_list.currentItem().text()] for v in range(len(self.current.xs)): row_pos = self.table.rowCount() self.table.insertRow(row_pos) self.table.setItem( v, 0, QTableWidgetItem(str(self.current.xs[v]))) self.table.setItem( v, 1, QTableWidgetItem(str(self.current.ys[v]))) curve_type = self.current.type self.cbo_pump_type.setCurrentIndex(curve_type) # Update GUI self.txt_id.setText(self.current.id) self.txt_desc.setText(self.current.desc) self.update_table_headers() # Update graph self.need_to_update_graph = True self.update_graph() else: # No curves self.txt_id.setText('') self.txt_desc.setText('') # Update table and chart self.need_to_update_graph = False for v in range(self.table.columnCount()): self.table.setItem(v, 1, QTableWidgetItem('')) self.need_to_update_graph = True self.update_graph() def import_file(self): config_file = ConfigFile(Parameters.config_file_path) directory = None if self.edit_type == GraphDialog.edit_curves: directory = self.params.last_curves_dir elif self.edit_type == GraphDialog.edit_patterns: directory = self.params.last_patterns_dir if directory is None: directory = self.params.last_project_dir file_path, __ = QFileDialog.getOpenFileName(self, 'Select file', directory, 'Files (*.txt *.inp)') if file_path is None or file_path == '': return else: if self.edit_type == GraphDialog.edit_patterns: # Save patterns file path in configuration file config_file.set_patterns_file_path(file_path) Parameters.patterns_file = file_path elif self.edit_type == GraphDialog.edit_curves: # Save curve file path in configuration file config_file.set_curves_file_path(file_path) Parameters.curves_file = file_path self.read(file_path) def read(self, file_path): self.lst_list.clear() if self.edit_type == self.edit_patterns: InpFile.read_patterns(self.params, file_path) for pattern_id, pattern in self.params.patterns.items(): # desc = ' (' + pattern.desc + ')' if pattern.desc is not None else '' self.lst_list.addItem(pattern.id) self.params.patterns[pattern.id] = pattern elif self.edit_type == self.edit_curves: InpFile.read_curves(self.params, file_path) for curve_id, curve in self.params.curves.items(): # desc = ' (' + curve.desc + ')' if curve.desc is not None else '' self.lst_list.addItem(curve.id) self.params.curves[curve.id] = curve if self.lst_list.count() > 0: self.lst_list.setCurrentRow(0) def new_element(self): old_ids = [] if self.edit_type == self.edit_patterns: for pattern in self.params.patterns.values(): old_ids.append(pattern.id) elif self.edit_type == self.edit_curves: for curve in self.params.curves.values(): old_ids.append(curve.id) self.new_dialog = NewIdDialog(self, old_ids) self.new_dialog.exec_() new_id = self.new_dialog.get_newid() description = self.new_dialog.get_description() if new_id is None or description is None: return if self.edit_type == self.edit_patterns: new_pattern = Pattern(new_id, description) self.params.patterns[new_pattern.id] = new_pattern self.lst_list.addItem(new_pattern.id) elif self.edit_type == self.edit_curves: curve_type = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) new_curve = Curve(new_id, curve_type, desc=description) self.params.curves[new_curve.id] = new_curve self.lst_list.addItem(new_curve.id) self.lst_list.setCurrentRow(self.lst_list.count() - 1) self.txt_id.setText(new_id) self.txt_desc.setText(description) # Clear table self.clear_table() self.static_canvas.axes.clear() self.txt_id.setEnabled(True) self.txt_desc.setEnabled(True) self.btn_save.setEnabled(True) self.btn_del.setEnabled(True) self.table.setEnabled(True) self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) def save(self): self.need_to_update_graph = False # Check for ID if not self.txt_id.text(): QMessageBox.warning( self, Parameters.plug_in_name, u'Please specify the ID.', # TODO: softcode QMessageBox.Ok) return if self.edit_type == GraphDialog.edit_patterns: values = [] for row in range(self.table.rowCount()): item = self.table.item(row, 1) if item is not None and item.text() != '': values.append(self.from_item_to_val(item)) else: values.append('0') pattern = Pattern(self.txt_id.text(), self.txt_desc.text(), values) old_patterns = self.params.patterns old_patterns[pattern.id] = pattern self.params.patterns = old_patterns self.lst_list.currentItem().setText(pattern.id) elif self.edit_type == GraphDialog.edit_curves: # Check for ID unique xs = [] ys = [] for row in range(self.table.rowCount()): item_x = self.table.item(row, 0) item_y = self.table.item(row, 1) if item_x.text().strip() != '' and item_y.text().strip() != '': xs.append(self.from_item_to_val(item_x)) ys.append(self.from_item_to_val(item_y)) curve_type = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) curve = Curve(self.txt_id.text(), curve_type, self.txt_desc.text()) for v in range(len(xs)): curve.append_xy(xs[v], ys[v]) old_curves = self.params.curves old_curves[curve.id] = curve self.params.curves = old_curves self.lst_list.currentItem().setText(curve.id) # Update GUI self.dockwidget.update_curves_combo() # self.read() self.need_to_update_graph = True def clear_table(self): self.need_to_update_graph = False for r in range(self.table.rowCount()): self.table.setItem(r, 0, QTableWidgetItem(None)) self.table.setItem(r, 1, QTableWidgetItem(None)) for row in range(self.rows_nr): for col in range(self.cols_nr): if self.edit_type == self.edit_patterns: if col == 0: item = QTableWidgetItem(str(row)) self.table.setItem(row, col, item) item.setFlags(QtCore.Qt.ItemIsSelectable) # elif col == 1 and row == 0: # item = QTableWidgetItem(str(1)) # self.table.setItem(row, col, item) # item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) # elif self.edit_type == self.edit_curves: # if row == 0: # item = QTableWidgetItem(str(0)) # self.table.setItem(row, 0, item) # item = QTableWidgetItem(str(1)) # self.table.setItem(row, 1, item) # item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.need_to_update_graph = True def del_item(self): selected_row = self.lst_list.currentRow() name = self.lst_list.currentItem().text() if selected_row < 0: return self.lst_list.takeItem(selected_row) if self.lst_list.count() == 0: self.txt_id.setEnabled(False) self.txt_desc.setEnabled(False) self.btn_save.setEnabled(False) self.btn_del.setEnabled(False) self.table.setEnabled(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) if self.edit_type == GraphDialog.edit_curves: del self.params.curves[name] # Update GUI self.dockwidget.update_curves_combo() elif self.edit_type == GraphDialog.edit_patterns: del self.params.patterns[name] # Update GUI self.dockwidget.update_patterns_combo() def data_changed(self): if self.need_to_update_graph: self.update_graph() def update_table_headers(self): if self.edit_type == self.edit_patterns: self.x_label = 'Time period' self.y_label = 'Multiplier' elif self.edit_type == self.edit_curves: cbo_data = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) if cbo_data == Curve.type_efficiency: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Efficiency ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_headloss: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Headloss ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_pump: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Head ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_volume: self.x_label = 'Height ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Volume ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' self.table.setHorizontalHeaderLabels([self.x_label, self.y_label]) # TODO: softcode def update_graph(self): if not self.need_to_update_graph: return xs = [] ys = [] for row in range(self.table.rowCount()): item = self.table.item(row, 0) x = self.from_item_to_val(item) item = self.table.item(row, 1) y = self.from_item_to_val(item) if x is not None: xs.append(float(x)) if y is not None: ys.append(float(y)) if len(xs) == 0 or len(ys) == 0: self.static_canvas.clear() return xys_t = list(zip(xs, ys)) xys_t.sort() xys = list(zip(*xys_t)) xs = xys[0] ys = xys[1] if self.edit_type == self.edit_patterns: y_axis_label = 'Mult. avg.: ' + '{0:.2f}'.format( (numpy.average(ys))) self.static_canvas.draw_bars_graph( ys, time_period=self.params.times.pattern_timestep, y_axes_label=y_axis_label) elif self.edit_type == self.edit_curves: # Account for different types of curves cbo_data = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) series_length = min(len(xs), len(ys)) # Need to account for different types of curves if cbo_data == Curve.type_efficiency or cbo_data == Curve.type_headloss or cbo_data == Curve.type_volume: self.static_canvas.draw_line_graph(xs[:series_length], ys[:series_length], self.x_label, self.y_label) elif cbo_data == Curve.type_pump: if series_length == 1 or series_length == 3: if series_length == 1: # 3 curve points curve_xs = [0, xs[0], xs[0] * 2] curve_ys = [ys[0] * 1.33, ys[0], 0] # y = a * x^2 + b * x + c elif series_length == 3: # 3 curve points curve_xs = [xs[0], xs[1], xs[2]] curve_ys = [ys[0], ys[1], ys[2]] (a, b, c) = numpy.polyfit(curve_xs, curve_ys, 2) # Create a few interpolated values interp_xs = [] interp_ys = [] n_vals = 30 for v in range(n_vals + 1): x = (curve_xs[2] - curve_xs[0]) / n_vals * v interp_xs.append(x) y = a * x**2 + b * x + c interp_ys.append(y) self.static_canvas.draw_line_graph(interp_xs, interp_ys, self.x_label, self.y_label) else: self.static_canvas.draw_line_graph(xs[:series_length], ys[:series_length], self.x_label, self.y_label) def from_item_to_val(self, item): if item is None: value = None else: value = item.text() try: value = float(value) value = max(value, 0) except: value = None return value
def show_results(self, api_results, pg_connections=dict()): """Display the results in a table.""" logger.info("Results manager called. Displaying the results") tbl_result = self.tbl_result # Get the name (and other informations) of all databases whose # connection is set up in QGIS if pg_connections == {}: pg_connections = self.pg_connections else: pass # Set table rows if api_results.get("total") >= 10: tbl_result.setRowCount(10) else: tbl_result.setRowCount(api_results.get("total")) # dimensions (see https://github.com/isogeo/isogeo-plugin-qgis/issues/276) hheader = tbl_result.horizontalHeader() # make the entire width of the table is occupied hheader.setSectionResizeMode(1) # make date and icone columns width adapted to their content # so title and adding columns occupy the rest of the available width hheader.setSectionResizeMode(1, 3) hheader.setSectionResizeMode(2, 3) vheader = tbl_result.verticalHeader() # Looping inside the table lines. For each of them, showing the title, # abstract, geometry type, and a button that allow to add the data # to the canvas. count = 0 for i in api_results.get("results"): md = Metadata.clean_attributes(i) # get metadata's keywords from tags, they will be displayed in QGIS # 'layer properties' if the layer is added to the canvas md.keywords = [ md.tags.get(kw) for kw in md.tags if kw.startswith("keyword:isogeo") ] # COLUMN 1 - Title and abstract # Displaying the metadata title inside a button title = md.title_or_name() if title: btn_md_title = QPushButton( plg_tools.format_button_title(title)) else: btn_md_title = QPushButton( self.tr("Undefined", context=__class__.__name__)) btn_md_title.setStyleSheet("font: italic") # Connecting the button to the full metadata popup btn_md_title.pressed.connect(partial(self.md_asked.emit, md._id)) # Putting the abstract as a tooltip on this button if md.abstract: btn_md_title.setToolTip(md.abstract[:300]) else: pass # Insert it in column 1 tbl_result.setCellWidget(count, 0, btn_md_title) # COLUMN 2 - Data last update lbl_date = QLabel(tbl_result) lbl_date.setText(plg_tools.handle_date(md._modified)) lbl_date.setMargin(5) lbl_date.setAlignment(Qt.AlignCenter) tbl_result.setCellWidget(count, 1, lbl_date) # COLUMN 3 - Geometry type lbl_geom = QLabel(tbl_result) if md.geometry: if md.geometry == "TIN": tbl_result.setItem(count, 2, QTableWidgetItem("TIN")) elif md.geometry in known_geom_list: for geom_type in self.pix_geom_dict: if md.geometry in geom_type: geom_item = self.pix_geom_dict.get(geom_type) lbl_geom.setPixmap(geom_item.get("pix")) lbl_geom.setToolTip( self.tr(geom_item.get("tooltip"), context=__class__.__name__)) else: continue else: tbl_result.setItem( count, 2, QTableWidgetItem( self.tr("Unknown geometry", context=__class__.__name__)), ) else: if "rasterDataset" in md.type: lbl_geom.setPixmap(pix_rastr) lbl_geom.setToolTip( self.tr("Raster", context=__class__.__name__)) elif "service" in md.type: lbl_geom.setPixmap(pix_serv) lbl_geom.setToolTip( self.tr("Service", context=__class__.__name__)) else: lbl_geom.setPixmap(pix_nogeo) lbl_geom.setToolTip( self.tr("Unknown geometry", context=__class__.__name__)) lbl_geom.setAlignment(Qt.AlignCenter) tbl_result.setCellWidget(count, 2, lbl_geom) # COLUMN 4 - Add options add_options_dict = {} # Build metadata portal URL if the setting is checked in "Settings" tab add_portal_md_url = int( qsettings.value("isogeo/settings/add_metadata_url_portal", 0)) portal_base_url = self.form_mng.input_portal_url.text() portal_md_url = "" if add_portal_md_url and portal_base_url != "": portal_md_url = portal_base_url + md._id else: pass # Files and PostGIS direct access if md.format: # If the data is a vector and the path is available, store # useful information in the dict if md.format in li_formats_vect and md.path: add_path = self._filepath_builder(md.path) if add_path: params = [ "vector", add_path, md.title, md.abstract, md.keywords, portal_md_url, ] add_options_dict[self.tr( "Data file", context=__class__.__name__)] = params else: pass # Same if the data is a raster elif md.format in li_formats_rastr and md.path: add_path = self._filepath_builder(md.path) if add_path: params = [ "raster", add_path, md.title, md.abstract, md.keywords, portal_md_url, ] add_options_dict[self.tr( "Data file", context=__class__.__name__)] = params else: pass # If the data is a postGIS table and the connexion has # been saved in QGIS. elif md.format == "postgis": if md.path: base_name = md.path else: base_name = "No path" if base_name in pg_connections.keys(): params = {} params["base_name"] = base_name schema_table = md.name if schema_table is not None and "." in schema_table: params["schema"] = schema_table.split(".")[0] params["table"] = schema_table.split(".")[1] params["abstract"] = md.abstract params["title"] = md.title params["keywords"] = md.keywords params["md_portal_url"] = portal_md_url add_options_dict[self.tr( "PostGIS table", context=__class__.__name__)] = params else: pass else: pass else: logger.debug( "Metadata {} has a format ({}) but it's not handled hear or path is" "missing".format(md._id, md.format)) pass # Associated service layers if md.type == "vectorDataset" or md.type == "rasterDataset": for layer in md.serviceLayers: service = layer.get("service") if service is not None: srv_details = { "path": service.get("path", "NR"), "formatVersion": service.get("formatVersion"), } # WMTS if service.get("format") == "wmts": params = self.layer_adder.build_wmts_url( layer, srv_details, rsc_type="ds_dyn_lyr_srv") # EFS, EMS, WMS or WFS elif service.get("format") in list( self.service_dict.keys()): url_builder = self.service_dict.get( service.get("format")).get("url_builder") params = url_builder( layer, srv_details, rsc_type="ds_dyn_lyr_srv", mode="quicky", ) else: params = [0] logger.debug( "Service with no format detected for '{}' metadata : {}" .format(md._id, service)) pass if params[0] != 0: basic_md = [ md.title, md.abstract, md.keywords, portal_md_url, ] params.append(basic_md) add_options_dict["{} : {}".format( params[0], params[1])] = params else: pass # New association mode. For services metadata sheet, the layers # are stored in the purposely named include: "layers". elif md.type == "service": if md.layers is not None: srv_details = { "path": md.path, "formatVersion": md.formatVersion, } # WMTS if md.format == "wmts": for layer in md.layers: name_url = self.layer_adder.build_wmts_url( layer, srv_details, rsc_type="service") if name_url[0] != 0: btn_label = "WMTS : {}".format(name_url[1]) add_options_dict[btn_label] = name_url else: continue # EFS, EMS, WMS or WFS elif md.format in list(self.service_dict.keys()): url_builder = self.service_dict.get( md.format).get("url_builder") for layer in md.layers: name_url = url_builder(layer, srv_details, rsc_type="service", mode="quicky") if name_url[0] != 0: add_options_dict[name_url[5]] = name_url else: continue else: pass else: pass # Now the plugin has tested every possibility for the layer to be # added. The "Add" column has to be filled accordingly. # If the data can't be added, just insert "can't" text. if add_options_dict == {}: text = self.tr("Can't be added", context=__class__.__name__) fake_button = QPushButton(text) fake_button.setStyleSheet("text-align: left") fake_button.setEnabled(False) tbl_result.setCellWidget(count, 3, fake_button) # If the data can be added else: data_info = {"limitations": None, "layer": None} # retrieves data limitations data_info["limitations"] = md.limitations # If there is only one way for the data to be added, insert a button. if len(add_options_dict) == 1: text = list(add_options_dict.keys())[0] params = add_options_dict.get(text) option_type = text.split(" : ")[0] # services if option_type.lower() in list(self.service_dict.keys()): icon = self.service_dict.get( option_type.lower()).get("ico") # PostGIS table elif option_type.startswith( self.tr("PostGIS table", context=__class__.__name__)): icon = ico_pgis # Data file elif option_type.startswith( self.tr("Data file", context=__class__.__name__)): icon = ico_file # Unkown option else: logger.debug( "Undefined add option type : {}/{} --> {}".format( option_type, text, params)) # create the add button with the icon corresponding to the add option add_button = QPushButton(icon, option_type) add_button.setStyleSheet("text-align: left") # connect the widget to the adding method from LayerAdder class data_info["layer"] = ("info", params, count) add_button.pressed.connect( partial(self.lim_checker.check, data_info)) tbl_result.setCellWidget(count, 3, add_button) # Else, add a combobox, storing all possibilities. else: combo = QComboBox() for option in add_options_dict: option_type = option.split(" : ")[0] # services if option_type.lower() in list( self.service_dict.keys()): icon = self.service_dict.get( option_type.lower()).get("ico") # PostGIS table elif option.startswith( self.tr("PostGIS table", context=__class__.__name__)): icon = ico_pgis # Data file elif option.startswith( self.tr("Data file", context=__class__.__name__)): icon = ico_file # Unkown option else: logger.debug( "Undefined add option type : {}/{} --> {}". format(option_type, text, params)) # add a combobox item with the icon corresponding to the add option combo.addItem(icon, option, add_options_dict.get(option)) # connect the widget to the adding method from LayerAdder class data_info["layer"] = ("index", count) combo.activated.connect( partial(self.lim_checker.check, data_info)) combo.model().sort( 0) # sort alphabetically on option prefix. see: #113 tbl_result.setCellWidget(count, 3, combo) # make the widget (button or combobox) width the same as the column width tbl_result.cellWidget(count, 3).setFixedWidth(hheader.sectionSize(3)) count += 1 # dimensions bis (see https://github.com/isogeo/isogeo-plugin-qgis/issues/276) # last column take the width of his content hheader.setSectionResizeMode(3, 3) # the height of the row adapts to the content without falling below 30px vheader.setMinimumSectionSize(30) vheader.setSectionResizeMode(3) # method ending return None
class MappingDialog(QDialog): """construct the mapping GUI""" targetTypes = [] importTypes = [] layerType = [] labels = {} comboBoxesType = {} comboBoxesLayer = {} comboBoxesLayerType = {} nextButton = None prevButton = None def __init__(self, parent=None): super(MappingDialog, self).__init__(parent) self.setWindowTitle("Maak een mapping t.b.v. het importeren") self.qlayout = QGridLayout(self) self.setWindowFlag(Qt.WindowCloseButtonHint, False) self.buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.nextButton = QPushButton() self.nextButton.setText("Volgende") self.prevButton = QPushButton() self.prevButton.setText("Vorige") self.label_laag = QLabel(self) self.label_laag.setText("Importeer in laag") self.label_types = QLabel(self) self.label_types.setText("Import types in bestand") self.label_conversie = QLabel(self) self.label_conversie.setText("Conversie naar type laag") self.label_target = QLabel(self) self.label_target.setText("Converteer naar type") self.qlayout.addWidget(self.label_types, 0, 0) self.qlayout.addWidget(self.label_conversie, 0, 1) self.qlayout.addWidget(self.label_laag, 0, 2) self.qlayout.addWidget(self.label_target, 0, 3) self.load_types() def load_types(self): i = 1 for importType in self.importTypes: try: self.comboBoxesLayer[importType].setEnabled(False) except: # pylint: disable=bare-except pass self.labels[i] = QLabel(self) self.labels[i].setText(importType) self.comboBoxesLayerType[importType] = QComboBox(self) self.comboBoxesLayerType[importType].addItems(self.layerType) self.qlayout.addWidget(self.labels[i], i, 0) self.qlayout.addWidget(self.comboBoxesLayerType[importType], i, 1) self.comboBoxesLayerType[importType].setEnabled(False) i += 1 self.qlayout.addWidget(self.nextButton, i, 1) self.qlayout.addWidget(self.prevButton, i, 0) self.qlayout.addWidget(self.buttons, i + 1, 0) self.set_buttons(False, True, None, self.load_layertype, False) def load_layertype(self): i = 1 for importType in self.comboBoxesLayerType: try: self.comboBoxesType[importType].setEnabled(False) except: # pylint: disable=bare-except pass self.comboBoxesLayerType[importType].setEnabled(False) self.comboBoxesLayer[importType] = QComboBox(self) layerType = self.comboBoxesLayerType[importType].currentText() layerNames = self.targetTypes[layerType].keys() self.comboBoxesLayer[importType].addItems(layerNames) self.qlayout.addWidget(self.comboBoxesLayer[importType], i, 2) i += 1 self.set_buttons(True, True, self.load_types, self.load_targettypes, False) def load_targettypes(self): i = 1 for importType in self.comboBoxesLayer: self.comboBoxesLayer[importType].setEnabled(False) self.comboBoxesType[importType] = QComboBox(self) layerType = self.comboBoxesLayerType[importType].currentText() layerName = self.comboBoxesLayer[importType].currentText() types = self.targetTypes[layerType][layerName] self.comboBoxesType[importType].addItems(types) self.qlayout.addWidget(self.comboBoxesType[importType], i, 3) i += 1 self.set_buttons(True, False, self.load_layertype, None, True) def set_buttons(self, prev, nxt, conPrev, conNext, okBtn): try: self.prevButton.clicked.disconnect() except: # pylint: disable=bare-except pass try: self.nextButton.clicked.disconnect() except: # pylint: disable=bare-except pass self.prevButton.setEnabled(prev) self.nextButton.setEnabled(nxt) if conPrev: self.prevButton.clicked.connect(conPrev) if conNext: self.nextButton.clicked.connect(conNext) self.buttons.button(QDialogButtonBox.Ok).setEnabled(okBtn) @staticmethod def getMapping(parent=None): """initiate the GUI and redirect the input""" mapping = {} dialog = MappingDialog(parent) result = dialog.exec_() for importType in dialog.importTypes: try: convType = dialog.comboBoxesLayerType[importType].currentText() except: # pylint: disable=bare-except convType = None try: convLayer = dialog.comboBoxesLayer[importType].currentText() except: # pylint: disable=bare-except convLayer = None try: convTargetType = dialog.comboBoxesType[importType].currentText( ) except: # pylint: disable=bare-except convTargetType = None mapping.update({ importType: { "convType": convType, "layerName": convLayer, "targetType": convTargetType } }) return (mapping, result == QDialog.Accepted)
class AlgorithmDialog(QgsProcessingAlgorithmDialogBase): def __init__(self, alg, in_place=False, parent=None): super().__init__(parent) self.feedback_dialog = None self.in_place = in_place self.active_layer = None self.context = None self.feedback = None self.setAlgorithm(alg) self.setMainWidget(self.getParametersPanel(alg, self)) if not self.in_place: self.runAsBatchButton = QPushButton( QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…")) self.runAsBatchButton.clicked.connect(self.runAsBatch) self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole ) # reset role to ensure left alignment else: self.active_layer = iface.activeLayer() self.runAsBatchButton = None has_selection = self.active_layer and ( self.active_layer.selectedFeatureCount() > 0) self.buttonBox().button(QDialogButtonBox.Ok).setText( QCoreApplication. translate("AlgorithmDialog", "Modify Selected Features" ) if has_selection else QCoreApplication. translate("AlgorithmDialog", "Modify All Features")) self.buttonBox().button(QDialogButtonBox.Close).setText( QCoreApplication.translate("AlgorithmDialog", "Cancel")) self.setWindowTitle(self.windowTitle() + ' | ' + self.active_layer.name()) self.updateRunButtonVisibility() def getParametersPanel(self, alg, parent): panel = ParametersPanel(parent, alg, self.in_place) return panel def runAsBatch(self): self.close() dlg = BatchAlgorithmDialog(self.algorithm().create(), parent=iface.mainWindow()) dlg.show() dlg.exec_() def resetAdditionalGui(self): if not self.in_place: self.runAsBatchButton.setEnabled(True) def blockAdditionalControlsWhileRunning(self): if not self.in_place: self.runAsBatchButton.setEnabled(False) def setParameters(self, parameters): self.mainWidget().setParameters(parameters) def createProcessingParameters(self): if self.mainWidget() is None: return {} else: return self.mainWidget().createProcessingParameters() def runAlgorithm(self): self.feedback = self.createFeedback() self.context = dataobjects.createContext(self.feedback) checkCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_CRS) try: parameters = self.createProcessingParameters() if checkCRS and not self.algorithm().validateInputCrs( parameters, self.context): reply = QMessageBox.question( self, self.tr("Unmatching CRS's"), self.tr('Parameters do not all use the same CRS. This can ' 'cause unexpected results.\nDo you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return ok, msg = self.algorithm().checkParameterValues( parameters, self.context) if not ok: QMessageBox.warning(self, self.tr('Unable to execute algorithm'), msg) return self.blockControlsWhileRunning() self.setExecutedAnyResult(True) self.cancelButton().setEnabled(False) self.iterateParam = None for param in self.algorithm().parameterDefinitions(): if isinstance( parameters.get(param.name(), None), QgsProcessingFeatureSourceDefinition ) and parameters[param.name( )].flags & QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature: self.iterateParam = param.name() break self.clearProgress() self.feedback.pushVersionInfo(self.algorithm().provider()) if self.algorithm().provider().warningMessage(): self.feedback.reportError( self.algorithm().provider().warningMessage()) self.setProgressText( QCoreApplication.translate('AlgorithmDialog', 'Processing algorithm…')) self.setInfo(QCoreApplication.translate( 'AlgorithmDialog', '<b>Algorithm \'{0}\' starting…</b>').format( self.algorithm().displayName()), escapeHtml=False) self.feedback.pushInfo(self.tr('Input parameters:')) display_params = [] for k, v in parameters.items(): display_params.append("'" + k + "' : " + self.algorithm( ).parameterDefinition(k).valueAsPythonString(v, self.context)) self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }') self.feedback.pushInfo('') start_time = time.time() if self.iterateParam: # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) if executeIterating(self.algorithm(), parameters, self.iterateParam, self.context, self.feedback): self.feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'). format(time.time() - start_time)) self.cancelButton().setEnabled(False) self.finish(True, parameters, self.context, self.feedback) else: self.cancelButton().setEnabled(False) self.resetGui() else: command = self.algorithm().asPythonCommand( parameters, self.context) if command: ProcessingLog.addToLog(command) QgsGui.instance().processingRecentAlgorithmLog().push( self.algorithm().id()) self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) def on_complete(ok, results): if ok: self.feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'). format(time.time() - start_time)) self.feedback.pushInfo(self.tr('Results:')) r = { k: v for k, v in results.items() if k not in ('CHILD_RESULTS', 'CHILD_INPUTS') } self.feedback.pushCommandInfo(pformat(r)) else: self.feedback.reportError( self.tr('Execution failed after {0:0.2f} seconds'). format(time.time() - start_time)) self.feedback.pushInfo('') if self.feedback_dialog is not None: self.feedback_dialog.close() self.feedback_dialog.deleteLater() self.feedback_dialog = None self.cancelButton().setEnabled(False) self.finish(ok, results, self.context, self.feedback, in_place=self.in_place) self.feedback = None self.context = None if not self.in_place and not ( self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading): # Make sure the Log tab is visible before executing the algorithm self.showLog() task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, self.context, self.feedback) if task.isCanceled(): on_complete(False, {}) else: task.executed.connect(on_complete) self.setCurrentTask(task) else: self.proxy_progress = QgsProxyProgressTask( QCoreApplication.translate( "AlgorithmDialog", "Executing “{}”").format( self.algorithm().displayName())) QgsApplication.taskManager().addTask(self.proxy_progress) self.feedback.progressChanged.connect( self.proxy_progress.setProxyProgress) self.feedback_dialog = self.createProgressDialog() self.feedback_dialog.show() if self.in_place: ok, results = execute_in_place(self.algorithm(), parameters, self.context, self.feedback) else: ok, results = execute(self.algorithm(), parameters, self.context, self.feedback) self.feedback.progressChanged.disconnect() self.proxy_progress.finalize(ok) on_complete(ok, results) except AlgorithmDialogBase.InvalidParameterValue as e: try: self.buttonBox().accepted.connect( lambda e=e: e.widget.setPalette(QPalette())) palette = e.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) e.widget.setPalette(palette) except: pass self.messageBar().clearWidgets() self.messageBar().pushMessage( "", self.tr("Wrong or missing parameter value: {0}").format( e.parameter.description()), level=Qgis.Warning, duration=5) except AlgorithmDialogBase.InvalidOutputExtension as e: try: self.buttonBox().accepted.connect( lambda e=e: e.widget.setPalette(QPalette())) palette = e.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) e.widget.setPalette(palette) except: pass self.messageBar().clearWidgets() self.messageBar().pushMessage("", e.message, level=Qgis.Warning, duration=5) def finish(self, successful, result, context, feedback, in_place=False): keepOpen = not successful or ProcessingConfig.getSetting( ProcessingConfig.KEEP_DIALOG_OPEN) if not in_place and self.iterateParam is None: # add html results to results dock for out in self.algorithm().outputDefinitions(): if isinstance(out, QgsProcessingOutputHtml) and out.name( ) in result and result[out.name()]: resultsList.addResult(icon=self.algorithm().icon(), name=out.description(), timestamp=time.localtime(), result=result[out.name()]) if not handleAlgorithmResults(self.algorithm(), context, feedback, not keepOpen, result): self.resetGui() return self.setExecuted(True) self.setResults(result) self.setInfo(self.tr('Algorithm \'{0}\' finished').format( self.algorithm().displayName()), escapeHtml=False) self.algorithmFinished.emit(successful, result) if not in_place and not keepOpen: self.close() else: self.resetGui() if self.algorithm().hasHtmlOutputs(): self.setInfo(self.tr( 'HTML output has been generated by this algorithm.' '\nOpen the results dialog to check it.'), escapeHtml=False)
class FixedTableDialog(BASE, WIDGET): def __init__(self, param, table): super(FixedTableDialog, self).__init__(None) self.setupUi(self) self.tblView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tblView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.param = param self.rettable = None # Additional buttons self.btnAdd = QPushButton(self.tr('Add row')) self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ActionRole) self.btnRemove = QPushButton(self.tr('Remove row(s)')) self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ActionRole) self.btnRemoveAll = QPushButton(self.tr('Remove all')) self.buttonBox.addButton(self.btnRemoveAll, QDialogButtonBox.ActionRole) self.btnAdd.clicked.connect(self.addRow) self.btnRemove.clicked.connect(lambda: self.removeRows()) self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True)) if self.param.fixedNumOfRows: self.btnAdd.setEnabled(False) self.btnRemove.setEnabled(False) self.btnRemoveAll.setEnabled(False) self.populateTable(table) def populateTable(self, table): cols = len(self.param.cols) rows = len(table) model = QStandardItemModel(rows, cols) # Set headers model.setHorizontalHeaderLabels(self.param.cols) # Populate table for i in range(rows): for j in range(cols): item = QStandardItem(table[i][j]) model.setItem(i, j, item) self.tblView.setModel(model) def accept(self): cols = self.tblView.model().columnCount() rows = self.tblView.model().rowCount() self.rettable = [] for i in range(rows): self.rettable.append(list()) for j in range(cols): self.rettable[i].append( str(self.tblView.model().item(i, j).text())) QDialog.accept(self) def reject(self): QDialog.reject(self) def removeRows(self, removeAll=False): if removeAll: self.tblView.model().clear() self.tblView.model().setHorizontalHeaderLabels(self.param.cols) else: indexes = sorted(self.tblView.selectionModel().selectedRows()) self.tblView.setUpdatesEnabled(False) for i in reversed(indexes): self.tblView.model().removeRows(i.row(), 1) self.tblView.setUpdatesEnabled(True) def addRow(self): items = [ QStandardItem('0') for i in range(self.tblView.model().columnCount()) ] self.tblView.model().appendRow(items)
class OutputAnalyserDialog(QDialog): def __init__(self, iface, parent, params): QDialog.__init__(self, parent) self.iface = iface self.parent = parent self.params = params self.output_reader = None self.tool = None self.element_ids_nodes = None self.element_ids_links = None self.nodes_lay = None self.links_lay = None self.setWindowTitle(Parameters.plug_in_name) # Selection changed listeners self.params.junctions_vlay.selectionChanged.connect(self.feature_sel_changed) self.params.reservoirs_vlay.selectionChanged.connect(self.feature_sel_changed) self.params.tanks_vlay.selectionChanged.connect(self.feature_sel_changed) self.params.pipes_vlay.selectionChanged.connect(self.feature_sel_changed) self.params.pumps_vlay.selectionChanged.connect(self.feature_sel_changed) self.params.valves_vlay.selectionChanged.connect(self.feature_sel_changed) # self.setMinimumWidth(min_width) # self.setMinimumHeight(min_height) fra_main_lay = QVBoxLayout(self) self.fra_out_file = QFrame(self) fra_out_file_lay = QHBoxLayout(self.fra_out_file) self.lbl_out_file = QLabel('Simulation output file:') self.txt_out_file = QLineEdit('') self.txt_out_file.setReadOnly(True) self.btn_out_file = QToolButton() self.btn_out_file.setText('...') self.btn_out_file.clicked.connect(self.btn_out_file_clicked) fra_out_file_lay.addWidget(self.lbl_out_file) fra_out_file_lay.addWidget(self.txt_out_file) fra_out_file_lay.addWidget(self.btn_out_file) self.tab_widget = QTabWidget(self) # Graphs tab --------------------------------------------------------------------------------------------------- self.tab_graphs = QWidget() tab_graphs_lay = QHBoxLayout(self.tab_graphs) # Left frame self.fra_graphs_left = QFrame() self.fra_graphs_left.setMaximumWidth(100) fra_graphs_left_lay = QVBoxLayout(self.fra_graphs_left) self.btn_sel_element = QPushButton('Pick') self.btn_sel_element.clicked.connect(self.btn_sel_element_clicked) fra_graphs_left_lay.addWidget(self.btn_sel_element) # Nodes self.grb_nodes = QGroupBox(u'Nodes') lay_grb_nodes = QVBoxLayout(self.grb_nodes) self.chk_node_demand = QCheckBox('Demand') lay_grb_nodes.addWidget(self.chk_node_demand) self.chk_node_head = QCheckBox('Head') lay_grb_nodes.addWidget(self.chk_node_head) self.chk_node_pressure = QCheckBox('Pressure') lay_grb_nodes.addWidget(self.chk_node_pressure) self.chk_node_quality = QCheckBox('Quality') lay_grb_nodes.addWidget(self.chk_node_quality) fra_graphs_left_lay.addWidget(self.grb_nodes) # Links self.grb_links = QGroupBox(u'Links') lay_grb_links = QVBoxLayout(self.grb_links) self.chk_link_flow = QCheckBox('Flow') lay_grb_links.addWidget(self.chk_link_flow) self.chk_link_velocity = QCheckBox('Velocity') lay_grb_links.addWidget(self.chk_link_velocity) self.chk_link_headloss = QCheckBox('Headloss') lay_grb_links.addWidget(self.chk_link_headloss) self.chk_link_quality = QCheckBox('Quality') lay_grb_links.addWidget(self.chk_link_quality) fra_graphs_left_lay.addWidget(self.grb_links) self.btn_draw_graph = QPushButton('Draw') self.btn_draw_graph.clicked.connect(self.draw_graphs) fra_graphs_left_lay.addWidget(self.btn_draw_graph) self.spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) fra_graphs_left_lay.addItem(self.spacer) tab_graphs_lay.addWidget(self.fra_graphs_left) # Right frame self.fra_graphs_right = QFrame() fra_graphs_right_lay = QVBoxLayout(self.fra_graphs_right) fra_graphs_right_lay.setContentsMargins(0, 0, 0, 0) self.static_canvas = StaticMplCanvas(self.fra_graphs_right, width=5, height=4, dpi=100) fra_graphs_right_lay.addWidget(self.static_canvas) tab_graphs_lay.addWidget(self.fra_graphs_right) # lay.addWidget(self.button) self.tab_widget.addTab(self.tab_graphs, 'Graphs') # Maps tab ----------------------------------------------------------------------------------------------------- self.tab_maps = QWidget() tab_maps_lay = QHBoxLayout(self.tab_maps) # Left frame self.fra_maps_left = QFrame() self.fra_maps_left.setMaximumWidth(200) fra_maps_left_lay = QVBoxLayout(self.fra_maps_left) self.grb_maps = QGroupBox(u'Variable') grb_maps_lay = QVBoxLayout(self.grb_maps) self.rad_maps_node_demand = QRadioButton(u'Node demand') grb_maps_lay.addWidget(self.rad_maps_node_demand) self.rad_maps_node_head = QRadioButton(u'Node head') grb_maps_lay.addWidget(self.rad_maps_node_head) self.rad_maps_node_pressure = QRadioButton(u'Node pressure') grb_maps_lay.addWidget(self.rad_maps_node_pressure) self.rad_maps_node_quality = QRadioButton(u'Node quality') grb_maps_lay.addWidget(self.rad_maps_node_quality) self.rad_maps_link_flow = QRadioButton(u'Link flow') grb_maps_lay.addWidget(self.rad_maps_link_flow) self.rad_maps_link_velocity = QRadioButton(u'Link velocity') grb_maps_lay.addWidget(self.rad_maps_link_velocity) self.rad_maps_link_headloss = QRadioButton(u'Link headloss') grb_maps_lay.addWidget(self.rad_maps_link_headloss) self.rad_maps_link_quality = QRadioButton(u'Link quality') grb_maps_lay.addWidget(self.rad_maps_link_quality) fra_maps_left_lay.addWidget(self.grb_maps) fra_maps_left_lay.addItem(self.spacer) tab_maps_lay.addWidget(self.fra_maps_left) # Right maps frame self.fra_maps_right = QFrame() fra_maps_right_lay = QVBoxLayout(self.fra_maps_right) self.fra_maps_right_time = QFrame() fra_maps_right_time_lay = QFormLayout(self.fra_maps_right_time) self.lbl_map_times = QLabel(u'Period [h]:') self.cbo_map_times = QComboBox() fra_maps_right_time_lay.addRow(self.lbl_map_times, self.cbo_map_times) fra_maps_right_lay.addWidget(self.fra_maps_right_time) self.btn_draw_map = QPushButton(u'Draw map') self.btn_draw_map.clicked.connect(self.draw_maps) fra_maps_right_lay.addWidget(self.btn_draw_map) fra_maps_right_lay.addItem(self.spacer) tab_maps_lay.addWidget(self.fra_maps_right) self.tab_widget.addTab(self.tab_maps, 'Maps') # # Add to main fra_main_lay.addWidget(self.fra_out_file) fra_main_lay.addWidget(self.tab_widget) self.setup() self.initialize() # self.read_outputs() # Set size self.setMinimumWidth(self.tab_graphs.width()) self.setMinimumHeight(self.tab_graphs.height()) def setup(self): pass def btn_out_file_clicked(self): config_file = ConfigFile(Parameters.config_file_path) out_file, __ = QFileDialog.getOpenFileName( self, 'Select out file', config_file.get_last_out_file(), 'Out files (*.out)') if out_file is None or out_file == '': return config_file.set_last_out_file(out_file) self.txt_out_file.setText(out_file) self.read_outputs() if self.output_reader is None: return # Fill times combo self.cbo_map_times.clear() for period_s in self.output_reader.period_results.keys(): text = self.seconds_to_string( period_s, self.output_reader.sim_duration_secs, self.output_reader.report_time_step_secs) self.cbo_map_times.addItem(text, period_s) # Activate widgets self.btn_sel_element.setEnabled(self.output_reader is not None) self.btn_draw_graph.setEnabled(self.output_reader is not None) self.grb_maps.setEnabled(self.output_reader is not None) self.btn_draw_map.setEnabled(self.output_reader is not None) def initialize(self): # Graphs self.grb_nodes.setEnabled(False) self.grb_links.setEnabled(False) self.btn_sel_element.setEnabled(self.output_reader is not None) self.btn_draw_graph.setEnabled(self.output_reader is not None) # Maps self.grb_maps.setEnabled(self.output_reader is not None) self.rad_maps_node_demand.setChecked(True) self.btn_draw_map.setEnabled(self.output_reader is not None) def feature_sel_changed(self): is_nodes = False sel_junctions = self.params.junctions_vlay.selectedFeatureCount() sel_reservoirs = self.params.reservoirs_vlay.selectedFeatureCount() sel_tanks = self.params.tanks_vlay.selectedFeatureCount() if sel_junctions > 0 or sel_reservoirs > 0 or sel_tanks > 0: is_nodes = True self.grb_nodes.setEnabled(is_nodes) is_links = False sel_pipes = self.params.pipes_vlay.selectedFeatureCount() sel_pumps = self.params.pumps_vlay.selectedFeatureCount() sel_valves = self.params.valves_vlay.selectedFeatureCount() if sel_pipes > 0 or sel_pumps > 0 or sel_valves > 0: is_links = True self.grb_links.setEnabled(is_links) def read_outputs(self): try: QApplication.setOverrideCursor(Qt.WaitCursor) self.output_reader = BinaryOutputReader() self.output_reader.read(self.txt_out_file.text()) QApplication.restoreOverrideCursor() # Check if output compatible with loaded project compatible = True out_nodes_nr = self.output_reader.nodes_nr out_tanks_reservs_nr = self.output_reader.tanks_reservs_nr out_juncts_nr = out_nodes_nr - out_tanks_reservs_nr out_links_nr = self.output_reader.links_nr out_pumps_nr = self.output_reader.pumps_nr out_valves_nr = self.output_reader.valves_nr out_pipes_nr = out_links_nr - out_pumps_nr - out_valves_nr if out_juncts_nr != self.params.junctions_vlay.featureCount(): compatible = False if out_tanks_reservs_nr != (self.params.reservoirs_vlay.featureCount() + self.params.tanks_vlay.featureCount()): compatible = False if out_pipes_nr != self.params.pipes_vlay.featureCount(): compatible = False if out_valves_nr != self.params.valves_vlay.featureCount(): compatible = False if out_pumps_nr != self.params.pumps_vlay.featureCount(): compatible = False if not compatible: message = 'The out file appears to incompatible with the actual project layers.' QMessageBox.warning( self, Parameters.plug_in_name, message, QMessageBox.Ok) self.output_reader = None self.txt_out_file.setText('') else: # Message after reading completed message = 'Out file loaded: ' + str(out_nodes_nr) + ' nodes, ' + str(out_links_nr) + ' links found.' # Clear refs to output layer self.params.out_lay_node_demand = None self.params.out_lay_node_head = None self.params.out_lay_node_pressure = None self.params.out_lay_node_quality = None self.params.out_lay_link_flow = None self.params.out_lay_link_velocity = None self.params.out_lay_link_headloss = None self.params.out_lay_link_quality = None QMessageBox.information( self, Parameters.plug_in_name, message, QMessageBox.Ok) finally: # self.iface.messageBar().pushWarning( # Parameters.plug_in_name, # 'Error while reading output file.') # TODO: softcode # self.output_reader = None # self.txt_out_file.setText('') QApplication.restoreOverrideCursor() def btn_sel_element_clicked(self): if self.output_reader is None: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Please select the simulation out file.', Qgis.Warning, 5) # TODO: softcode return self.tool = SelectTool(self, self.params) self.iface.mapCanvas().setMapTool(self.tool) cursor = QCursor() cursor.setShape(Qt.ArrowCursor) self.iface.mapCanvas().setCursor(cursor) def draw_graphs(self): # Get selected features self.element_ids_nodes = [] for junction_feat in self.params.junctions_vlay.selectedFeatures(): self.element_ids_nodes.append(junction_feat.attribute(Junction.field_name_eid)) for reservoir_feat in self.params.reservoirs_vlay.selectedFeatures(): self.element_ids_nodes.append(reservoir_feat.attribute(Reservoir.field_name_eid)) for tank_feat in self.params.tanks_vlay.selectedFeatures(): self.element_ids_nodes.append(tank_feat.attribute(Tank.field_name_eid)) self.element_ids_links = [] for pipe_feat in self.params.pipes_vlay.selectedFeatures(): self.element_ids_links.append(pipe_feat.attribute(Pipe.field_name_eid)) for pump_feat in self.params.pumps_vlay.selectedFeatures(): self.element_ids_links.append(pump_feat.attribute(Pump.field_name_eid)) for valve_feat in self.params.valves_vlay.selectedFeatures(): self.element_ids_links.append(valve_feat.attribute(Valve.field_name_eid)) # Build values dictionaries xs = self.output_reader.report_times ys_d_d = {} params_count = 0 # Nodes if self.grb_nodes.isEnabled(): if self.chk_node_demand.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_demands_d[element_id], self.params.options.flow_units] ys_d_d[OutputParamCodes.NODE_DEMAND] = ys_d if self.chk_node_head.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_heads_d[element_id], Options.units_diameter_tanks[self.params.options.units]] ys_d_d[OutputParamCodes.NODE_HEAD] = ys_d if self.chk_node_pressure.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_pressures_d[element_id], Options.units_pressure[self.params.options.units]] ys_d_d[OutputParamCodes.NODE_PRESSURE] = ys_d if self.chk_node_quality.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_nodes: ys_d[element_id] = [ self.output_reader.node_qualities_d[element_id], Quality.quality_units_text[self.params.options.quality.mass_units]] ys_d_d[OutputParamCodes.NODE_QUALITY] = ys_d # Links if self.grb_links.isEnabled(): if self.chk_link_flow.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_flows_d[element_id], self.params.options.flow_units] ys_d_d[OutputParamCodes.LINK_FLOW] = ys_d if self.chk_link_velocity.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_velocities_d[element_id], Options.units_velocity[self.params.options.units]] ys_d_d[OutputParamCodes.LINK_VELOCITY] = ys_d if self.chk_link_headloss.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_headlosses_d[element_id], Options.units_diameter_tanks[self.params.options.units]] ys_d_d[OutputParamCodes.LINK_HEADLOSS] = ys_d if self.chk_link_quality.isChecked(): params_count += 1 ys_d = {} for element_id in self.element_ids_links: ys_d[element_id] = [ self.output_reader.link_qualities_d[element_id], Quality.quality_units_text[self.params.options.quality.mass_units]] ys_d_d[OutputParamCodes.LINK_QUALITY] = ys_d if ys_d_d: self.static_canvas.draw_output_line(xs, ys_d_d, params_count) def draw_maps(self): """ Draws layers with all the attributes :return: """ report_time = self.cbo_map_times.itemText(self.cbo_map_times.currentIndex()) if self.rad_maps_node_demand.isChecked(): # ------------------------------------------------------------------- lay_name = u'Node demand' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_demand_id, lay_name, self.output_reader.node_demands_d, report_time) self.params.out_lay_node_demand_id = lay_id elif self.rad_maps_node_head.isChecked(): lay_name = u'Node head' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_head_id, lay_name, self.output_reader.node_heads_d, report_time) self.params.out_lay_node_head_id = lay_id elif self.rad_maps_node_pressure.isChecked(): lay_name = u'Node pressure' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_pressure_id, lay_name, self.output_reader.node_pressures_d, report_time) self.params.out_lay_node_pressure_id = lay_id elif self.rad_maps_node_quality.isChecked(): lay_name = u'Node quality' lay_id = self.draw_map(LayerType.NODE, self.params.out_lay_node_quality_id, lay_name, self.output_reader.node_qualities_d, report_time) self.params.out_lay_node_quality_id = lay_id elif self.rad_maps_link_flow.isChecked(): # ------------------------------------------------------------------- lay_name = u'Link flow' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_flow_id, lay_name, self.output_reader.link_flows_d, report_time) self.params.out_lay_link_flow_id = lay_id elif self.rad_maps_link_velocity.isChecked(): lay_name = u'Link velocity' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_velocity_id, lay_name, self.output_reader.link_velocities_d, report_time) self.params.out_lay_link_velocity_id = lay_id elif self.rad_maps_link_headloss.isChecked(): lay_name = u'Link headloss' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_headloss_id, lay_name, self.output_reader.link_headlosses_d, report_time) self.params.out_lay_link_headloss_id = lay_id elif self.rad_maps_link_quality.isChecked(): lay_name = u'Link quality' lay_id = self.draw_map(LayerType.LINK, self.params.out_lay_link_quality_id, lay_name, self.output_reader.link_qualities_d, report_time) self.params.out_lay_link_quality_id = lay_id def draw_map(self, lay_type, lay_id, lay_name, dataset, report_time): try: QApplication.setOverrideCursor(Qt.WaitCursor) lay_name += ' ' + report_time lay = LayerUtils.get_lay_from_id(lay_id) if lay is None: if lay_type == LayerType.NODE: lay = self.create_out_node_layer(lay_name, dataset) ns = NodeSymbology() lay.setRenderer(ns.make_graduated_sym_renderer(lay, report_time)) elif lay_type == LayerType.LINK: lay = self.create_out_link_layer(lay_name, dataset) ls = LinkSymbology() lay.setRenderer(ls.make_flow_sym_renderer(lay, report_time)) lay_id = lay.id() QgsProject.instance().addMapLayer(lay) self.params.out_layers.append(lay) else: lay.setLayerName(lay_name) lay.triggerRepaint() QApplication.restoreOverrideCursor() finally: QApplication.restoreOverrideCursor() return lay_id def btn_cancel_clicked(self): self.setVisible(False) def btn_ok_clicked(self): pass def create_out_node_layer(self, lay_name, values_d): return self.create_out_layer(lay_name, values_d, LayerType.NODE) def create_out_link_layer(self, lay_name, values_d): return self.create_out_layer(lay_name, values_d, LayerType.LINK) def create_out_layer(self, lay_name, values_d, lay_type): field_name_vars = [] periods = list(self.output_reader.period_results.keys()) for period_s in periods: text = self.seconds_to_string( period_s, self.output_reader.sim_duration_secs, self.output_reader.report_time_step_secs) field_name_vars.append(text) if lay_type == LayerType.NODE: new_lay = MemoryDS.create_nodes_lay(self.params, field_name_vars, lay_name, self.params.crs) elif lay_type == LayerType.LINK: new_lay = MemoryDS.create_links_lay(self.params, field_name_vars, lay_name, self.params.crs) with edit(new_lay): # Update attributes for feat in new_lay.getFeatures(): fid = feat.id() eid = feat.attribute(Node.field_name_eid) values = values_d[eid] for p in range(len(periods)): new_lay.changeAttributeValue(fid, p+1, values[p]) return new_lay def seconds_to_string(self, period_s, duration_s, interval_s): day = int(math.floor(period_s / 86400)) hour = period_s / 3600 - day * 24 minute = period_s / 60 - day * 24 * 60 - hour * 60 second = period_s - day * 86400 - hour * 3600 - minute * 60 text = '' if duration_s >= 86400: # We need days text += str(day) + 'd' if duration_s >= 3600: # We need hours text += '{:02}'.format(hour) + 'H' text += '{:02}'.format(minute) + 'm' if second > 0: text += '{:02}'.format(second) + 's' return text
class DbSchemaDbPanel(DbConfigPanel): def __init__(self, db_connector): super(DbSchemaDbPanel, self).__init__() self.db_connector = db_connector self.selected_db_combobox = QComboBox() self.selected_schema_combobox = QComboBox() self.create_db_button = QPushButton() self.create_db_button.clicked.connect(self.show_create_db_dialog) icon_create_db_button = QIcon( ":/Asistente-LADM_COL/resources/images/create_db.png") self.create_db_button.setIcon(icon_create_db_button) self.create_schema_button = QPushButton() self.create_schema_button.clicked.connect( self.show_create_schema_dialog) icon_create_schema_button = QIcon( ":/Asistente-LADM_COL/resources/images/schema.png") self.create_schema_button.setIcon(icon_create_schema_button) self.refresh_db_button = QPushButton() self.refresh_db_button.setText( QCoreApplication.translate("SettingsDialog", "Refresh databases and schemas")) self.refresh_db_button.clicked.connect(self._refresh_db_button_clicked) self._set_controls_enabled(False) def _connect_change_signals(self): self.selected_db_combobox.currentIndexChanged.connect( self.selected_database_changed) def _set_controls_enabled(self, value): self.selected_db_combobox.setEnabled(value) self.selected_schema_combobox.setEnabled(value) self.create_db_button.setEnabled(value) self.create_schema_button.setEnabled(value) def _refresh_db_button_clicked(self): self._disconnect_change_signals() old_db_selected = self.selected_db_combobox.currentText().strip() old_schema_selected = self.selected_schema_combobox.currentText( ).strip() if self.update_db_names(): old_db_index = self.selected_db_combobox.findText( old_db_selected, Qt.MatchFixedString) if old_db_index >= 0: self.selected_db_combobox.setCurrentIndex(old_db_index) self.update_db_schemas() old_schema_index = self.selected_schema_combobox.findText( old_schema_selected, Qt.MatchFixedString) if old_schema_index >= 0: self.selected_schema_combobox.setCurrentIndex(old_schema_index) self._set_controls_enabled(True) else: self.selected_schema_combobox.clear() self._set_controls_enabled(False) self._connect_change_signals() def _disconnect_change_signals(self): try: self.selected_db_combobox.currentIndexChanged.disconnect( self.selected_database_changed) except TypeError: pass def update_db_names(self): result = False dict_conn = self.read_connection_parameters() tmp_db_conn = self.db_connector uri = tmp_db_conn.get_connection_uri(dict_conn, level=0) res, data = tmp_db_conn.get_dbnames_list(uri) self.selected_db_combobox.clear() if res: self.selected_db_combobox.addItems(data) result = True else: self.notify_message_requested.emit( QCoreApplication.translate("SettingsDialog", data), Qgis.Warning) return result def selected_database_changed(self, index): self.update_db_schemas() def update_db_schemas(self): dict_conn = self.read_connection_parameters() tmp_db_conn = self.db_connector if tmp_db_conn: uri = tmp_db_conn.get_connection_uri(dict_conn) res, data = tmp_db_conn.get_dbname_schema_list(uri) self.selected_schema_combobox.clear() if res: self.selected_schema_combobox.addItems(data) else: # We won't show a message here to avoid bothering the user with potentially too much messages pass def database_created(self, db_name): self.update_db_names() # select the database created by the user index = self.selected_db_combobox.findText(db_name, Qt.MatchFixedString) if index >= 0: self.selected_db_combobox.setCurrentIndex(index) def schema_created(self, schema_name): self.update_db_schemas() # select the schema created by the user index = self.selected_schema_combobox.findText(schema_name, Qt.MatchFixedString) if index >= 0: self.selected_schema_combobox.setCurrentIndex(index) def show_create_db_dialog(self): tmp_db_conn = self.db_connector dict_conn = self.read_connection_parameters() tmp_db_conn.dict_conn_params = dict_conn res, msg = tmp_db_conn.test_connection(test_level=EnumTestLevel.SERVER) if res: create_db_dlg = DialogGetDBOrSchemaName(tmp_db_conn, tmp_db_conn.uri, 'database', parent=self) create_db_dlg.db_or_schema_created.connect(self.database_created) create_db_dlg.setModal(True) create_db_dlg.exec_() else: msg = QCoreApplication.translate( "SettingsDialog", "First set the connection to the database before attempting to create a database." ) self.notify_message_requested.emit(msg, Qgis.Warning) def show_create_schema_dialog(self): tmp_db_conn = self.db_connector dict_conn = self.read_connection_parameters() tmp_db_conn.dict_conn_params = dict_conn res, msg = tmp_db_conn.test_connection(test_level=EnumTestLevel.DB) if res: create_db_dlg = DialogGetDBOrSchemaName(tmp_db_conn, tmp_db_conn.uri, 'schema', parent=self) create_db_dlg.db_or_schema_created.connect(self.schema_created) create_db_dlg.setModal(True) create_db_dlg.exec_() else: msg = QCoreApplication.translate( "SettingsDialog", "First set the connection to the database before attempting to create a schema." ) self.notify_message_requested.emit(msg, Qgis.Warning)
class FixedTableDialog(BASE, WIDGET): def __init__(self, param, table): super(FixedTableDialog, self).__init__(None) self.setupUi(self) self.tblView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tblView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.param = param self.rettable = None # Additional buttons self.btnAdd = QPushButton(self.tr('Add row')) self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ActionRole) self.btnRemove = QPushButton(self.tr('Remove row(s)')) self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ActionRole) self.btnRemoveAll = QPushButton(self.tr('Remove all')) self.buttonBox.addButton(self.btnRemoveAll, QDialogButtonBox.ActionRole) self.btnAdd.clicked.connect(self.addRow) self.btnRemove.clicked.connect(lambda: self.removeRows()) self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True)) if self.param.fixedNumOfRows: self.btnAdd.setEnabled(False) self.btnRemove.setEnabled(False) self.btnRemoveAll.setEnabled(False) self.populateTable(table) def populateTable(self, table): cols = len(self.param.cols) rows = len(table) model = QStandardItemModel(rows, cols) # Set headers model.setHorizontalHeaderLabels(self.param.cols) # Populate table for i in range(rows): for j in range(cols): item = QStandardItem(table[i][j]) model.setItem(i, j, item) self.tblView.setModel(model) def accept(self): cols = self.tblView.model().columnCount() rows = self.tblView.model().rowCount() self.rettable = [] for i in range(rows): self.rettable.append(list()) for j in range(cols): self.rettable[i].append(str(self.tblView.model().item(i, j).text())) QDialog.accept(self) def reject(self): QDialog.reject(self) def removeRows(self, removeAll=False): if removeAll: self.tblView.model().clear() self.tblView.model().setHorizontalHeaderLabels(self.param.cols) else: indexes = sorted(self.tblView.selectionModel().selectedRows()) self.tblView.setUpdatesEnabled(False) for i in reversed(indexes): self.tblView.model().removeRows(i.row(), 1) self.tblView.setUpdatesEnabled(True) def addRow(self): items = [QStandardItem('0') for i in range(self.tblView.model().columnCount())] self.tblView.model().appendRow(items)
class RemotesDialog(QDialog): def __init__(self, parent, repo): QDialog.__init__(self, parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint) self.changed = False self.repo = repo self.remotes = repo.remotes() self.setupUi() def setupUi(self): self.resize(500, 350) self.setWindowTitle("Remote connections manager") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Vertical) self.buttonBox.setStandardButtons(QDialogButtonBox.Close) self.table = QTableWidget() self.table.verticalHeader().setVisible(False) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.addRowButton = QPushButton() self.addRowButton.setText("Add connection") self.editRowButton = QPushButton() self.editRowButton.setText("Edit connection") self.removeRowButton = QPushButton() self.removeRowButton.setText("Remove connection") self.buttonBox.addButton(self.addRowButton, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.editRowButton, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.removeRowButton, QDialogButtonBox.ActionRole) self.setTableContent() self.horizontalLayout.addWidget(self.table) self.horizontalLayout.addWidget(self.buttonBox) self.setLayout(self.horizontalLayout) self.buttonBox.rejected.connect(self.close) self.editRowButton.clicked.connect(self.editRow) self.addRowButton.clicked.connect(self.addRow) self.removeRowButton.clicked.connect(self.removeRow) QMetaObject.connectSlotsByName(self) self.editRowButton.setEnabled(False) self.removeRowButton.setEnabled(False) def setTableContent(self): self.table.clear() self.table.setColumnCount(2) self.table.setColumnWidth(0, 200) self.table.setColumnWidth(1, 200) self.table.setHorizontalHeaderLabels(["Name", "URL"]) self.table.horizontalHeader().setResizeMode(QHeaderView.Stretch) self.table.setRowCount(len(self.remotes)) for i, name in enumerate(self.remotes): url = self.remotes[name] self.table.setRowHeight(i, 22) item = QTableWidgetItem(name, 0) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self.table.setItem(i, 0, item) item = QTableWidgetItem(url, 0) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) self.table.setItem(i, 1, item) self.table.itemSelectionChanged.connect(self.selectionChanged) def selectionChanged(self): enabled = len(self.table.selectedItems()) > 0 self.editRowButton.setEnabled(enabled) self.removeRowButton.setEnabled(enabled) def editRow(self): item = self.table.item(self.table.currentRow(), 0) if item is not None: name = item.text() url = self.table.item(self.table.currentRow(), 1).text() dlg = NewRemoteDialog(name, url, self) dlg.exec_() if dlg.ok: self.repo.removeremote(name) self.repo.addremote(dlg.name, dlg.url) del self.remotes[name] self.remotes[dlg.name] = dlg.url self.setTableContent() self.changed = True def removeRow(self): item = self.table.item(self.table.currentRow(), 0) if item is not None: name = item.text() self.repo.removeremote(name) del self.remotes[name] self.setTableContent() self.changed = True def addRow(self): dlg = NewRemoteDialog(parent = self) dlg.exec_() if dlg.ok: try: self.repo.addremote(dlg.name, dlg.url) self.remotes[dlg.name] = dlg.url self.setTableContent() self.changed = True except HTTPError: QMessageBox.warning(self, 'Cannot add remote connection', "Remote connection could not be added.\n" "Ensure that the entered data is correct and the geogig server is running.", QMessageBox.Ok)
class ImportDialog(QDialog): def __init__(self, parent, repo = None, layer = None): super(ImportDialog, self).__init__(parent) self.repo = repo self.layer = layer self.ok = False self.initGui() def initGui(self): self.setWindowTitle('Add layer to GeoGig repository') verticalLayout = QVBoxLayout() if self.repo is None: repos = repository.repos layerLabel = QLabel('Repository') verticalLayout.addWidget(layerLabel) self.repoCombo = QComboBox() self.repoCombo.addItems(["%s - %s" % (r.group, r.title) for r in repos]) self.repoCombo.currentIndexChanged.connect(self.updateBranches) verticalLayout.addWidget(self.repoCombo) if self.layer is None: layerLabel = QLabel('Layer') verticalLayout.addWidget(layerLabel) self.layerCombo = QComboBox() layerNames = [layer.name() for layer in getVectorLayers() if layer.source().lower().split("|")[0].split(".")[-1] in["gpkg", "geopkg"] and not isRepoLayer(layer)] self.layerCombo.addItems(layerNames) verticalLayout.addWidget(self.layerCombo) self.branchLabel = QLabel("Branch") verticalLayout.addWidget(self.branchLabel) self.branchCombo = QComboBox() self.branches = self.repo.branches() if self.repo is not None else repos[0].branches() self.branchCombo.addItems(self.branches) verticalLayout.addWidget(self.branchCombo) messageLabel = QLabel('Message to describe this update') verticalLayout.addWidget(messageLabel) self.messageBox = QPlainTextEdit() self.messageBox.textChanged.connect(self.messageHasChanged) verticalLayout.addWidget(self.messageBox) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel) self.importButton = QPushButton("Add layer") self.importButton.clicked.connect(self.importClicked) self.importButton.setEnabled(False) self.buttonBox.addButton(self.importButton, QDialogButtonBox.ApplyRole) self.buttonBox.rejected.connect(self.cancelPressed) verticalLayout.addWidget(self.buttonBox) self.setLayout(verticalLayout) self.resize(600, 300) self.messageBox.setFocus() def updateBranches(self): self.branchCombo.clear() repo = repository.repos[self.repoCombo.currentIndex()] self.branches = repo.branches() self.branchCombo.addItems(self.branches) def messageHasChanged(self): self.importButton.setEnabled(self.messageBox.toPlainText() != "") def importClicked(self): if self.repo is None: self.repo = repository.repos[self.repoCombo.currentIndex()] if self.layer is None: text = self.layerCombo.currentText() self.layer = resolveLayer(text) user, email = config.getUserInfo() if user is None: self.close() return message = self.messageBox.toPlainText() branch = self.branchCombo.currentText() try: self.repo.importgeopkg(self.layer, branch, message, user, email, False) filename, layername = namesFromLayer(self.layer) self.repo.checkoutlayer(filename, layername, ref = branch) self.layer.reload() self.layer.triggerRepaint() except GeoGigException as e: iface.messageBar().pushMessage("Error", str(e), level=QgsMessageBar.CRITICAL, duration=5) self.close() return addTrackedLayer(self.layer, self.repo.url) self.ok = True iface.messageBar().pushMessage("Layer was correctly added to repository", level=QgsMessageBar.INFO, duration=5) self.close() def cancelPressed(self): self.close()
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
class HydraulicsDialog(QDialog): def __init__(self, parent, params, new_proj=False): QDialog.__init__(self, parent) self.parent = parent self.params = params self.new_proj = new_proj self.setMinimumWidth(min_width) # self.setMinimumHeight(min_height) # Build dialog self.setWindowTitle('Options - Hydraulics') # TODO: softcode self.setWindowModality(QtCore.Qt.ApplicationModal) self.fra_form = QFrame(self) fra_form_lay = QFormLayout(self.fra_form) fra_form_lay.setContentsMargins(10, 10, 10, 10) self.lbl_units = QLabel('Units system:') # TODO: softocode self.cbo_units = QComboBox() fra_form_lay.addRow(self.lbl_units, self.cbo_units) self.lbl_flow_units = QLabel('Flow units:') # TODO: softocode self.cbo_flow_units = QComboBox() fra_form_lay.addRow(self.lbl_flow_units, self.cbo_flow_units) self.lbl_headloss = QLabel('Head loss:') # TODO: softocode self.cbo_headloss = QComboBox() fra_form_lay.addRow(self.lbl_headloss, self.cbo_headloss) self.chk_hydraulics = QCheckBox('Hydraulics:') # TODO: softcode self.cbo_hydraulics = QComboBox() fra_form_lay.addRow(self.chk_hydraulics, self.cbo_hydraulics) self.txt_hydraulics_file = QLineEdit() fra_form_lay.addRow(None, self.txt_hydraulics_file) self.btn_hydraulics_file = QPushButton('File...') # TODO: softcode fra_form_lay.addRow(None, self.btn_hydraulics_file) self.lbl_viscosity = QLabel('Viscosity:') # TODO: softocode self.txt_viscosity = QLineEdit() fra_form_lay.addRow(self.lbl_viscosity, self.txt_viscosity) # self.lbl_diffusivity = QLabel('Diffusivity:') # TODO: softocode # self.txt_diffusivity = QLineEdit() # fra_form_lay.addRow(self.lbl_diffusivity, self.txt_diffusivity) self.lbl_spec_gravity = QLabel('Specific gravity:') # TODO: softocode self.txt_spec_gravity = QLineEdit() fra_form_lay.addRow(self.lbl_spec_gravity, self.txt_spec_gravity) self.lbl_max_trials = QLabel('Max trials:') # TODO: softocode self.txt_max_trials = QLineEdit() fra_form_lay.addRow(self.lbl_max_trials, self.txt_max_trials) self.lbl_accuracy = QLabel('Accuracy:') # TODO: softocode self.txt_accuracy = QLineEdit() fra_form_lay.addRow(self.lbl_accuracy, self.txt_accuracy) self.lbl_unbalanced = QLabel('Unbalanced:') # TODO: softcode self.fra_unbalanced = QFrame(self) fra_unbalanced_lay = QHBoxLayout(self.fra_unbalanced) fra_unbalanced_lay.setContentsMargins(0, 0, 0, 0) self.cbo_unbalanced = QComboBox() self.txt_unbalanced = QLineEdit() fra_unbalanced_lay.addWidget(self.cbo_unbalanced) fra_unbalanced_lay.addWidget(self.txt_unbalanced) fra_form_lay.addRow(self.lbl_unbalanced, self.fra_unbalanced) self.lbl_pattern = QLabel('Pattern:') # TODO: softocode self.cbo_pattern = QComboBox() fra_form_lay.addRow(self.lbl_pattern, self.cbo_pattern) self.lbl_demand_mult = QLabel('Demand multiplier:') # TODO: softocode self.txt_demand_mult = QLineEdit() fra_form_lay.addRow(self.lbl_demand_mult, self.txt_demand_mult) self.lbl_emitter_exp = QLabel('Emitter exponent:') # TODO: softocode self.txt_emitter_exp = QLineEdit() fra_form_lay.addRow(self.lbl_emitter_exp, self.txt_emitter_exp) self.lbl_tolerance = QLabel('Tolerance:') # TODO: softocode self.txt_tolerance = QLineEdit() fra_form_lay.addRow(self.lbl_tolerance, self.txt_tolerance) # Buttons self.fra_buttons = QFrame(self) fra_buttons_lay = QHBoxLayout(self.fra_buttons) self.btn_Cancel = QPushButton('Cancel') self.btn_Ok = QPushButton('OK') fra_buttons_lay.addWidget(self.btn_Ok) fra_buttons_lay.addWidget(self.btn_Cancel) # Add to main fra_main_lay = QVBoxLayout(self) fra_main_lay.setContentsMargins(0, 0, 0, 0) fra_main_lay.addWidget(self.fra_form) fra_main_lay.addWidget(self.fra_buttons) self.setup() def setup(self): # Fill units system combo box for unit in self.params.options.units_sys: self.cbo_units.addItem(self.params.options.units_sys_text[unit], unit) # Fill flow units combo box for fu in Options.units_flow[self.params.options.units]: self.cbo_flow_units.addItem(Options.units_flow_text[fu], fu) self.cbo_units.activated.connect(self.cbo_units_activated) # self.cbo_flow_units.activated.connect(self.cbo_flow_units_activated) for key, value in self.params.options.headlosses_text.items(): self.cbo_headloss.addItem(value, key) self.cbo_headloss.activated.connect(self.cbo_headloss_activated) self.chk_hydraulics.stateChanged.connect(self.chk_hydraulics_changed) self.btn_hydraulics_file.clicked.connect(self.btn_hydraulics_clicked) self.cbo_hydraulics.addItem( self.params.options.hydraulics.action_names[self.params.options.hydraulics.action_use], self.params.options.hydraulics.action_use) self.cbo_hydraulics.addItem( self.params.options.hydraulics.action_names[self.params.options.hydraulics.action_save], self.params.options.hydraulics.action_save) self.txt_hydraulics_file.setReadOnly(True) # - Unbalanced for id, text in self.params.options.unbalanced.unb_text.items(): self.cbo_unbalanced.addItem(text, id) self.cbo_unbalanced.activated.connect(self.cbo_unbalanced_changed) self.txt_unbalanced.setValidator(RegExValidators.get_pos_int_no_zero()) self.txt_unbalanced.setText('1') # - Pattern self.cbo_pattern.addItem('None (=1.0)', None) for pattern_id, pattern in self.params.patterns.items(): self.cbo_pattern.addItem(pattern_id, pattern) # Buttons self.btn_Cancel.clicked.connect(self.btn_cancel_clicked) self.btn_Ok.clicked.connect(self.btn_ok_clicked) # Validators self.txt_viscosity.setValidator(RegExValidators.get_pos_decimals()) self.txt_spec_gravity.setValidator(RegExValidators.get_pos_decimals()) self.txt_max_trials.setValidator(RegExValidators.get_pos_int_no_zero()) self.txt_accuracy.setValidator(RegExValidators.get_pos_decimals()) self.txt_demand_mult.setValidator(RegExValidators.get_pos_decimals()) self.txt_emitter_exp.setValidator(RegExValidators.get_pos_decimals()) self.txt_tolerance.setValidator(RegExValidators.get_pos_decimals()) def show(self): super(HydraulicsDialog, self).show() self.cbo_units.setCurrentIndex(self.cbo_units.findData(self.params.options.units)) self.cbo_flow_units.setCurrentIndex(self.cbo_flow_units.findData(self.params.options.flow_units)) self.cbo_headloss.setCurrentIndex(self.cbo_headloss.findData(self.params.options.headloss)) self.chk_hydraulics.setChecked(self.params.options.hydraulics.use_hydraulics) self.btn_hydraulics_file.setEnabled(self.chk_hydraulics.isChecked()) self.cbo_hydraulics.setEnabled(self.chk_hydraulics.isChecked()) self.txt_hydraulics_file.setEnabled(self.chk_hydraulics.isChecked()) if self.params.options.hydraulics.action is not None: self.cbo_hydraulics.setCurrentIndex(self.cbo_hydraulics.findData(self.params.options.hydraulics.action)) if self.params.options.hydraulics.file is not None: self.txt_hydraulics_file.setText(self.params.options.hydraulics.file) self.txt_viscosity.setText(str(self.params.options.viscosity)) self.txt_spec_gravity.setText(str(self.params.options.spec_gravity)) self.txt_max_trials.setText(str(self.params.options.trials)) self.txt_accuracy.setText(str(self.params.options.accuracy)) self.cbo_unbalanced.setCurrentIndex(self.cbo_unbalanced.findData(self.params.options.unbalanced.unbalanced)) self.txt_unbalanced.setEnabled(self.cbo_unbalanced.currentIndex() != 0) self.txt_unbalanced.setText(str(self.params.options.unbalanced.trials)) # Patterns if self.params.options.pattern is not None: if self.params.options.pattern is None: self.cbo_pattern.setCurrentIndex(0) else: for i in range(self.cbo_pattern.count()): if self.params.options.pattern.id == self.cbo_pattern.itemText(i): self.cbo_pattern.setCurrentIndex(i) break self.txt_demand_mult.setText(str(self.params.options.demand_mult)) self.txt_emitter_exp.setText(str(self.params.options.emitter_exp)) self.txt_tolerance.setText(str(self.params.options.tolerance)) def cbo_units_activated(self): self.params.options.units = self.cbo_units.itemData(self.cbo_units.currentIndex()) # Parameters combo box self.cbo_flow_units.clear() for fu in Options.units_flow[self.params.options.units]: self.cbo_flow_units.addItem(Options.units_flow_text[fu], fu) def cbo_headloss_activated(self): # Warning if not self.new_proj: QMessageBox.warning( self, Parameters.plug_in_name, u'Head loss units changed: the head loss values already present might need to be reviewed.', QMessageBox.Ok) def chk_hydraulics_changed(self): self.btn_hydraulics_file.setEnabled(self.chk_hydraulics.isChecked()) self.cbo_hydraulics.setEnabled(self.chk_hydraulics.isChecked()) self.txt_hydraulics_file.setEnabled(self.chk_hydraulics.isChecked()) def btn_hydraulics_clicked(self): file_dialog = QFileDialog(self, 'Select hydraulics file') file_dialog.setLabelText(QFileDialog.Accept, 'Select') file_dialog.setLabelText(QFileDialog.Reject, 'Cancel') file_dialog.setFileMode(QFileDialog.AnyFile) file_dialog.exec_() hydraulics_file_path = file_dialog.selectedFiles() if not hydraulics_file_path or hydraulics_file_path[0] is None or hydraulics_file_path[0] == '': return self.txt_hydraulics_file.setText(hydraulics_file_path[0]) def cbo_unbalanced_changed(self): self.txt_unbalanced.setEnabled( self.cbo_unbalanced.itemData( self.cbo_unbalanced.currentIndex()) == self.params.options.unbalanced.unb_continue) def btn_cancel_clicked(self): self.setVisible(False) def btn_ok_clicked(self): if not self.check_params(): return # Update parameters and options self.params.options.units = self.cbo_units.itemData(self.cbo_units.currentIndex()) self.params.options.flow_units = self.cbo_flow_units.itemData(self.cbo_flow_units.currentIndex()) self.params.options.headloss = self.cbo_headloss.itemData(self.cbo_headloss.currentIndex()) self.params.options.hydraulics.use_hydraulics = self.chk_hydraulics.isChecked() if self.params.options.hydraulics.action is not None: self.params.options.hydraulics.action = self.cbo_hydraulics.itemData(self.cbo_hydraulics.currentIndex()) self.params.options.hydraulics.file = self.txt_hydraulics_file.text() self.params.options.viscosity = float(self.txt_viscosity.text()) # self.params.options.diffusivity = float(self.txt_diffusivity.text()) self.params.options.spec_gravity = float(self.txt_spec_gravity.text()) self.params.options.trials = float(self.txt_max_trials.text()) self.params.options.accuracy = float(self.txt_accuracy.text()) self.params.options.unbalanced.unbalanced = self.cbo_unbalanced.itemData(self.cbo_unbalanced.currentIndex()) self.params.options.unbalanced.trials = int(self.txt_unbalanced.text()) self.params.options.pattern = self.cbo_pattern.itemData(self.cbo_pattern.currentIndex()) self.params.options.demand_mult = float(self.txt_demand_mult.text()) self.params.options.emitter_exp = float(self.txt_emitter_exp.text()) self.params.options.tolerance = float(self.txt_tolerance.text()) # Junctions self.parent.lbl_junction_demand.setText(pre_l('Demand', Options.units_flow[self.params.options.units][0])) # TODO: softcode self.parent.lbl_junction_deltaz.setText(pre_l('Delta Z', Options.units_deltaz[self.params.options.units])) # TODO: softcode # Reservoirs self.parent.lbl_reservoir_deltaz.setText( pre_l('Delta Z', Options.units_deltaz[self.params.options.units])) # TODO: softcode self.parent.lbl_reservoir_pressure_head.setText( pre_l('Pressure head', Options.units_deltaz[self.params.options.units])) # TODO: softcode # Tanks self.parent.lbl_tank_deltaz.setText(pre_l('Delta Z', Options.units_deltaz[self.params.options.units])) # TODO: softcode self.parent.lbl_tank_level_init.setText(pre_l('Level init.', Options.units_deltaz[self.params.options.units])) # TODO: softcode self.parent.lbl_tank_level_min.setText(pre_l('Level min', Options.units_deltaz[self.params.options.units])) # TODO: softcode self.parent.lbl_tank_level_max.setText(pre_l('Level max', Options.units_deltaz[self.params.options.units])) # TODO: softcode self.parent.lbl_tank_diameter.setText(pre_l('Diameter', Options.units_diameter_tanks[self.params.options.units])) # TODO: softcode self.parent.lbl_tank_vol_min.setText(pre_l('Volume min', Options.units_volume[self.params.options.units])) # TODO: softcode # Pipes self.parent.lbl_pipe_demand.setText(pre_l('Demand', Options.units_flow[self.params.options.units][0])) # TODO: softcode self.parent.lbl_pipe_diameter.setText(pre_l('Diameter', Options.units_diameter_pipes[self.params.options.units])) # TODO: softcode self.parent.lbl_pipe_roughness_val.setText(pre_l('Value', Options.units_roughness[self.params.options.units][self.params.options.headloss])) # TODO: softcode self.params.options.headloss_units = self.cbo_headloss.itemData(self.cbo_headloss.currentIndex()) self.parent.update_roughness_params( self.parent.cbo_pipe_roughness.itemData(self.parent.cbo_pipe_roughness.currentIndex())[self.params.options.headloss]) # self.parent.lbl_pipe_roughness.setText( # pre_l( # 'Roughness', # self.params.options.units_roughness[self.params.options.units][self.params.options.headloss_units])) # Pumps self.parent.lbl_pump_head.setText(pre_l('Head', self.params.options.units_deltaz[self.params.options.units])) self.parent.lbl_pump_power.setText(pre_l('Power', self.params.options.units_power[self.params.options.units])) # Valves valve_type = self.parent.cbo_valve_type.itemData(self.parent.cbo_valve_type.currentIndex()) # Pressure valves if valve_type == Valve.type_psv or valve_type == Valve.type_prv or valve_type == Valve.type_pbv: self.parent.lbl_valve_setting.setText( pre_l('Pressure', self.params.options.units_pressure[self.params.options.units])) # FCV valve: Flow if valve_type == Valve.type_fcv: self.parent.lbl_valve_setting.setText( pre_l('Flow', self.params.options.flow_units)) # Throttle control valve elif valve_type == Valve.type_tcv: self.parent.lbl_valve_setting.setText( pre_l('Loss coeff.', '-')) # self.parent.lbl_valve_diameter.setText(pre_l('Pressure', self.params.options.units_diameter_pipes[self.params.options.units])) # Flow units units = self.cbo_flow_units.itemData(self.cbo_flow_units.currentIndex()) self.parent.lbl_junction_demand.setText(pre_l('Demand', units)) # TODO: softcode self.parent.lbl_pipe_demand.setText(pre_l('Demand', units)) # TODO: softcode self.setVisible(False) def check_params(self): if self.chk_hydraulics.isChecked(): if not os.path.isfile(self.txt_hydraulics_file.text()): QMessageBox.warning( self, Parameters.plug_in_name, u'Hydraulics option slected, but no valid file specified.', QMessageBox.Ok) return False return True