Пример #1
0
    def test_all_dynamic_translations(self):
        """Test all the phrases defined in dynamic_translations translate."""
        parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
        dir_path = os.path.abspath(parent_path)
        file_path = os.path.join(
            dir_path, '../safe', 'common', 'dynamic_translations.py')
        translations_file = file(file_path)
        failure_list = []
        os.environ['LANG'] = 'id'
        line_count = 0
        # exception_words is a list of words that has the same form in both
        # English and Indonesian. For example hotel, bank
        exception_words = ['hotel', 'bank', 'Area']
        for line in translations_file.readlines():
            line_count += 1
            if 'tr(' in line:
                match = re.search(r'\(\'(.*)\'\)', line, re.M | re.I)
                if match:
                    group = match.group()
                    cleaned_line = group[2:-2]
                    if cleaned_line in exception_words:
                        continue
                    translation = safeTr(cleaned_line)
                    if cleaned_line == translation:
                        failure_list.append(cleaned_line)

        message = (
            'Translations not found for:\n %s\n%i of %i untranslated\n' % (
                str(failure_list).replace(',', '\n'), len(failure_list),
                line_count))
        message += (
            'If you think the Indonesian word for the failed translations is '
            'the same form in English, i.e. "hotel", you can add it in '
            'exception_words in safe_qgis/test_safe_translations.py')
        self.assertEqual(len(failure_list), 0, message)
Пример #2
0
    def test_dynamic_translation(self):
        """Test for dynamic translations for a string."""

        # English
        function_title = 'Be affected'
        expected_title = safeTr('Be affected')
        message = 'Expected %s but got %s' % (expected_title, function_title)
        self.assertEqual(function_title, expected_title, message)

        # Indonesia
        os.environ['LANG'] = 'id'
        function_title = 'Be affected'
        real_title = safeTr(function_title)
        expected_title = 'Terkena dampak'
        message = 'expected %s but got %s' % (expected_title, real_title)
        self.assertEqual(expected_title, real_title, message)
Пример #3
0
    def testAllDynamicTranslatons(self):
        """Test all the phrases defined in dynamic_translations translate."""
        myParentPath = os.path.join(__file__, os.path.pardir, os.path.pardir)
        myDirPath = os.path.abspath(myParentPath)
        myFilePath = os.path.join(myDirPath, '../safe', 'common',
                                  'dynamic_translations.py')
        myFile = file(myFilePath, 'rt')
        myFailureList = []
        os.environ['LANG'] = 'id'
        myLineCount = 0
        # exception_words is a list of words that has the same form in both
        # English and Indonesian. For example hotel, bank
        exception_words = ['hotel', 'bank']
        for myLine in myFile.readlines():
            myLineCount += 1
            if 'tr(' in myLine:
                myMatch = re.search(r'\(\'(.*)\'\)', myLine, re.M | re.I)
                if myMatch:
                    myGroup = myMatch.group()
                    myCleanedLine = myGroup[2:-2]
                    if myCleanedLine in exception_words:
                        continue
                    myTranslation = safeTr(myCleanedLine)
                    print myTranslation, myCleanedLine
                    if myCleanedLine == myTranslation:
                        myFailureList.append(myCleanedLine)

        myMessage = ('Translations not found for:\n %s\n%i '
                     'of %i untranslated\n' % (str(myFailureList).replace(
                         ',', '\n'), len(myFailureList), myLineCount))
        myMessage += ('If you think the Indonesian word for the failed '
                      'translations is the same form in English, i.'
                      'e. "hotel", you can add it in exception_words in '
                      'safe_qgis/test_safe_translations.py')
        assert len(myFailureList) == 0, myMessage
Пример #4
0
    def test_all_dynamic_translations(self):
        """Test all the phrases defined in dynamic_translations translate."""
        parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
        dir_path = os.path.abspath(parent_path)
        file_path = os.path.join(dir_path, '../safe', 'common',
                                 'dynamic_translations.py')
        translations_file = file(file_path)
        failure_list = []
        os.environ['LANG'] = 'id'
        line_count = 0
        # exception_words is a list of words that has the same form in both
        # English and Indonesian. For example hotel, bank
        exception_words = ['hotel', 'bank', 'Area']
        for line in translations_file.readlines():
            line_count += 1
            if 'tr(' in line:
                match = re.search(r'\(\'(.*)\'\)', line, re.M | re.I)
                if match:
                    group = match.group()
                    cleaned_line = group[2:-2]
                    if cleaned_line in exception_words:
                        continue
                    translation = safeTr(cleaned_line)
                    print translation, cleaned_line
                    if cleaned_line == translation:
                        failure_list.append(cleaned_line)

        message = ('Translations not found for:\n %s\n%i '
                   'of %i untranslated\n' % (str(failure_list).replace(
                       ',', '\n'), len(failure_list), line_count))
        message += ('If you think the Indonesian word for the failed '
                    'translations is the same form in English, i.'
                    'e. "hotel", you can add it in exception_words in '
                    'safe_qgis/test_safe_translations.py')
        assert len(failure_list) == 0, message
Пример #5
0
 def testImpactSummaryWords(self):
     """Test specific words from impact summary info shown in doc see #348.
     """
     os.environ['LANG'] = 'id'
     myPhraseList = []
     myMessage = 'Specific words checked for translation:\n'
     for myPhrase in myPhraseList:
         if myPhrase == safeTr(myPhrase):
             myMessage += 'FAIL: %s' % myPhrase
         else:
             myMessage += 'PASS: %s' % myPhrase
     self.assertNotIn('FAIL', myMessage, myMessage)
Пример #6
0
 def test_impact_summary_words(self):
     """Test specific words from impact summary info shown in doc see #348.
     """
     os.environ['LANG'] = 'id'
     phrase_list = []
     message = 'Specific words checked for translation:\n'
     for phrase in phrase_list:
         if phrase == safeTr(phrase):
             message += 'FAIL: %s' % phrase
         else:
             message += 'PASS: %s' % phrase
     self.assertNotIn('FAIL', message, message)
Пример #7
0
 def test_impact_summary_words(self):
     """Test specific words from impact summary info shown in doc see #348.
     """
     os.environ['LANG'] = 'id'
     phrase_list = []
     message = 'Specific words checked for translation:\n'
     for myPhrase in phrase_list:
         if myPhrase == safeTr(myPhrase):
             message += 'FAIL: %s' % myPhrase
         else:
             message += 'PASS: %s' % myPhrase
     self.assertNotIn('FAIL', message, message)
