class StepKwInaSAFERasterDefaultValues(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Raster Default Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.extra_parameters = [(DefaultValueParameter, DefaultValueParameterWidget)] self.parameters = [] self.parameter_container = ParameterContainer( extra_parameters=self.extra_parameters) self.default_values_grid.addWidget(self.parameter_container) def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ new_step = self.parent.step_kw_source return new_step def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose( )['key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = True inasafe_fields = get_fields(layer_purpose_key, subcategory_key, replace_null=True, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove( get_compulsory_fields(layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" existing_inasafe_default_values = self.parent.get_existing_keyword( 'inasafe_default_values') # Remove old container and parameter if self.parameter_container: self.default_values_grid.removeWidget(self.parameter_container) if self.parameters: self.parameters = [] # Iterate through all inasafe fields # existing_inasafe_default_values for inasafe_field in self.inasafe_fields_for_the_layer(): # Create DefaultSelectParameter parameter = DefaultValueParameter() parameter.guid = inasafe_field['key'] parameter.name = inasafe_field['name'] parameter.is_required = False parameter.help_text = inasafe_field['default_value']['description'] # parameter.description = inasafe_field['default_value'] parameter.element_type = unicode parameter.labels = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[0] parameter.options = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[1] if existing_inasafe_default_values: existing_default_value = existing_inasafe_default_values.get( inasafe_field['key']) if existing_default_value: parameter.default = existing_default_value self.parameters.append(parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer( self.parameters, extra_parameters=self.extra_parameters) self.parameter_container.setup_ui() self.default_values_grid.addWidget(self.parameter_container) # Set default value to None for parameter_widget in self.parameter_container.\ get_parameter_widgets(): parameter_widget.widget().set_value(None) # Set default value from existing keywords if existing_inasafe_default_values: for guid, default in existing_inasafe_default_values.items(): parameter_widget = self.parameter_container.\ get_parameter_widget_by_guid(guid) if isinstance(parameter_widget, DefaultValueParameterWidget): parameter_widget.set_value(default) def get_inasafe_default_values(self): """Return inasafe default from the current wizard state. :returns: Dictionary of key and value from InaSAFE Default Values. :rtype: dict """ inasafe_default_values = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if parameter.value is not None: inasafe_default_values[parameter.guid] = parameter.value return inasafe_default_values def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(range(self.default_values_grid.count())): self.default_values_grid.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to ' 'set a value that corresponded with a InaSAFE field ' 'concept as default value.').format( step_name=self.step_name))) return message
class StepKwDefaultInaSAFEFields(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Default Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.extra_parameters = [(DefaultSelectParameter, DefaultSelectParameterWidget)] self.parameters = [] self.parameter_container = ParameterContainer( extra_parameters=self.extra_parameters) self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) self.message_label = QLabel() def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ new_step = self.parent.step_kw_source return new_step def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ if (self.parent.get_layer_geometry_key() == layer_geometry_raster['key']): return [] # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose( )['key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = True inasafe_fields = get_fields(layer_purpose_key, subcategory_key, replace_null=True, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove( get_compulsory_fields(layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" self.clear() existing_inasafe_field = self.parent.get_existing_keyword( 'inasafe_fields') existing_inasafe_default_values = self.parent.get_existing_keyword( 'inasafe_default_values') # Remove old container and parameter if self.parameter_container: self.kwExtraKeywordsGridLayout.removeWidget( self.parameter_container) if self.parameters: self.parameters = [] # Iterate through all inasafe fields # existing_inasafe_default_values for inasafe_field in self.inasafe_fields_for_the_layer(): # Option for Not Available option_list = [no_field] for field in self.parent.layer.fields(): # Check the field type if isinstance(inasafe_field['type'], list): if field.type() in inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) else: if field.type() == inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) # Create DefaultSelectParameter parameter = DefaultSelectParameter() parameter.guid = inasafe_field['key'] parameter.name = inasafe_field['name'] parameter.is_required = False parameter.description = inasafe_field['description'] parameter.help_text = inasafe_field['help_text'] parameter.element_type = unicode parameter.options_list = option_list parameter.value = no_field parameter.default_labels = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[0] parameter.default_values = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[1] parameter.minimum = inasafe_field['default_value'].get('min_value') parameter.maximum = inasafe_field['default_value'].get('max_value') # Check if there is already value in the metadata. if existing_inasafe_field: existing_value = existing_inasafe_field.get( inasafe_field['key']) if existing_value: if existing_value in parameter.options_list: parameter.value = existing_value if existing_inasafe_default_values: existing_default_value = existing_inasafe_default_values.get( inasafe_field['key']) if existing_default_value: parameter.default = existing_default_value self.parameters.append(parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer( self.parameters, extra_parameters=self.extra_parameters) self.parameter_container.setup_ui() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) # Add Message label self.kwExtraKeywordsGridLayout.addWidget(self.message_label) # Set default value to None for parameter_widget in self.parameter_container.\ get_parameter_widgets(): parameter_widget.widget().set_default(None) # Set selected radio button to 'Do not report' parameter_widget.widget().set_selected_radio_button() # Set default value from existing keywords if existing_inasafe_default_values: for guid, default in existing_inasafe_default_values.items(): parameter_widget = self.parameter_container.\ get_parameter_widget_by_guid(guid) if isinstance(parameter_widget, DefaultSelectParameterWidget): parameter_widget.set_default(default) # Set selected radio button to 'Do not report' parameter_widget.set_selected_radio_button() def get_inasafe_fields(self): """Return inasafe fields from the current wizard state. :returns: Dictionary of key and value from InaSAFE Fields. :rtype: dict """ inasafe_fields = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if not parameter.value == no_field: inasafe_fields[parameter.guid] = parameter.value return inasafe_fields def get_inasafe_default_values(self): """Return inasafe default from the current wizard state. :returns: Dictionary of key and value from InaSAFE Default Values. :rtype: dict """ inasafe_default_values = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if parameter.default is not None: inasafe_default_values[parameter.guid] = parameter.default return inasafe_default_values def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(range(self.kwExtraKeywordsGridLayout.count())): self.kwExtraKeywordsGridLayout.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('InaSAFE Default Field Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to ' 'set a field that corresponded with a InaSAFE field ' 'concept. It also allows you to set a default value for all ' 'feature if you do not want to use any field').format( step_name=self.step_name))) return message
def main(): """Main function""" application = QApplication([]) name_parameter = StringParameter('UUID-1') name_parameter.name = 'Resource name' name_parameter.help_text = ( 'Name of the resource that will be provided as part of minimum needs.' 'e.g. Tea, Water etc.') name_parameter.description = ( 'A <b>resource</b> is something that you provide to displaced persons ' 'in the event of a disaster. The resource will be made available ' 'at IDP camps and may need to be stockpiled by contingency planners ' 'in their preparations for a disaster.') name_parameter.is_required = True name_parameter.value = '' description_parameter = StringParameter('UUID-1') description_parameter.name = 'Resource description' description_parameter.help_text = ( 'Description of the resource that will be provided as part of minimum ' 'needs. e.g. Tea, Water etc.') description_parameter.description = ( 'Description of the resource that will be provided as part of minimum ' 'needs. e.g. Tea, Water etc.') description_parameter.is_required = True description_parameter.value = '' unit_parameter = StringParameter('UUID-2') unit_parameter.name = 'Units' unit_parameter.help_text = ( 'Unit for the resources. e.g. litres, kg etc.') unit_parameter.description = ( 'A <b>unit</b> the basic measurement unit used for computing the ' 'allowance per individual. For example when planning water rations ' 'the units would be litres.') unit_parameter.is_required = True unit_parameter.value = '' minimum_parameter = FloatParameter('UUID-3') minimum_parameter.name = 'Minimum allowed' minimum_parameter.is_required = True minimum_parameter.precision = 3 minimum_parameter.minimum_allowed_value = -99999.0 minimum_parameter.maximum_allowed_value = 99999.0 minimum_parameter.help_text = 'The minimum allowable quantity per person. ' minimum_parameter.description = ( 'The <b>minimum</b> is the minimum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be less than 0.5l.') minimum_parameter.value = 1.0 maximum_parameter = FloatParameter('UUID-3') maximum_parameter.name = 'Minimum allowed' maximum_parameter.is_required = True maximum_parameter.precision = 3 maximum_parameter.minimum_allowed_value = -99999.0 maximum_parameter.maximum_allowed_value = 99999.0 maximum_parameter.help_text = 'The maximum allowable quantity per person. ' maximum_parameter.description = ( 'The <b>maximum</b> is the maximum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be more than 50l.') maximum_parameter.value = 1.0 maximum_parameter = FloatParameter('UUID-4') maximum_parameter.name = 'Minimum allowed' maximum_parameter.is_required = True maximum_parameter.precision = 3 maximum_parameter.minimum_allowed_value = -99999.0 maximum_parameter.maximum_allowed_value = 99999.0 maximum_parameter.help_text = 'The maximum allowable quantity per person. ' maximum_parameter.description = ( 'The <b>maximum</b> is the maximum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be more than 50l.') maximum_parameter.value = 1.0 default_parameter = FloatParameter('UUID-5') default_parameter.name = 'Default' default_parameter.is_required = True default_parameter.precision = 3 default_parameter.minimum_allowed_value = -99999.0 default_parameter.default_allowed_value = 99999.0 default_parameter.help_text = 'The default allowable quantity per person. ' default_parameter.description = ( 'The <b>default</b> is the default allowed quantity of the resource ' 'per person. For example you may indicate that the water ration per ' 'person per day should be 25l.') default_parameter.value = 1.0 parameters = [ name_parameter, description_parameter, unit_parameter, minimum_parameter, maximum_parameter, default_parameter] parameter_container = ParameterContainer(parameters) widget = QWidget() layout = QGridLayout() layout.addWidget(parameter_container) widget.setLayout(layout) widget.setGeometry(0, 0, 500, 500) widget.show() new_parameters = parameter_container.get_parameters() for new_parameter in new_parameters: print(new_parameter.name, new_parameter.value) sys.exit(application.exec_())
class StepKwInaSAFEFields(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.parameters = [] self.parameter_container = ParameterContainer() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ layer_purpose = self.parent.step_kw_purpose.selected_purpose() if layer_purpose['key'] != layer_purpose_aggregation['key']: subcategory = self.parent.step_kw_subcategory. \ selected_subcategory() else: subcategory = {'key': None} # Check if it can go to inasafe default field step default_inasafe_fields = get_fields(layer_purpose['key'], subcategory['key'], replace_null=True, in_group=False) if default_inasafe_fields: return self.parent.step_kw_default_inasafe_fields # Any other case return self.parent.step_kw_source def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ if (self.parent.get_layer_geometry_key() == layer_geometry_raster['key']): return [] # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose( )['key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = False inasafe_fields = get_fields(layer_purpose_key, subcategory_key, replace_null=False, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove( get_compulsory_fields(layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" existing_inasafe_field = self.parent.get_existing_keyword( 'inasafe_fields') # Remove old container and parameter if self.parameter_container: self.kwExtraKeywordsGridLayout.removeWidget( self.parameter_container) if self.parameters: self.parameters = [] layer_data_provider = self.parent.layer.dataProvider() # Iterate through all inasafe fields for inasafe_field in self.inasafe_fields_for_the_layer(): # Option for Not Available option_list = [no_field] for field in layer_data_provider.fields(): # Check the field type if isinstance(inasafe_field['type'], list): if field.type() in inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) else: if field.type() == inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) # If there is no option, pass if option_list == [no_field]: continue # Create SelectParameter select_parameter = SelectParameter() select_parameter.guid = inasafe_field['key'] select_parameter.name = inasafe_field['name'] select_parameter.is_required = False select_parameter.description = inasafe_field['description'] select_parameter.help_text = inasafe_field['help_text'] select_parameter.element_type = unicode select_parameter.options_list = option_list select_parameter.value = no_field # Check if there is already value in the metadata. if existing_inasafe_field: existing_value = existing_inasafe_field.get( inasafe_field['key']) if existing_value: if existing_value in select_parameter.options_list: select_parameter.value = existing_value self.parameters.append(select_parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer(self.parameters) self.parameter_container.setup_ui() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) if not self.parameters: no_field_message = tr( 'There is no available field that has match type for the ' 'InaSAFE fields. You can click next.') self.lblInaSAFEFields.setText(no_field_message) def get_inasafe_fields(self): """Return inasafe fields from the current wizard state. :returns: Dictionary of key and value from InaSAFE Fields. :rtype: dict """ inasafe_fields = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if not parameter.value == no_field: inasafe_fields[parameter.guid] = parameter.value return inasafe_fields def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(range(self.kwExtraKeywordsGridLayout.count())): self.kwExtraKeywordsGridLayout.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('InaSAFE Field Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add( m.Paragraph( tr('In this wizard step: {step_name}, you will be able to ' 'set a field that corresponded with a InaSAFE field ' 'concept.').format(step_name=self.step_name))) return message
class StepKwInaSAFERasterDefaultValues(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Raster Default Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.extra_parameters = [ (DefaultValueParameter, DefaultValueParameterWidget) ] self.parameters = [] self.parameter_container = ParameterContainer( extra_parameters=self.extra_parameters) self.default_values_grid.addWidget(self.parameter_container) def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ new_step = self.parent.step_kw_source return new_step def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose()[ 'key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = True inasafe_fields = get_fields( layer_purpose_key, subcategory_key, replace_null=True, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove(get_compulsory_fields( layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" existing_inasafe_default_values = self.parent.get_existing_keyword( 'inasafe_default_values') # Remove old container and parameter if self.parameter_container: self.default_values_grid.removeWidget( self.parameter_container) if self.parameters: self.parameters = [] # Iterate through all inasafe fields # existing_inasafe_default_values for inasafe_field in self.inasafe_fields_for_the_layer(): # Create DefaultSelectParameter parameter = DefaultValueParameter() parameter.guid = inasafe_field['key'] parameter.name = inasafe_field['name'] parameter.is_required = False parameter.help_text = inasafe_field['default_value']['description'] # parameter.description = inasafe_field['default_value'] parameter.element_type = unicode parameter.labels = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[0] parameter.options = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[1] if existing_inasafe_default_values: existing_default_value = existing_inasafe_default_values.get( inasafe_field['key']) if existing_default_value: parameter.default = existing_default_value self.parameters.append(parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer( self.parameters, extra_parameters=self.extra_parameters) self.parameter_container.setup_ui() self.default_values_grid.addWidget(self.parameter_container) # Set default value to None for parameter_widget in self.parameter_container.\ get_parameter_widgets(): parameter_widget.widget().set_value(None) # Set default value from existing keywords if existing_inasafe_default_values: for guid, default in existing_inasafe_default_values.items(): parameter_widget = self.parameter_container.\ get_parameter_widget_by_guid(guid) if isinstance(parameter_widget, DefaultValueParameterWidget): parameter_widget.set_value(default) def get_inasafe_default_values(self): """Return inasafe default from the current wizard state. :returns: Dictionary of key and value from InaSAFE Default Values. :rtype: dict """ inasafe_default_values = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if parameter.value is not None: inasafe_default_values[parameter.guid] = parameter.value return inasafe_default_values def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(range(self.default_values_grid.count())): self.default_values_grid.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to ' 'set a value that corresponded with a InaSAFE field ' 'concept as default value.').format(step_name=self.step_name))) return message
class GroupParameterWidget(GenericParameterWidget): """Widget class for List parameter.""" def __init__(self, parameter, parent=None): """Constructor .. versionadded:: 2.2 :param parameter: A GroupParameter object. :type parameter: GroupParameter """ super(GroupParameterWidget, self).__init__(parameter, parent) # Get the parameter label and use its value as the checkbox text label_item = self.input_layout.itemAt(0) label_widget = label_item.widget() text = label_widget.text() self._enable_check_box = QCheckBox(text) # Tooltips self.setToolTip('Tick here to enable ' + self._parameter.name) # add all widget in the group self._group_layout = QVBoxLayout() self._group_layout.setSpacing(0) if not self._parameter.is_required: self.input_layout.insertWidget(0, self._enable_check_box) # now we don't need the parameter label anymore so chuck it self.input_layout.removeItem(label_item) # Make the sub group appear indented self._group_layout.setContentsMargins(20, 0, 0, 0) else: self._parameter.enable_parameter = True self.main_layout.addLayout(self._group_layout) # Why are we doing imports here? TS from parameters.qt_widgets.parameter_container import ParameterContainer self.param_container = ParameterContainer( parameters=self._parameter.value) self.param_container.setup_ui(must_scroll=parameter.must_scroll) # add handlers # noinspection PyUnresolvedReferences self._enable_check_box.stateChanged.connect( self.on_enable_checkbox_changed) self._enable_check_box.setChecked(self._parameter.enable_parameter) self.on_enable_checkbox_changed(self._parameter.enable_parameter) self._group_layout.addWidget(self.param_container) def on_enable_checkbox_changed(self, state): if state: self.param_container.show() else: self.param_container.hide() self._parameter.enable_parameter = state def get_parameter(self): """Obtain list parameter object from the current widget state. :returns: A ListParameter from the current state of widget """ if self._parameter.enable_parameter: parameters = self.param_container.get_parameters() self._parameter.value = parameters self._parameter.validate() return self._parameter
class StepKwDefaultInaSAFEFields(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Default Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.extra_parameters = [ (DefaultSelectParameter, DefaultSelectParameterWidget) ] self.parameters = [] self.parameter_container = ParameterContainer( extra_parameters=self.extra_parameters) self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) self.message_label = QLabel() def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ new_step = self.parent.step_kw_source return new_step def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ if (self.parent.get_layer_geometry_key() == layer_geometry_raster['key']): return [] # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose()[ 'key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = True inasafe_fields = get_fields( layer_purpose_key, subcategory_key, replace_null=True, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove(get_compulsory_fields( layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" self.clear() existing_inasafe_field = self.parent.get_existing_keyword( 'inasafe_fields') existing_inasafe_default_values = self.parent.get_existing_keyword( 'inasafe_default_values') # Remove old container and parameter if self.parameter_container: self.kwExtraKeywordsGridLayout.removeWidget( self.parameter_container) if self.parameters: self.parameters = [] # Iterate through all inasafe fields # existing_inasafe_default_values for inasafe_field in self.inasafe_fields_for_the_layer(): # Option for Not Available option_list = [no_field] for field in self.parent.layer.fields(): # Check the field type if isinstance(inasafe_field['type'], list): if field.type() in inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) else: if field.type() == inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) # Create DefaultSelectParameter parameter = DefaultSelectParameter() parameter.guid = inasafe_field['key'] parameter.name = inasafe_field['name'] parameter.is_required = False parameter.description = inasafe_field['description'] parameter.help_text = inasafe_field['help_text'] parameter.element_type = str parameter.options_list = option_list parameter.value = no_field parameter.default_labels = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[0] parameter.default_values = get_inasafe_default_value_fields( self.parent.setting, inasafe_field['key'])[1] parameter.minimum = inasafe_field['default_value'].get( 'min_value') parameter.maximum = inasafe_field['default_value'].get( 'max_value') # Check if there is already value in the metadata. if existing_inasafe_field: existing_value = existing_inasafe_field.get( inasafe_field['key']) if existing_value: if existing_value in parameter.options_list: parameter.value = existing_value if existing_inasafe_default_values: existing_default_value = existing_inasafe_default_values.get( inasafe_field['key']) if existing_default_value: parameter.default = existing_default_value self.parameters.append(parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer( self.parameters, extra_parameters=self.extra_parameters) self.parameter_container.setup_ui() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) # Add Message label self.kwExtraKeywordsGridLayout.addWidget(self.message_label) # Set default value to None for parameter_widget in self.parameter_container.\ get_parameter_widgets(): parameter_widget.widget().set_default(None) # Set selected radio button to 'Do not report' parameter_widget.widget().set_selected_radio_button() # Set default value from existing keywords if existing_inasafe_default_values: for guid, default in list(existing_inasafe_default_values.items()): parameter_widget = self.parameter_container.\ get_parameter_widget_by_guid(guid) if isinstance(parameter_widget, DefaultSelectParameterWidget): parameter_widget.set_default(default) # Set selected radio button to 'Do not report' parameter_widget.set_selected_radio_button() def get_inasafe_fields(self): """Return inasafe fields from the current wizard state. :returns: Dictionary of key and value from InaSAFE Fields. :rtype: dict """ inasafe_fields = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if not parameter.value == no_field: inasafe_fields[parameter.guid] = parameter.value return inasafe_fields def get_inasafe_default_values(self): """Return inasafe default from the current wizard state. :returns: Dictionary of key and value from InaSAFE Default Values. :rtype: dict """ inasafe_default_values = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if parameter.default is not None: inasafe_default_values[parameter.guid] = parameter.default return inasafe_default_values def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(list(range(self.kwExtraKeywordsGridLayout.count()))): self.kwExtraKeywordsGridLayout.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('InaSAFE Default Field Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to ' 'set a field that corresponded with a InaSAFE field ' 'concept. It also allows you to set a default value for all ' 'feature if you do not want to use any field').format( step_name=self.step_name))) return message
class FieldMappingTab(QWidget, object): """Widget class for field mapping.""" def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() # Parameters self.extra_parameters = [ (GroupSelectParameter, GroupSelectParameterWidget) ] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout) def set_layer(self, layer, keywords=None): """Set layer and update UI accordingly. :param layer: A vector layer that has been already patched with metadata. :type layer: QgsVectorLayer :param keywords: Custom keyword for the layer. :type keywords: dict, None """ self.layer = layer if keywords is not None: self.metadata = keywords else: # Check if it has keywords if not hasattr(layer, 'keywords'): message = 'Layer {layer_name} does not have keywords.'.format( layer_name=layer.name()) raise KeywordNotFoundError(message) self.metadata = layer.keywords self.populate_parameter() def populate_field_list(self, excluded_fields=None): """Helper to add field of the layer to the list. :param excluded_fields: List of field that want to be excluded. :type excluded_fields: list """ # Populate fields list if excluded_fields is None: excluded_fields = [] self.field_list.clear() for field in self.layer.dataProvider().fields(): # Skip if it's excluded if field.name() in excluded_fields: continue # Skip if it's not number (float, int, etc) if field.type() not in qvariant_numbers: continue field_item = QListWidgetItem(self.field_list) field_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field.name()) field_item.setText(field.name()) self.field_list.addItem(field_item) def populate_parameter(self): """Helper to setup the parameter widget.""" used_fields = [] self.parameters = [] for field in self.field_group.get('fields', []): selected_option = DO_NOT_REPORT options = OrderedDict([ (DO_NOT_REPORT, { 'label': tr('Do not report'), 'value': None, 'type': STATIC, 'constraint': {} }), ]) # Example: count if field['absolute']: # Used in field options field_label = tr('Count fields') else: # Example: ratio # Used in field options field_label = tr('Ratio fields') global_default_value = get_inasafe_default_value_qsetting( self.setting, GLOBAL, field['key']) options[GLOBAL_DEFAULT] = { 'label': tr('Global default'), 'value': global_default_value, 'type': STATIC, 'constraint': {} } default_custom_value = get_inasafe_default_value_qsetting( self.setting, RECENT, field['key']) custom_value = self.metadata.get( 'inasafe_default_values', {}).get( field['key'], default_custom_value) if field['key'] in self.metadata.get( 'inasafe_default_values', {}): if custom_value == global_default_value: selected_option = GLOBAL_DEFAULT else: selected_option = CUSTOM_VALUE min_value = field['default_value'].get('min_value', 0) max_value = field['default_value'].get('max_value', 100) default_step = (max_value - min_value) / 100.0 step = field['default_value'].get('increment', default_step) options[CUSTOM_VALUE] = { 'label': tr('Custom'), 'value': custom_value, 'type': SINGLE_DYNAMIC, 'constraint': { 'min': min_value, 'max': max_value, 'step': step } } custom_fields = self.metadata.get('inasafe_fields', {}).get( field['key'], []) if field['key'] in self.metadata.get('inasafe_fields', {}): selected_option = FIELDS if isinstance(custom_fields, basestring): custom_fields = [custom_fields] options[FIELDS] = { 'label': field_label, 'value': custom_fields, 'type': MULTIPLE_DYNAMIC, 'constraint': {} } used_fields.extend(custom_fields) parameter = GroupSelectParameter() parameter.guid = field['key'] parameter.name = field['name'] parameter.options = options parameter.selected = selected_option parameter.help_text = field['help_text'] parameter.description = field['description'] self.parameters.append(parameter) self.parameter_container = ParameterContainer( parameters=self.parameters, extra_parameters=self.extra_parameters, vertical=False ) self.parameter_container.setup_ui() constraints = self.field_group.get('constraints', {}) for key, value in constraints.items(): self.parameter_container.add_validator( validators[key], kwargs=value['kwargs'], validation_message=value['message']) self.parameter_layout.addWidget(self.parameter_container) default_ratio_help_text = tr( 'By default, InaSAFE will calculate the default ratio ' 'however users have the option to include this in the ' 'analysis report. If you do not want to see the default ' 'results in the report choose "do not report".') # Set move or copy if self.field_group.get('exclusive', False): # If exclusive, do not add used field. self.populate_field_list(excluded_fields=used_fields) # Use move action since it's exclusive self.field_list.setDefaultDropAction(Qt.MoveAction) # Just make sure that the signal is disconnected try: # noinspection PyUnresolvedReferences self.field_list.itemChanged.disconnect(self.drop_remove) except TypeError: pass # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can only map one field to one concept.') else: # If not exclusive, add all field. self.populate_field_list() # Use copy action since it's not exclusive self.field_list.setDefaultDropAction(Qt.CopyAction) # noinspection PyUnresolvedReferences self.field_list.itemChanged.connect( partial(self.drop_remove, field_list=self.field_list)) self.connect_drop_remove_parameter() # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can map one field to more than one concepts.') self.header_label.setText(header_text) def get_parameter_value(self): """Get parameter of the tab. :returns: Dictionary of parameters by type in this format: {'fields': {}, 'values': {}}. :rtype: dict """ parameters = self.parameter_container.get_parameters(True) field_parameters = {} value_parameters = {} for parameter in parameters: if parameter.selected_option_type() in [SINGLE_DYNAMIC, STATIC]: value_parameters[parameter.guid] = parameter.value elif parameter.selected_option_type() == MULTIPLE_DYNAMIC: field_parameters[parameter.guid] = parameter.value return { 'fields': field_parameters, 'values': value_parameters } def update_footer(self): """Update footer when the field list change.""" field_item = self.field_list.currentItem() if not field_item: self.footer_label.setText('') return field_name = field_item.data(Qt.UserRole) field = self.layer.fields().field(field_name) index = self.layer.fieldNameIndex(field_name) unique_values = self.layer.uniqueValues(index) pretty_unique_values = ', '.join([str(v) for v in unique_values[:10]]) footer_text = tr('Field type: {0}\n').format(field.typeName()) footer_text += tr('Unique values: {0}').format(pretty_unique_values) self.footer_label.setText(footer_text) def connect_drop_remove_parameter(self): parameter_widgets = self.parameter_container.get_parameter_widgets() for parameter_widget in parameter_widgets: field_list = parameter_widget.widget().list_widget field_list.itemChanged.connect( partial(self.drop_remove, field_list=field_list)) @staticmethod def drop_remove(*args, **kwargs): """Action when we need to remove dropped item. :param *args: Position arguments. :type *args: list :param kwargs: Keywords arguments. :type kwargs: dict """ dropped_item = args[0] field_list = kwargs['field_list'] num_duplicate = 0 for i in range(field_list.count()): if dropped_item.text() == field_list.item(i).text(): num_duplicate += 1 if num_duplicate > 1: # Notes(IS): For some reason, removeItemWidget is not working. field_list.takeItem(field_list.row(dropped_item))
def main(): """Main function""" application = QApplication([]) name_parameter = StringParameter('UUID-1') name_parameter.name = 'Resource name' name_parameter.help_text = ( 'Name of the resource that will be provided as part of minimum needs.' 'e.g. Tea, Water etc.') name_parameter.description = ( 'A <b>resource</b> is something that you provide to displaced persons ' 'in the event of a disaster. The resource will be made available ' 'at IDP camps and may need to be stockpiled by contingency planners ' 'in their preparations for a disaster.') name_parameter.is_required = True name_parameter.value = '' description_parameter = StringParameter('UUID-1') description_parameter.name = 'Resource description' description_parameter.help_text = ( 'Description of the resource that will be provided as part of minimum ' 'needs. e.g. Tea, Water etc.') description_parameter.description = ( 'Description of the resource that will be provided as part of minimum ' 'needs. e.g. Tea, Water etc.') description_parameter.is_required = True description_parameter.value = '' unit_parameter = StringParameter('UUID-2') unit_parameter.name = 'Units' unit_parameter.help_text = ('Unit for the resources. e.g. litres, kg etc.') unit_parameter.description = ( 'A <b>unit</b> the basic measurement unit used for computing the ' 'allowance per individual. For example when planning water rations ' 'the units would be litres.') unit_parameter.is_required = True unit_parameter.value = '' minimum_parameter = FloatParameter('UUID-3') minimum_parameter.name = 'Minimum allowed' minimum_parameter.is_required = True minimum_parameter.precision = 3 minimum_parameter.minimum_allowed_value = -99999.0 minimum_parameter.maximum_allowed_value = 99999.0 minimum_parameter.help_text = 'The minimum allowable quantity per person. ' minimum_parameter.description = ( 'The <b>minimum</b> is the minimum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be less than 0.5l.') minimum_parameter.value = 1.0 maximum_parameter = FloatParameter('UUID-3') maximum_parameter.name = 'Minimum allowed' maximum_parameter.is_required = True maximum_parameter.precision = 3 maximum_parameter.minimum_allowed_value = -99999.0 maximum_parameter.maximum_allowed_value = 99999.0 maximum_parameter.help_text = 'The maximum allowable quantity per person. ' maximum_parameter.description = ( 'The <b>maximum</b> is the maximum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be more than 50l.') maximum_parameter.value = 1.0 maximum_parameter = FloatParameter('UUID-4') maximum_parameter.name = 'Minimum allowed' maximum_parameter.is_required = True maximum_parameter.precision = 3 maximum_parameter.minimum_allowed_value = -99999.0 maximum_parameter.maximum_allowed_value = 99999.0 maximum_parameter.help_text = 'The maximum allowable quantity per person. ' maximum_parameter.description = ( 'The <b>maximum</b> is the maximum allowed quantity of the resource ' 'per person. For example you may dictate that the water ration per ' 'person per day should never be allowed to be more than 50l.') maximum_parameter.value = 1.0 default_parameter = FloatParameter('UUID-5') default_parameter.name = 'Default' default_parameter.is_required = True default_parameter.precision = 3 default_parameter.minimum_allowed_value = -99999.0 default_parameter.default_allowed_value = 99999.0 default_parameter.help_text = 'The default allowable quantity per person. ' default_parameter.description = ( 'The <b>default</b> is the default allowed quantity of the resource ' 'per person. For example you may indicate that the water ration per ' 'person per day should be 25l.') default_parameter.value = 1.0 parameters = [ name_parameter, description_parameter, unit_parameter, minimum_parameter, maximum_parameter, default_parameter ] parameter_container = ParameterContainer(parameters) widget = QWidget() layout = QGridLayout() layout.addWidget(parameter_container) widget.setLayout(layout) widget.setGeometry(0, 0, 500, 500) widget.show() new_parameters = parameter_container.get_parameters() for new_parameter in new_parameters: print new_parameter.name, new_parameter.value sys.exit(application.exec_())
class FieldMappingTab(QWidget, object): """Widget class for field mapping.""" def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() self.footer_label.setWordWrap(True) # Parameters self.extra_parameters = [ (GroupSelectParameter, GroupSelectParameterWidget) ] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout) def set_layer(self, layer, keywords=None): """Set layer and update UI accordingly. :param layer: A vector layer that has been already patched with metadata. :type layer: QgsVectorLayer :param keywords: Custom keyword for the layer. :type keywords: dict, None """ self.layer = layer if keywords is not None: self.metadata = keywords else: # Check if it has keywords if not hasattr(layer, 'keywords'): message = 'Layer {layer_name} does not have keywords.'.format( layer_name=layer.name()) raise KeywordNotFoundError(message) self.metadata = layer.keywords self.populate_parameter() def populate_field_list(self, excluded_fields=None): """Helper to add field of the layer to the list. :param excluded_fields: List of field that want to be excluded. :type excluded_fields: list """ # Populate fields list if excluded_fields is None: excluded_fields = [] self.field_list.clear() for field in self.layer.fields(): # Skip if it's excluded if field.name() in excluded_fields: continue # Skip if it's not number (float, int, etc) if field.type() not in qvariant_numbers: continue field_item = QListWidgetItem(self.field_list) field_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field.name()) field_item.setText(field.name()) self.field_list.addItem(field_item) def populate_parameter(self): """Helper to setup the parameter widget.""" used_fields = [] self.parameters = [] for field in self.field_group.get('fields', []): selected_option = DO_NOT_REPORT options = OrderedDict([ (DO_NOT_REPORT, { 'label': tr('Do not report'), 'value': None, 'type': STATIC, 'constraint': {} }), ]) # Example: count if field['absolute']: # Used in field options field_label = tr('Count fields') else: # Example: ratio # Used in field options field_label = tr('Ratio fields') global_default_value = get_inasafe_default_value_qsetting( self.setting, GLOBAL, field['key']) options[GLOBAL_DEFAULT] = { 'label': tr('Global default'), 'value': global_default_value, 'type': STATIC, 'constraint': {} } default_custom_value = get_inasafe_default_value_qsetting( self.setting, RECENT, field['key']) custom_value = self.metadata.get( 'inasafe_default_values', {}).get( field['key'], default_custom_value) if field['key'] in self.metadata.get( 'inasafe_default_values', {}): if custom_value == global_default_value: selected_option = GLOBAL_DEFAULT else: selected_option = CUSTOM_VALUE min_value = field['default_value'].get('min_value', 0) max_value = field['default_value'].get('max_value', 100) default_step = (max_value - min_value) / 100.0 step = field['default_value'].get('increment', default_step) options[CUSTOM_VALUE] = { 'label': tr('Custom'), 'value': custom_value, 'type': SINGLE_DYNAMIC, 'constraint': { 'min': min_value, 'max': max_value, 'step': step } } custom_fields = self.metadata.get('inasafe_fields', {}).get( field['key'], []) if field['key'] in self.metadata.get('inasafe_fields', {}): selected_option = FIELDS if isinstance(custom_fields, str): custom_fields = [custom_fields] options[FIELDS] = { 'label': field_label, 'value': custom_fields, 'type': MULTIPLE_DYNAMIC, 'constraint': {} } used_fields.extend(custom_fields) parameter = GroupSelectParameter() parameter.guid = field['key'] parameter.name = field['name'] parameter.options = options parameter.selected = selected_option parameter.help_text = field['help_text'] parameter.description = field['description'] self.parameters.append(parameter) self.parameter_container = ParameterContainer( parameters=self.parameters, extra_parameters=self.extra_parameters, vertical=False ) self.parameter_container.setup_ui() constraints = self.field_group.get('constraints', {}) for key, value in list(constraints.items()): self.parameter_container.add_validator( validators[key], kwargs=value['kwargs'], validation_message=value['message']) self.parameter_layout.addWidget(self.parameter_container) default_ratio_help_text = tr( 'By default, InaSAFE will calculate the default ratio ' 'however users have the option to include this in the ' 'analysis report. If you do not want to see the default ' 'results in the report choose "do not report".') # Set move or copy if self.field_group.get('exclusive', False): # If exclusive, do not add used field. self.populate_field_list(excluded_fields=used_fields) # Use move action since it's exclusive self.field_list.setDefaultDropAction(Qt.MoveAction) # Just make sure that the signal is disconnected try: # noinspection PyUnresolvedReferences self.field_list.itemChanged.disconnect(self.drop_remove) except TypeError: pass # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can only map one field to one concept.') else: # If not exclusive, add all field. self.populate_field_list() # Use copy action since it's not exclusive self.field_list.setDefaultDropAction(Qt.CopyAction) # noinspection PyUnresolvedReferences self.field_list.itemChanged.connect( partial(self.drop_remove, field_list=self.field_list)) self.connect_drop_remove_parameter() # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can map one field to more than one concepts.') self.header_label.setText(header_text) def get_parameter_value(self): """Get parameter of the tab. :returns: Dictionary of parameters by type in this format: {'fields': {}, 'values': {}}. :rtype: dict """ parameters = self.parameter_container.get_parameters(True) field_parameters = {} value_parameters = {} for parameter in parameters: if parameter.selected_option_type() in [SINGLE_DYNAMIC, STATIC]: value_parameters[parameter.guid] = parameter.value elif parameter.selected_option_type() == MULTIPLE_DYNAMIC: field_parameters[parameter.guid] = parameter.value return { 'fields': field_parameters, 'values': value_parameters } def update_footer(self): """Update footer when the field list change.""" field_item = self.field_list.currentItem() if not field_item: self.footer_label.setText('') return field_name = field_item.data(Qt.UserRole) field = self.layer.fields().field(field_name) index = self.layer.fields().lookupField(field_name) unique_values = list(self.layer.uniqueValues(index)) pretty_unique_values = ', '.join([str(v) for v in unique_values[:10]]) footer_text = tr('Field type: {0}\n').format(field.typeName()) footer_text += tr('Unique values: {0}').format(pretty_unique_values) self.footer_label.setText(footer_text) def connect_drop_remove_parameter(self): parameter_widgets = self.parameter_container.get_parameter_widgets() for parameter_widget in parameter_widgets: field_list = parameter_widget.widget().list_widget field_list.itemChanged.connect( partial(self.drop_remove, field_list=field_list)) @staticmethod def drop_remove(*args, **kwargs): """Action when we need to remove dropped item. :param *args: Position arguments. :type *args: list :param kwargs: Keywords arguments. :type kwargs: dict """ dropped_item = args[0] field_list = kwargs['field_list'] num_duplicate = 0 for i in range(field_list.count()): if dropped_item.text() == field_list.item(i).text(): num_duplicate += 1 if num_duplicate > 1: # Notes(IS): For some reason, removeItemWidget is not working. field_list.takeItem(field_list.row(dropped_item))
class StepKwInaSAFEFields(WizardStep, FORM_CLASS): """InaSAFE Wizard Step InaSAFE Fields.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: parent - widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.parameters = [] self.parameter_container = ParameterContainer() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) def is_ready_to_next_step(self): """Check if the step is complete. If so, there is no reason to block the Next button. :returns: True if new step may be enabled. :rtype: bool """ return True def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to :rtype: WizardStep instance or None """ layer_purpose = self.parent.step_kw_purpose.selected_purpose() if layer_purpose['key'] != layer_purpose_aggregation['key']: subcategory = self.parent.step_kw_subcategory. \ selected_subcategory() else: subcategory = {'key': None} # Check if it can go to inasafe default field step default_inasafe_fields = get_fields( layer_purpose['key'], subcategory['key'], replace_null=True, in_group=False) if default_inasafe_fields: return self.parent.step_kw_default_inasafe_fields # Any other case return self.parent.step_kw_source def inasafe_fields_for_the_layer(self): """Return a list of inasafe fields the current layer. :returns: A list where each value represents inasafe field. :rtype: list """ if (self.parent.get_layer_geometry_key() == layer_geometry_raster['key']): return [] # Get hazard or exposure value layer_purpose_key = self.parent.step_kw_purpose.selected_purpose()[ 'key'] if layer_purpose_key != layer_purpose_aggregation['key']: subcategory_key = self.parent.step_kw_subcategory.\ selected_subcategory()['key'] else: subcategory_key = None # Get all fields with replace_null = False inasafe_fields = get_fields( layer_purpose_key, subcategory_key, replace_null=False, in_group=False) # remove compulsory field since it has been set in previous step try: inasafe_fields.remove(get_compulsory_fields( layer_purpose_key, subcategory_key)) except ValueError: pass return inasafe_fields # noinspection PyTypeChecker def set_widgets(self): """Set widgets on the Extra Keywords tab.""" existing_inasafe_field = self.parent.get_existing_keyword( 'inasafe_fields') # Remove old container and parameter if self.parameter_container: self.kwExtraKeywordsGridLayout.removeWidget( self.parameter_container) if self.parameters: self.parameters = [] layer_data_provider = self.parent.layer.dataProvider() # Iterate through all inasafe fields for inasafe_field in self.inasafe_fields_for_the_layer(): # Option for Not Available option_list = [no_field] for field in layer_data_provider.fields(): # Check the field type if isinstance(inasafe_field['type'], list): if field.type() in inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) else: if field.type() == inasafe_field['type']: field_name = field.name() option_list.append('%s' % field_name) # If there is no option, pass if option_list == [no_field]: continue # Create SelectParameter select_parameter = SelectParameter() select_parameter.guid = inasafe_field['key'] select_parameter.name = inasafe_field['name'] select_parameter.is_required = False select_parameter.description = inasafe_field['description'] select_parameter.help_text = inasafe_field['help_text'] select_parameter.element_type = unicode select_parameter.options_list = option_list select_parameter.value = no_field # Check if there is already value in the metadata. if existing_inasafe_field: existing_value = existing_inasafe_field.get( inasafe_field['key']) if existing_value: if existing_value in select_parameter.options_list: select_parameter.value = existing_value self.parameters.append(select_parameter) # Create the parameter container and add to the wizard. self.parameter_container = ParameterContainer(self.parameters) self.parameter_container.setup_ui() self.kwExtraKeywordsGridLayout.addWidget(self.parameter_container) if not self.parameters: no_field_message = tr( 'There is no available field that has match type for the ' 'InaSAFE fields. You can click next.') self.lblInaSAFEFields.setText(no_field_message) def get_inasafe_fields(self): """Return inasafe fields from the current wizard state. :returns: Dictionary of key and value from InaSAFE Fields. :rtype: dict """ inasafe_fields = {} parameters = self.parameter_container.get_parameters(True) for parameter in parameters: if not parameter.value == no_field: inasafe_fields[parameter.guid] = parameter.value return inasafe_fields def clear(self): """Clear current state.""" # Adapted from http://stackoverflow.com/a/13103617/1198772 for i in reversed(range(self.kwExtraKeywordsGridLayout.count())): self.kwExtraKeywordsGridLayout.itemAt(i).widget().setParent(None) self.parameters = [] self.parameter_container = ParameterContainer() @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('InaSAFE Field Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to ' 'set a field that corresponded with a InaSAFE field ' 'concept.').format(step_name=self.step_name))) return message