inasafe/inasafe

View on GitHub
safe/gui/tools/wizard/step_kw05_subcategory.py

Summary

Maintainability
B
6 hrs
Test Coverage
# coding=utf-8
"""InaSAFE Wizard Step Layer Purpose Type."""


from qgis.PyQt import QtCore
from qgis.PyQt.QtWidgets import QListWidgetItem
from qgis.PyQt.QtGui import QPixmap

from safe import messaging as m
from safe.definitions.layer_purposes import (
    layer_purpose_exposure, layer_purpose_hazard)
from safe.definitions.utilities import (
    hazards_for_layer,
    definition,
    exposures_for_layer)
from safe.gui.tools.wizard.utilities import get_question_text, get_image_path
from safe.gui.tools.wizard.wizard_step import WizardStep
from safe.gui.tools.wizard.wizard_step import get_wizard_step_ui_class
from safe.utilities.gis import is_raster_layer
from safe.utilities.i18n import tr

__copyright__ = "Copyright 2016, The InaSAFE Project"
__license__ = "GPL version 3"
__email__ = "info@inasafe.org"
__revision__ = '$Format:%H$'

FORM_CLASS = get_wizard_step_ui_class(__file__)


class StepKwSubcategory(WizardStep, FORM_CLASS):

    """InaSAFE Wizard Step Layer Purpose Type."""

    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 bool(self.selected_subcategory())

    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
        """
        if self.parent.step_kw_purpose.\
                selected_purpose() == layer_purpose_hazard:
            new_step = self.parent.step_kw_hazard_category
        else:
            if is_raster_layer(self.parent.layer):
                new_step = self.parent.step_kw_band_selector
            else:
                new_step = self.parent.step_kw_layermode
        return new_step

    def subcategories_for_layer(self):
        """Return a list of valid subcategories for a layer.
           Subcategory is hazard type or exposure type.

        :returns: A list where each value represents a valid subcategory.
        :rtype: list
        """
        purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_geometry_key = self.parent.get_layer_geometry_key()
        if purpose == layer_purpose_hazard:
            return hazards_for_layer(layer_geometry_key)
        elif purpose == layer_purpose_exposure:
            return exposures_for_layer(layer_geometry_key)

    # noinspection PyPep8Naming
    def on_lstSubcategories_itemSelectionChanged(self):
        """Update subcategory description label.

        .. note:: This is an automatic Qt slot
           executed when the subcategory selection changes.
        """
        self.clear_further_steps()
        # Set widgets
        subcategory = self.selected_subcategory()
        # Exit if no selection
        if not subcategory:
            return
        # Set description label
        self.lblDescribeSubcategory.setText(subcategory['description'])

        icon_path = get_image_path(subcategory)

        self.lblIconSubcategory.setPixmap(QPixmap(icon_path))
        # Enable the next button
        self.parent.pbnNext.setEnabled(True)

    def selected_subcategory(self):
        """Obtain the subcategory selected by user.

        :returns: Metadata of the selected subcategory.
        :rtype: dict, None
        """
        item = self.lstSubcategories.currentItem()
        try:
            return definition(item.data(QtCore.Qt.UserRole))
        except (AttributeError, NameError):
            return None

    def clear_further_steps(self):
        """Clear all further steps in order to properly calculate the prev step
        """
        self.parent.step_kw_hazard_category.lstHazardCategories.clear()
        self.parent.step_kw_layermode.lstLayerModes.clear()
        self.parent.step_kw_unit.lstUnits.clear()
        self.parent.step_kw_field.lstFields.clear()
        self.parent.step_kw_classification.lstClassifications.clear()

    def set_widgets(self):
        """Set widgets on the Subcategory tab."""
        self.clear_further_steps()
        # Set widgets
        purpose = self.parent.step_kw_purpose.selected_purpose()
        self.lstSubcategories.clear()
        self.lblDescribeSubcategory.setText('')
        self.lblIconSubcategory.setPixmap(QPixmap())
        self.lblSelectSubcategory.setText(
            get_question_text('%s_question' % purpose['key']))
        for i in self.subcategories_for_layer():
            # noinspection PyTypeChecker
            item = QListWidgetItem(i['name'], self.lstSubcategories)
            # noinspection PyTypeChecker
            item.setData(QtCore.Qt.UserRole, i['key'])
            self.lstSubcategories.addItem(item)

        # Check if layer keywords are already assigned
        key = self.parent.step_kw_purpose.selected_purpose()['key']
        keyword = self.parent.get_existing_keyword(key)

        # Overwrite the keyword if it's KW mode embedded in IFCW mode
        if self.parent.parent_step:
            keyword = self.parent.get_parent_mode_constraints()[1]['key']

        # Set values based on existing keywords or parent mode
        if keyword:
            subcategories = []
            for index in range(self.lstSubcategories.count()):
                item = self.lstSubcategories.item(index)
                subcategories.append(item.data(QtCore.Qt.UserRole))
            if keyword in subcategories:
                self.lstSubcategories.setCurrentRow(
                    subcategories.index(keyword))

        self.auto_select_one_item(self.lstSubcategories)

    @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('Layer Purpose Type 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 the '
            'type of your layer based on the purpose that you have set in the '
            'previous step (if you choose hazard or exposure purpose). In '
            'this step, there is list of exposure / hazard type that you can '
            'select to specify your layer purpose type.'
        ).format(step_name=self.step_name)))
        return message