Пример #8
0
 def test_impact_summary_words(self):
     """Test specific words from impact summary info shown in doc see #348.
     """
     os.environ["LANG"] = "id"
     phrase_list = []
     message = "Specific words checked for translation:\n"
     for myPhrase in phrase_list:
         if myPhrase == safeTr(myPhrase):
             message += "FAIL: %s" % myPhrase
         else:
             message += "PASS: %s" % myPhrase
     self.assertNotIn("FAIL", message, message)
Пример #9
0
    def Xtest_ImpactFunctionI18n(self):
        """Library translations are working."""
        # Import this late so that i18n setup is already in place

        # Test indonesian too
        myCanvas = QgsMapCanvas(PARENT)
        myIface = QgisInterface(myCanvas)
        myPlugin = Plugin(myIface)
        myPlugin.change_i18n('id')  # indonesian
        myExpectedString = 'Letusan gunung berapi'
        myTranslation = safeTr('A volcano eruption')
        message = '\nTranslated: %s\nGot: %s\nExpected: %s' % \
                    ('A volcano eruption', myTranslation, myExpectedString)
        assert myTranslation == myExpectedString, message
Пример #10
0
    def Xtest_ImpactFunctionI18n(self):
        """Library translations are working."""
        # Import this late so that i18n setup is already in place

        # Test indonesian too
        myCanvas = QgsMapCanvas(PARENT)
        myIface = QgisInterface(myCanvas)
        myPlugin = Plugin(myIface)
        myPlugin.setup_i18n('id')  # indonesian
        myExpectedString = 'Letusan gunung berapi'
        myTranslation = safeTr('A volcano eruption')
        myMessage = '\nTranslated: %s\nGot: %s\nExpected: %s' % \
                    ('A volcano eruption', myTranslation, myExpectedString)
        assert myTranslation == myExpectedString, myMessage
Пример #11
0
    def buildWidget(self, theFormLayout, theName, theValue):
        """Create a new form element dynamically based from theValue type.
        The element will be inserted to theFormLayout.

        :param theFormLayout: Mandatory a layout instance
        :type theFormLayout: QFormLayout

        :param theName: Mandatory string referencing the key in the function
         configurable parameters dictionary.
        :type theName: str

        :param theValue: Mandatory representing the value referenced by the
         key.
        :type theValue: object

        :returns: a function that return the value of widget

        :raises: None
        """

        # create label
        if isinstance(theName, str):
            myLabel = QLabel()
            myLabel.setObjectName(_fromUtf8(theName + "Label"))
            myLabelText = theName.replace('_', ' ').capitalize()
            myLabel.setText(safeTr(myLabelText))
            myLabel.setToolTip(str(type(theValue)))
        else:
            myLabel = theName

        # create widget based on the type of theValue variable
        if isinstance(theValue, list):
            myWidget = QLineEdit()
            myValue = ', '.join([str(x) for x in theValue])
            # NOTE: we assume that all element in list have same type
            myType = type(theValue[0])
            myFunc = lambda x: [myType(y) for y in str(x).split(',')]
        elif isinstance(theValue, dict):
            myWidget = QLineEdit()
            myValue = str(theValue)
            myFunc = lambda x: ast.literal_eval(str(x))
        else:
            myWidget = QLineEdit()
            myValue = str(theValue)
            myFunc = type(theValue)

        myWidget.setText(myValue)
        theFormLayout.addRow(myLabel, myWidget)

        return self.bind(myWidget, 'text', myFunc)
Пример #12
0
    def buildWidget(self, theFormLayout, theName, theValue):
        """Create a new form element dynamically based from theValue type.
        The element will be inserted to theFormLayout.

        :param theFormLayout: Mandatory a layout instance
        :type theFormLayout: QFormLayout

        :param theName: Mandatory string referencing the key in the function
         configurable parameters dictionary.
        :type theName: str

        :param theValue: Mandatory representing the value referenced by the
         key.
        :type theValue: object

        :returns: a function that return the value of widget

        :raises: None
        """

        # create label
        if isinstance(theName, str):
            myLabel = QLabel()
            myLabel.setObjectName(_fromUtf8(theName + "Label"))
            myLabelText = theName.replace('_', ' ').capitalize()
            myLabel.setText(safeTr(myLabelText))
            myLabel.setToolTip(str(type(theValue)))
        else:
            myLabel = theName

        # create widget based on the type of theValue variable
        if isinstance(theValue, list):
            myWidget = QLineEdit()
            myValue = ', '.join([str(x) for x in theValue])
            # NOTE: we assume that all element in list have same type
            myType = type(theValue[0])
            myFunc = lambda x: [myType(y) for y in str(x).split(',')]
        elif isinstance(theValue, dict):
            myWidget = QLineEdit()
            myValue = str(theValue)
            myFunc = lambda x: ast.literal_eval(str(x))
        else:
            myWidget = QLineEdit()
            myValue = str(theValue)
            myFunc = type(theValue)

        myWidget.setText(myValue)
        theFormLayout.addRow(myLabel, myWidget)

        return self.bind(myWidget, 'text', myFunc)
Пример #13
0
    def test_dynamic_translation(self):
        """Test for dynamic translations for a string
        """

        # English
        func_title = "Be affected"
        expected_title = "Be affected"
        assert func_title == expected_title

        # Indonesia
        os.environ["LANG"] = "id"
        func_title = "Be affected"
        real_title = safeTr(func_title)
        expected_title = "Terkena dampak"
        msg = "expected %s but got %s" % (expected_title, real_title)
        assert expected_title == real_title, msg
Пример #14
0
    def test_dynamic_translation(self):
        """Test for dynamic translations for a string
        """

        # English
        func_title = 'Be affected'
        expected_title = 'Be affected'
        assert func_title == expected_title

        # Indonesia
        os.environ['LANG'] = 'id'
        func_title = 'Be affected'
        real_title = safeTr(func_title)
        expected_title = 'Terkena dampak'
        msg = 'expected %s but got %s' % (expected_title, real_title)
        assert expected_title == real_title, msg
Пример #15
0
    def testDynamicTranslation(self):
        """Test for dynamic translations for a string
        """

        # English
        func_title = 'Be affected'
        expected_title = 'Be affected'
        assert func_title == expected_title

        # Indonesia
        os.environ['LANG'] = 'id'
        func_title = 'Be affected'
        real_title = safeTr(func_title)
        expected_title = 'Terkena dampak'
        msg = 'expected %s but got %s' % (expected_title, real_title)
        assert expected_title == real_title, msg
Пример #16
0
    def testAllDynamicTranslatons(self):
        """Test all the phrases defined in dynamic_translations translate."""
        myParentPath = os.path.join(__file__, os.path.pardir, os.path.pardir)
        myDirPath = os.path.abspath(myParentPath)
        myFilePath = os.path.join(myDirPath,
                                  '../safe',
                                  'common',
                                  'dynamic_translations.py')
        myFile = file(myFilePath, 'rt')
        myFailureList = []
        os.environ['LANG'] = 'id'
        myLineCount = 0
        # exception_words is a list of words that has the same form in both
        # English and Indonesian. For example hotel, bank
        exception_words = ['hotel', 'bank']
        for myLine in myFile.readlines():
            myLineCount += 1
            if 'tr(' in myLine:
                myMatch = re.search(r'\(\'(.*)\'\)', myLine, re.M | re.I)
                if myMatch:
                    myGroup = myMatch.group()
                    myCleanedLine = myGroup[2:-2]
                    if myCleanedLine in exception_words:
                        continue
                    myTranslation = safeTr(myCleanedLine)
                    print myTranslation, myCleanedLine
                    if myCleanedLine == myTranslation:
                        myFailureList.append(myCleanedLine)

        myMessage = ('Translations not found for:\n %s\n%i '
                     'of %i untranslated\n' % (
                     str(myFailureList).replace(',', '\n'),
                     len(myFailureList),
                     myLineCount))
        myMessage += ('If you think the Indonesian word for the failed '
                      'translations is the same form in English, i.'
                      'e. "hotel", you can add it in exception_words in '
                      'safe_qgis/test_safe_translations.py')
        assert len(myFailureList) == 0, myMessage
Пример #17
0
    def test_all_dynamic_translations(self):
        """Test all the phrases defined in dynamic_translations translate."""
        parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
        dir_path = os.path.abspath(parent_path)
        file_path = os.path.join(dir_path, "../safe", "common", "dynamic_translations.py")
        translations_file = file(file_path)
        failure_list = []
        os.environ["LANG"] = "id"
        line_count = 0
        # exception_words is a list of words that has the same form in both
        # English and Indonesian. For example hotel, bank
        exception_words = ["hotel", "bank", "Area"]
        for line in translations_file.readlines():
            line_count += 1
            if "tr(" in line:
                match = re.search(r"\(\'(.*)\'\)", line, re.M | re.I)
                if match:
                    group = match.group()
                    cleaned_line = group[2:-2]
                    if cleaned_line in exception_words:
                        continue
                    translation = safeTr(cleaned_line)
                    print translation, cleaned_line
                    if cleaned_line == translation:
                        failure_list.append(cleaned_line)

        message = "Translations not found for:\n %s\n%i " "of %i untranslated\n" % (
            str(failure_list).replace(",", "\n"),
            len(failure_list),
            line_count,
        )
        message += (
            "If you think the Indonesian word for the failed "
            "translations is the same form in English, i."
            'e. "hotel", you can add it in exception_words in '
            "safe_qgis/test_safe_translations.py"
        )
        assert len(failure_list) == 0, message
Пример #18
0
    def save_scenario(self, scenario_file_path=None):
        """Save current scenario to a text file.

        You can use the saved scenario with the batch runner.

        :param scenario_file_path: A path to the scenario file.
        :type scenario_file_path: str
        """
        # Validate Input
        warning_title = self.tr('InaSAFE Save Scenario Warning')
        is_valid, warning_message = self.validate_input()
        if not is_valid:
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(self, warning_title, warning_message)
            return

        # Make extent to look like:
        # 109.829170982, -8.13333290561, 111.005344795, -7.49226294379
        extent = viewport_geo_array(self.iface.mapCanvas())
        extent_string = ', '.join(('%f' % x) for x in extent)

        exposure_path = str(self.exposure_layer.publicSource())
        hazard_path = str(self.hazard_layer.publicSource())
        title = self.keyword_io.read_keywords(self.hazard_layer, 'title')
        title = safeTr(title)
        default_filename = title.replace(
            ' ', '_').replace('(', '').replace(')', '')

        # Popup a dialog to request the filename if scenario_file_path = None
        dialog_title = self.tr('Save Scenario')
        if scenario_file_path is None:
            # noinspection PyCallByClass,PyTypeChecker
            scenario_file_path = str(
                QFileDialog.getSaveFileName(
                    self,
                    dialog_title,
                    os.path.join(
                        self.output_directory,
                        default_filename + '.txt'),
                    "Text files (*.txt)"))
        if scenario_file_path is None or scenario_file_path == '':
            return
        self.output_directory = os.path.dirname(scenario_file_path)

        # Get relative path for each layer
        relative_exposure_path = self.relative_path(
            scenario_file_path, exposure_path)
        relative_hazard_path = self.relative_path(
            scenario_file_path, hazard_path)

        #  Write to file
        parser = ConfigParser()
        parser.add_section(title)
        parser.set(title, 'exposure', relative_exposure_path)
        parser.set(title, 'hazard', relative_hazard_path)
        parser.set(title, 'function', self.function_id)
        parser.set(title, 'extent', extent_string)
        if self.aggregation_layer is not None:
            aggregation_path = str(self.aggregation_layer.publicSource())
            relative_aggregation_path = self.relative_path(
                scenario_file_path, aggregation_path)
            parser.set(title, 'aggregation', relative_aggregation_path)

        try:
            parser.write(open(scenario_file_path, 'a'))
        except IOError:
            # noinspection PyTypeChecker,PyCallByClass,PyArgumentList
            QtGui.QMessageBox.warning(
                self,
                self.tr('InaSAFE'),
                self.tr('Failed to save scenario to ' + scenario_file_path))

        # Save State
        self.save_state()
Пример #19
0
    def _generateTables(self):
        """Parses the postprocessing output as one table per postprocessor.

        Args:
            None

        Returns:
            str - a string containing the html
        """
        myMessage = m.Message()

        for proc, resList in self.postProcessingOutput.iteritems():
            # resList is for example:
            # [
            #    (PyQt4.QtCore.QString(u'Entire area'), OrderedDict([
            #        (u'Total', {'value': 977536, 'metadata': {}}),
            #        (u'Female population', {'value': 508319, 'metadata': {}}),
            #        (u'Weekly hygiene packs', {'value': 403453, 'metadata': {
            #         'description': 'Females hygiene packs for weekly use'}})
            #    ]))
            #]
            try:
                #sorting using the first indicator of a postprocessor
                sortedResList = sorted(
                    resList,
                    key=self._sortNoData,
                    reverse=True)

            except KeyError:
                LOGGER.debug('Skipping sorting as the postprocessor did not '
                             'have a "Total" field')

            #init table
            hasNoDataValues = False
            myTable = m.Table(
                style_class='table table-condensed table-striped')
            myTable.caption = self.tr('Detailed %1 report').arg(safeTr(
                get_postprocessor_human_name(proc)).lower())

            myHeaderRow = m.Row()
            myHeaderRow.add(str(self.attributeTitle).capitalize())
            for calculationName in sortedResList[0][1]:
                myHeaderRow.add(self.tr(calculationName))
            myTable.add(myHeaderRow)

            for zoneName, calc in sortedResList:
                myRow = m.Row(zoneName)

                for _, calculationData in calc.iteritems():
                    myValue = calculationData['value']
                    if myValue == self.aggregator.defaults['NO_DATA']:
                        hasNoDataValues = True
                        myValue += ' *'
                    myRow.add(myValue)
                myTable.add(myRow)

            #add table to message
            myMessage.add(myTable)
            if hasNoDataValues:
                myMessage.add(m.EmphasizedText(self.tr(
                    '* "%1" values mean that there where some problems while '
                    'calculating them. This did not affect the other '
                    'values.').arg(self.aggregator.defaults['NO_DATA'])))

        try:
            if (self.keywordIO.read_keywords(
                    self.aggregator.layer, 'HAD_MULTIPART_POLY')):
                myMessage.add(m.EmphasizedText(self.tr(
                    'The aggregation layer had multipart polygons, these have '
                    'been exploded and are now marked with a #. This has no '
                    'influence on the calculation, just keep in mind that the '
                    'attributes shown may represent the original multipart '
                    'polygon and not the individual exploded polygon parts.')))
        except Exception:  # pylint: disable=W0703
            pass

        return myMessage
Пример #20
0
    def _generateTables(self):
        """Parses the postprocessing output as one table per postprocessor.

        Args:
            None

        Returns:
            str - a string containing the html
        """
        myMessage = m.Message()

        for proc, resList in self.postProcessingOutput.iteritems():
            # resList is for example:
            # [
            #    (PyQt4.QtCore.QString(u'Entire area'), OrderedDict([
            #        (u'Total', {'value': 977536, 'metadata': {}}),
            #        (u'Female population', {'value': 508319, 'metadata': {}}),
            #        (u'Weekly hygiene packs', {'value': 403453, 'metadata': {
            #         'description': 'Females hygiene packs for weekly use'}})
            #    ]))
            #]
            try:
                #sorting using the first indicator of a postprocessor
                sortedResList = sorted(resList,
                                       key=self._sortNoData,
                                       reverse=True)

            except KeyError:
                LOGGER.debug('Skipping sorting as the postprocessor did not '
                             'have a "Total" field')

            #init table
            hasNoDataValues = False
            myTable = m.Table(
                style_class='table table-condensed table-striped')
            myTable.caption = self.tr('Detailed %1 report').arg(
                safeTr(get_postprocessor_human_name(proc)).lower())

            myHeaderRow = m.Row()
            myHeaderRow.add(str(self.attributeTitle).capitalize())
            for calculationName in sortedResList[0][1]:
                myHeaderRow.add(self.tr(calculationName))
            myTable.add(myHeaderRow)

            for zoneName, calc in sortedResList:
                myRow = m.Row(zoneName)

                for _, calculationData in calc.iteritems():
                    myValue = calculationData['value']
                    if myValue == self.aggregator.defaults['NO_DATA']:
                        hasNoDataValues = True
                        myValue += ' *'
                    myRow.add(myValue)
                myTable.add(myRow)

            #add table to message
            myMessage.add(myTable)
            if hasNoDataValues:
                myMessage.add(
                    m.EmphasizedText(
                        self.
                        tr('* "%1" values mean that there where some problems while '
                           'calculating them. This did not affect the other '
                           'values.').arg(
                               self.aggregator.defaults['NO_DATA'])))

        try:
            if (self.keywordIO.read_keywords(self.aggregator.layer,
                                             'HAD_MULTIPART_POLY')):
                myMessage.add(
                    m.EmphasizedText(
                        self.
                        tr('The aggregation layer had multipart polygons, these have '
                           'been exploded and are now marked with a #. This has no '
                           'influence on the calculation, just keep in mind that the '
                           'attributes shown may represent the original multipart '
                           'polygon and not the individual exploded polygon parts.'
                           )))
        except Exception:  # pylint: disable=W0703
            pass

        return myMessage
Пример #21
0
def impactLayerAttribution(theKeywords, theInaSAFEFlag=False):
    """Make a little table for attribution of data sources used in impact.

    Args:
        * theKeywords: dict{} - a keywords dict for an impact layer.
        * theInaSAFEFlag: bool - whether to show a little InaSAFE promotional
            text in the attribution output. Defaults to False.

    Returns:
        str: an html snippet containing attribution information for the impact
            layer. If no keywords are present or no appropriate keywords are
            present, None is returned.

    Raises:
        None
    """
    if theKeywords is None:
        return None
    myReport = ''
    myJoinWords = ' - %s ' % tr('sourced from')
    myHazardDetails = tr('Hazard details')
    myHazardTitleKeyword = 'hazard_title'
    myHazardSourceKeyword = 'hazard_source'
    myExposureDetails = tr('Exposure details')
    myExposureTitleKeyword = 'exposure_title'
    myExposureSourceKeyword = 'exposure_source'

    if myHazardTitleKeyword in theKeywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardTitle = safeTr(theKeywords[myHazardTitleKeyword])
    else:
        myHazardTitle = tr('Hazard layer')

    if myHazardSourceKeyword in theKeywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardSource = safeTr(theKeywords[myHazardSourceKeyword])
    else:
        myHazardSource = tr('an unknown source')

    if myExposureTitleKeyword in theKeywords:
        myExposureTitle = theKeywords[myExposureTitleKeyword]
    else:
        myExposureTitle = tr('Exposure layer')

    if myExposureSourceKeyword in theKeywords:
        myExposureSource = theKeywords[myExposureSourceKeyword]
    else:
        myExposureSource = tr('an unknown source')

    myReport += ('<table class="table table-striped condensed'
                 ' bordered-table">')
    myReport += '<tr><th>%s</th></tr>' % myHazardDetails
    myReport += '<tr><td>%s%s %s.</td></tr>' % (
        myHazardTitle,
        myJoinWords,
        myHazardSource)

    myReport += '<tr><th>%s</th></tr>' % myExposureDetails
    myReport += '<tr><td>%s%s %s.</td></tr>' % (
        myExposureTitle,
        myJoinWords,
        myExposureSource)

    if theInaSAFEFlag:
        myReport += '<tr><th>%s</th></tr>' % tr('Software notes')
        myInaSAFEPhrase = tr('This report was created using InaSAFE '
                              'version %1. Visit http://inasafe.org to get '
                              'your free copy of this software!').arg(
                                get_version())
        myInaSAFEPhrase += tr('InaSAFE has been jointly developed by'
                               ' BNPB, AusAid & the World Bank')
        myReport += '<tr><td>%s</td></tr>' % myInaSAFEPhrase

    myReport += '</table>'

    return myReport
Пример #22
0
def impact_attribution(keywords, inasafe_flag=False):
    """Make a little table for attribution of data sources used in impact.

    :param keywords: A keywords dict for an impact layer.
    :type keywords: dict

    :param inasafe_flag: bool - whether to show a little InaSAFE promotional
        text in the attribution output. Defaults to False.

    :returns: An html snippet containing attribution information for the impact
        layer. If no keywords are present or no appropriate keywords are
        present, None is returned.
    :rtype: safe.messaging.Message
    """
    if keywords is None:
        return None

    join_words = ' - %s ' % tr('sourced from')
    hazard_details = tr('Hazard details')
    hazard_title_keywords = 'hazard_title'
    hazard_source_keywords = 'hazard_source'
    exposure_details = tr('Exposure details')
    exposure_title_keywords = 'exposure_title'
    exposure_source_keyword = 'exposure_source'

    if hazard_title_keywords in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        hazard_title = safeTr(keywords[hazard_title_keywords])
    else:
        hazard_title = tr('Hazard layer')

    if hazard_source_keywords in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        hazard_source = safeTr(keywords[hazard_source_keywords])
    else:
        hazard_source = tr('an unknown source')

    if exposure_title_keywords in keywords:
        exposure_title = keywords[exposure_title_keywords]
    else:
        exposure_title = tr('Exposure layer')

    if exposure_source_keyword in keywords:
        exposure_source = keywords[exposure_source_keyword]
    else:
        exposure_source = tr('an unknown source')

    report = m.Message()
    report.add(m.Heading(hazard_details, **INFO_STYLE))
    report.add(m.Paragraph(
        hazard_title,
        join_words,
        hazard_source))

    report.add(m.Heading(exposure_details, **INFO_STYLE))
    report.add(m.Paragraph(
        exposure_title,
        join_words,
        exposure_source))

    if inasafe_flag:
        report.add(m.Heading(tr('Software notes'), **INFO_STYLE))
        # noinspection PyUnresolvedReferences
        inasafe_phrase = tr(
            'This report was created using InaSAFE version %s. Visit '
            'http://inasafe.org to get your free copy of this software!'
            'InaSAFE has been jointly developed by BNPB, AusAid/AIFDRR & the '
            'World Bank') % (get_version())

        report.add(m.Paragraph(m.Text(inasafe_phrase)))
    return report
Пример #23
0
def impact_attribution(keywords, inasafe_flag=False):
    """Make a little table for attribution of data sources used in impact.

    :param keywords: A keywords dict for an impact layer.
    :type keywords: dict

    :param inasafe_flag: bool - whether to show a little InaSAFE promotional
        text in the attribution output. Defaults to False.

    :returns: An html snippet containing attribution information for the impact
        layer. If no keywords are present or no appropriate keywords are
        present, None is returned.
    :rtype: str
    """
    if keywords is None:
        return None

    myJoinWords = ' - %s ' % tr('sourced from')
    myHazardDetails = tr('Hazard details')
    myHazardTitleKeyword = 'hazard_title'
    myHazardSourceKeyword = 'hazard_source'
    myExposureDetails = tr('Exposure details')
    myExposureTitleKeyword = 'exposure_title'
    myExposureSourceKeyword = 'exposure_source'

    if myHazardTitleKeyword in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardTitle = safeTr(keywords[myHazardTitleKeyword])
    else:
        myHazardTitle = tr('Hazard layer')

    if myHazardSourceKeyword in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardSource = safeTr(keywords[myHazardSourceKeyword])
    else:
        myHazardSource = tr('an unknown source')

    if myExposureTitleKeyword in keywords:
        myExposureTitle = keywords[myExposureTitleKeyword]
    else:
        myExposureTitle = tr('Exposure layer')

    if myExposureSourceKeyword in keywords:
        myExposureSource = keywords[myExposureSourceKeyword]
    else:
        myExposureSource = tr('an unknown source')

    myReport = m.Message()
    myReport.add(m.Heading(myHazardDetails, **INFO_STYLE))
    myReport.add(m.Paragraph(
        myHazardTitle,
        myJoinWords,
        myHazardSource))

    myReport.add(m.Heading(myExposureDetails, **INFO_STYLE))
    myReport.add(m.Paragraph(
        myExposureTitle,
        myJoinWords,
        myExposureSource))

    if inasafe_flag:
        myReport.add(m.Heading(tr('Software notes'), **INFO_STYLE))
        myInaSAFEPhrase = tr(
            'This report was created using InaSAFE version %1. Visit '
            'http://inasafe.org to get your free copy of this software!'
            'InaSAFE has been jointly developed by BNPB, AusAid/AIFDRR & the '
            'World Bank').arg(get_version())

        myReport.add(m.Paragraph(m.Text(myInaSAFEPhrase)))
    return myReport
Пример #24
0
    def _generate_tables(self):
        """Parses the postprocessing output as one table per postprocessor.

        TODO: This should rather return json and then have a helper method to
        make html from the JSON.

        :returns: The html.
        :rtype: str
        """
        message = m.Message()

        for processor, results_list in self.output.iteritems():

            self.current_output_postprocessor = processor
            # results_list is for example:
            # [
            #    (PyQt4.QtCore.QString(u'Entire area'), OrderedDict([
            #        (u'Total', {'value': 977536, 'metadata': {}}),
            #        (u'Female population', {'value': 508319, 'metadata': {}}),
            #        (u'Weekly hygiene packs', {'value': 403453, 'metadata': {
            #         'description': 'Females hygiene packs for weekly use'}})
            #    ]))
            #]

            #sorting using the first indicator of a postprocessor
            sorted_results = sorted(
                results_list,
                key=self._sort_no_data,
                reverse=True)

            #init table
            has_no_data = False
            table = m.Table(
                style_class='table table-condensed table-striped')
            table.caption = self.tr('Detailed %s report') % (safeTr(
                get_postprocessor_human_name(processor)).lower())

            header = m.Row()
            header.add(str(self.attribute_title).capitalize())
            for calculation_name in sorted_results[0][1]:
                header.add(self.tr(calculation_name))
            table.add(header)

            # used to calculate the totals row as per issue #690
            postprocessor_totals = OrderedDict()

            for zone_name, calc in sorted_results:
                row = m.Row(zone_name)

                for indicator, calculation_data in calc.iteritems():
                    value = calculation_data['value']
                    if value == self.aggregator.defaults['NO_DATA']:
                        has_no_data = True
                        value += ' *'
                        try:
                            postprocessor_totals[indicator] += 0
                        except KeyError:
                            postprocessor_totals[indicator] = 0
                    else:
                        try:
                            postprocessor_totals[indicator] += int(value)
                        except KeyError:
                            postprocessor_totals[indicator] = int(value)
                    row.add(value)
                table.add(row)

            # add the totals row
            row = m.Row(self.tr('Total in aggregation areas'))
            for _, total in postprocessor_totals.iteritems():
                row.add(str(total))
            table.add(row)

            # add table to message
            message.add(table)
            if has_no_data:
                message.add(m.EmphasizedText(self.tr(
                    '* "%s" values mean that there where some problems while '
                    'calculating them. This did not affect the other '
                    'values.') % (self.aggregator.defaults['NO_DATA'])))

        return message
    def build_widget(self, form_layout, name, key_value):
        """Create a new form element dynamically based from theValue type.
        The element will be inserted to theFormLayout.

        :param form_layout: Mandatory a layout instance
        :type form_layout: QFormLayout

        :param name: Mandatory string referencing the key in the function
         configurable parameters dictionary.
        :type name: str

        :param key_value: Mandatory representing the value referenced by the
         key.
        :type key_value: object

        :returns: a function that return the value of widget

        :raises: None
        """

        # create label
        if isinstance(name, str):
            label = QLabel()
            label.setObjectName(_fromUtf8(name + "Label"))
            label_text = name.replace('_', ' ').capitalize()
            label.setText(safeTr(label_text))
            label.setToolTip(str(type(key_value)))
        else:
            label = name

        # create widget based on the type of key_value variable
        # if widget is a QLineEdit, value needs to be set
        # if widget is NOT a QLineEdit, property_name needs to be set
        value = None
        property_name = None

        # can be used for widgets that have their own text like QCheckBox
        hide_label = False

        if isinstance(key_value, list):
            widget = QLineEdit()
            value = ', '.join([str(x) for x in key_value])
            # NOTE: we assume that all element in list have same type
            value_type = type(key_value[0])
            function = lambda z: [value_type(y) for y in str(z).split(',')]
        elif isinstance(key_value, dict):
            widget = QLineEdit()
            value = str(key_value)
            function = lambda z: ast.literal_eval(str(z))
        elif isinstance(key_value, bool):
            widget = QCheckBox()
            widget.setChecked(key_value)
            widget.setText(label.text())
            property_name = 'checked'
            function = bool
            hide_label = True
        else:
            widget = QLineEdit()
            value = str(key_value)
            function = type(key_value)

        if hide_label:
            form_layout.addRow(widget)
        else:
            form_layout.addRow(label, widget)

        if type(widget) is QLineEdit:
            widget.setText(value)
            property_name = 'text'

        return self.bind(widget, property_name, function)
Пример #26
0
    def build_widget(self, form_layout, name, key_value):
        """Create a new form element dynamically based from theValue type.
        The element will be inserted to theFormLayout.

        :param form_layout: Mandatory a layout instance
        :type form_layout: QFormLayout

        :param name: Mandatory string referencing the key in the function
         configurable parameters dictionary.
        :type name: str

        :param key_value: Mandatory representing the value referenced by the
         key.
        :type key_value: object

        :returns: a function that return the value of widget

        :raises: None
        """

        # create label
        if isinstance(name, str):
            label = QLabel()
            label.setObjectName(_fromUtf8(name + "Label"))
            label_text = name.replace('_', ' ').capitalize()
            label.setText(safeTr(label_text))
            label.setToolTip(str(type(key_value)))
        else:
            label = name

        # create widget based on the type of key_value variable
        # if widget is a QLineEdit, value needs to be set
        # if widget is NOT a QLineEdit, property_name needs to be set
        value = None
        property_name = None

        # can be used for widgets that have their own text like QCheckBox
        hide_label = False

        if isinstance(key_value, list):
            widget = QLineEdit()
            value = ', '.join([str(x) for x in key_value])
            # NOTE: we assume that all element in list have same type
            value_type = type(key_value[0])
            function = lambda x: [value_type(y) for y in str(x).split(',')]
        elif isinstance(key_value, dict):
            widget = QLineEdit()
            value = str(key_value)
            function = lambda x: ast.literal_eval(str(x))
        elif isinstance(key_value, bool):
            widget = QCheckBox()
            widget.setChecked(key_value)
            widget.setText(label.text())
            property_name = 'checked'
            function = bool
            hide_label = True
        else:
            widget = QLineEdit()
            value = str(key_value)
            function = type(key_value)

        if hide_label:
            form_layout.addRow(widget)
        else:
            form_layout.addRow(label, widget)

        # are we dealing with a QLineEdit?
        if value is not None:
            widget.setText(value)
            property_name = 'text'

        return self.bind(widget, property_name, function)
Пример #27
0
def impact_attribution(keywords, inasafe_flag=False):
    """Make a little table for attribution of data sources used in impact.

    :param keywords: A keywords dict for an impact layer.
    :type keywords: dict

    :param inasafe_flag: bool - whether to show a little InaSAFE promotional
        text in the attribution output. Defaults to False.

    :returns: An html snippet containing attribution information for the impact
        layer. If no keywords are present or no appropriate keywords are
        present, None is returned.
    :rtype: safe.messaging.Message
    """
    if keywords is None:
        return None

    join_words = ' - %s ' % tr('sourced from')
    hazard_details = tr('Hazard details')
    hazard_title_keywords = 'hazard_title'
    hazard_source_keywords = 'hazard_source'
    exposure_details = tr('Exposure details')
    exposure_title_keywords = 'exposure_title'
    exposure_source_keyword = 'exposure_source'

    if hazard_title_keywords in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        hazard_title = safeTr(keywords[hazard_title_keywords])
    else:
        hazard_title = tr('Hazard layer')

    if hazard_source_keywords in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        hazard_source = safeTr(keywords[hazard_source_keywords])
    else:
        hazard_source = tr('an unknown source')

    if exposure_title_keywords in keywords:
        exposure_title = keywords[exposure_title_keywords]
    else:
        exposure_title = tr('Exposure layer')

    if exposure_source_keyword in keywords:
        exposure_source = keywords[exposure_source_keyword]
    else:
        exposure_source = tr('an unknown source')

    report = m.Message()
    report.add(m.Heading(hazard_details, **INFO_STYLE))
    report.add(m.Paragraph(hazard_title, join_words, hazard_source))

    report.add(m.Heading(exposure_details, **INFO_STYLE))
    report.add(m.Paragraph(exposure_title, join_words, exposure_source))

    if inasafe_flag:
        report.add(m.Heading(tr('Software notes'), **INFO_STYLE))
        # noinspection PyUnresolvedReferences
        inasafe_phrase = tr(
            'This report was created using InaSAFE version %s. Visit '
            'http://inasafe.org to get your free copy of this software!'
            'InaSAFE has been jointly developed by BNPB, AusAid/AIFDRR & the '
            'World Bank') % (get_version())

        report.add(m.Paragraph(m.Text(inasafe_phrase)))
    return report
Пример #28
0
def impact_attribution(keywords, inasafe_flag=False):
    """Make a little table for attribution of data sources used in impact.

    :param keywords: A keywords dict for an impact layer.
    :type keywords: dict

    :param inasafe_flag: bool - whether to show a little InaSAFE promotional
        text in the attribution output. Defaults to False.

    :returns: An html snippet containing attribution information for the impact
        layer. If no keywords are present or no appropriate keywords are
        present, None is returned.
    :rtype: str
    """
    if keywords is None:
        return None

    myJoinWords = ' - %s ' % tr('sourced from')
    myHazardDetails = tr('Hazard details')
    myHazardTitleKeyword = 'hazard_title'
    myHazardSourceKeyword = 'hazard_source'
    myExposureDetails = tr('Exposure details')
    myExposureTitleKeyword = 'exposure_title'
    myExposureSourceKeyword = 'exposure_source'

    if myHazardTitleKeyword in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardTitle = safeTr(keywords[myHazardTitleKeyword])
    else:
        myHazardTitle = tr('Hazard layer')

    if myHazardSourceKeyword in keywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardSource = safeTr(keywords[myHazardSourceKeyword])
    else:
        myHazardSource = tr('an unknown source')

    if myExposureTitleKeyword in keywords:
        myExposureTitle = keywords[myExposureTitleKeyword]
    else:
        myExposureTitle = tr('Exposure layer')

    if myExposureSourceKeyword in keywords:
        myExposureSource = keywords[myExposureSourceKeyword]
    else:
        myExposureSource = tr('an unknown source')

    myReport = m.Message()
    myReport.add(m.Heading(myHazardDetails, **INFO_STYLE))
    myReport.add(m.Paragraph(myHazardTitle, myJoinWords, myHazardSource))

    myReport.add(m.Heading(myExposureDetails, **INFO_STYLE))
    myReport.add(m.Paragraph(myExposureTitle, myJoinWords, myExposureSource))

    if inasafe_flag:
        myReport.add(m.Heading(tr('Software notes'), **INFO_STYLE))
        myInaSAFEPhrase = tr(
            'This report was created using InaSAFE version %1. Visit '
            'http://inasafe.org to get your free copy of this software!'
            'InaSAFE has been jointly developed by BNPB, AusAid/AIFDRR & the '
            'World Bank').arg(get_version())

        myReport.add(m.Paragraph(m.Text(myInaSAFEPhrase)))
    return myReport
Пример #29
0
    def save_scenario(self, scenario_file_path=None):
        """Save current scenario to a text file.

        You can use the saved scenario with the batch runner.

        :param scenario_file_path: A path to the scenario file.
        :type scenario_file_path: str
        """
        # Validate Input
        warning_title = self.tr('InaSAFE Save Scenario Warning')
        is_valid, warning_message = self.validate_input()
        if not is_valid:
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(self, warning_title, warning_message)
            return

        # Make extent to look like:
        # 109.829170982, -8.13333290561, 111.005344795, -7.49226294379

        # Added in 2.2 to support user defined analysis extents
        if self.dock.user_extent is not None \
                and self.dock.user_extent_crs is not None:
            extent = extent_to_array(self.dock.user_extent,
                                     self.dock.user_extent_crs)
        else:
            extent = viewport_geo_array(self.iface.mapCanvas())
        extent_string = ', '.join(('%f' % x) for x in extent)

        exposure_path = str(self.exposure_layer.publicSource())
        hazard_path = str(self.hazard_layer.publicSource())
        title = self.keyword_io.read_keywords(self.hazard_layer, 'title')
        title = safeTr(title)
        default_filename = title.replace(' ',
                                         '_').replace('(',
                                                      '').replace(')', '')

        # Popup a dialog to request the filename if scenario_file_path = None
        dialog_title = self.tr('Save Scenario')
        if scenario_file_path is None:
            # noinspection PyCallByClass,PyTypeChecker
            scenario_file_path = str(
                QFileDialog.getSaveFileName(
                    self, dialog_title,
                    os.path.join(self.output_directory,
                                 default_filename + '.txt'),
                    "Text files (*.txt)"))
        if scenario_file_path is None or scenario_file_path == '':
            return
        self.output_directory = os.path.dirname(scenario_file_path)

        # Get relative path for each layer
        relative_exposure_path = self.relative_path(scenario_file_path,
                                                    exposure_path)
        relative_hazard_path = self.relative_path(scenario_file_path,
                                                  hazard_path)

        #  Write to file
        parser = ConfigParser()
        parser.add_section(title)
        parser.set(title, 'exposure', relative_exposure_path)
        parser.set(title, 'hazard', relative_hazard_path)
        parser.set(title, 'function', self.function_id)
        parser.set(title, 'extent', extent_string)
        parser.set(title, 'extent_crs', self.dock.user_extent_crs.authid())
        if self.aggregation_layer is not None:
            aggregation_path = str(self.aggregation_layer.publicSource())
            relative_aggregation_path = self.relative_path(
                scenario_file_path, aggregation_path)
            parser.set(title, 'aggregation', relative_aggregation_path)

        try:
            parser.write(open(scenario_file_path, 'a'))
        except IOError:
            # noinspection PyTypeChecker,PyCallByClass,PyArgumentList
            QtGui.QMessageBox.warning(
                self, self.tr('InaSAFE'),
                self.tr('Failed to save scenario to ' + scenario_file_path))

        # Save State
        self.save_state()
Пример #30
0
    def _generateTables(self):
        """Parses the postprocessing output as one table per postprocessor.

        Args:
            None

        Returns:
            str - a string containing the html
        """
        myMessage = m.Message()

        for proc, results_list in self.postProcessingOutput.iteritems():

            self._currentOutputPostprocessor = proc
            # results_list is for example:
            # [
            #    (PyQt4.QtCore.QString(u'Entire area'), OrderedDict([
            #        (u'Total', {'value': 977536, 'metadata': {}}),
            #        (u'Female population', {'value': 508319, 'metadata': {}}),
            #        (u'Weekly hygiene packs', {'value': 403453, 'metadata': {
            #         'description': 'Females hygiene packs for weekly use'}})
            #    ]))
            #]

            #sorting using the first indicator of a postprocessor
            sortedResList = sorted(
                results_list,
                key=self._sortNoData,
                reverse=True)

            #init table
            hasNoDataValues = False
            myTable = m.Table(
                style_class='table table-condensed table-striped')
            myTable.caption = self.tr('Detailed %s report') % (safeTr(
                get_postprocessor_human_name(proc)).lower())

            myHeaderRow = m.Row()
            myHeaderRow.add(str(self.attributeTitle).capitalize())
            for calculationName in sortedResList[0][1]:
                myHeaderRow.add(self.tr(calculationName))
            myTable.add(myHeaderRow)

            for zoneName, calc in sortedResList:
                myRow = m.Row(zoneName)

                for _, calculationData in calc.iteritems():
                    myValue = calculationData['value']
                    if myValue == self.aggregator.defaults['NO_DATA']:
                        hasNoDataValues = True
                        myValue += ' *'
                    myRow.add(myValue)
                myTable.add(myRow)

            # add table to message
            myMessage.add(myTable)
            if hasNoDataValues:
                myMessage.add(m.EmphasizedText(self.tr(
                    '* "%s" values mean that there where some problems while '
                    'calculating them. This did not affect the other '
                    'values.') % (self.aggregator.defaults['NO_DATA'])))

        return myMessage
Пример #31
0
def impactLayerAttribution(theKeywords, theInaSAFEFlag=False):
    """Make a little table for attribution of data sources used in impact.

    Args:
        * theKeywords: dict{} - a keywords dict for an impact layer.
        * theInaSAFEFlag: bool - whether to show a little InaSAFE promotional
            text in the attribution output. Defaults to False.

    Returns:
        str: an html snippet containing attribution information for the impact
            layer. If no keywords are present or no appropriate keywords are
            present, None is returned.

    Raises:
        None
    """
    if theKeywords is None:
        return None
    myReport = ''
    myJoinWords = ' - %s ' % tr('sourced from')
    myHazardDetails = tr('Hazard details')
    myHazardTitleKeyword = 'hazard_title'
    myHazardSourceKeyword = 'hazard_source'
    myExposureDetails = tr('Exposure details')
    myExposureTitleKeyword = 'exposure_title'
    myExposureSourceKeyword = 'exposure_source'

    if myHazardTitleKeyword in theKeywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardTitle = safeTr(theKeywords[myHazardTitleKeyword])
    else:
        myHazardTitle = tr('Hazard layer')

    if myHazardSourceKeyword in theKeywords:
        # We use safe translation infrastructure for this one (rather than Qt)
        myHazardSource = safeTr(theKeywords[myHazardSourceKeyword])
    else:
        myHazardSource = tr('an unknown source')

    if myExposureTitleKeyword in theKeywords:
        myExposureTitle = theKeywords[myExposureTitleKeyword]
    else:
        myExposureTitle = tr('Exposure layer')

    if myExposureSourceKeyword in theKeywords:
        myExposureSource = theKeywords[myExposureSourceKeyword]
    else:
        myExposureSource = tr('an unknown source')

    myReport += ('<table class="table table-striped condensed'
                 ' bordered-table">')
    myReport += '<tr><th>%s</th></tr>' % myHazardDetails
    myReport += '<tr><td>%s%s %s.</td></tr>' % (myHazardTitle, myJoinWords,
                                                myHazardSource)

    myReport += '<tr><th>%s</th></tr>' % myExposureDetails
    myReport += '<tr><td>%s%s %s.</td></tr>' % (myExposureTitle, myJoinWords,
                                                myExposureSource)

    if theInaSAFEFlag:
        myReport += '<tr><th>%s</th></tr>' % tr('Software notes')
        myInaSAFEPhrase = tr('This report was created using InaSAFE '
                             'version %1. Visit http://inasafe.org to get '
                             'your free copy of this software!').arg(
                                 get_version())
        myInaSAFEPhrase += tr('InaSAFE has been jointly developed by'
                              ' BNPB, AusAid & the World Bank')
        myReport += '<tr><td>%s</td></tr>' % myInaSAFEPhrase

    myReport += '</table>'

    return myReport