def emit_pre_run_message(self): """Inform the user about parameters before starting the processing.""" title = tr('Processing started') details = tr( 'Please wait - processing may take a while depending on your ' 'hardware configuration and the analysis extents and data.') # trap for issue 706 try: exposure_name = self.exposure.name hazard_name = self.hazard.name # aggregation layer could be set to AOI so no check for that except AttributeError: title = tr('No valid layers') details = tr( 'Please ensure your hazard and exposure layers are set ' 'in the question area and then press run again.') message = m.Message(LOGO_ELEMENT, m.Heading(title, **WARNING_STYLE), m.Paragraph(details)) raise NoValidLayerError(message) text = m.Text( tr('This analysis will calculate the impact of'), m.EmphasizedText(hazard_name), tr('on'), m.EmphasizedText(exposure_name), ) if self.aggregation is not None: try: aggregation_name = self.aggregation.name # noinspection PyTypeChecker text.add( m.Text(tr('and bullet list the results'), m.ImportantText(tr('aggregated by')), m.EmphasizedText(aggregation_name))) except AttributeError: pass text.add('.') message = m.Message(LOGO_ELEMENT, m.Heading(title, **PROGRESS_UPDATE_STYLE), m.Paragraph(details), m.Paragraph(text)) try: # add which postprocessors will run when appropriated # noinspection PyTypeChecker post_processors_names = self.parameters['postprocessors'] post_processors = get_postprocessors(post_processors_names) message.add( m.Paragraph(tr('The following postprocessors will be used:'))) bullet_list = m.BulletedList() for name, post_processor in post_processors.iteritems(): bullet_list.add('%s: %s' % (get_postprocessor_human_name(name), post_processor.description())) message.add(bullet_list) except (TypeError, KeyError): # TypeError is for when function_parameters is none # KeyError is for when ['postprocessors'] is unavailable pass send_static_message(self, message)
def format_postprocessing(self): """Format postprocessing. :returns: The postprocessing. :rtype: safe.messaging.Message """ # List of post processor that can't be sum up. Issue #3118 no_total = ['Age', 'Gender', 'MinimumNeeds'] if not self.postprocessing: return False message = m.Message() for postprocessor, v in self.postprocessing.items(): table = m.Table(style_class='table table-condensed table-striped') table.caption = v['caption'] attributes = v['attributes'] if attributes: header = m.Row() # Bold and align left the 1st one. header.add(m.Cell(attributes[0], header=True, align='left')) for attribute in attributes[1:]: # Bold and align right. header.add(m.Cell(attribute, header=True, align='right')) if postprocessor not in no_total: header.add(m.Cell('Total', header=True, align='right')) table.add(header) for field in v['fields']: row = m.Row() # First column is string row.add(m.Cell(field[0])) total = 0 for value in field[1:]: try: val = int(value) total += val # Align right integers. row.add(m.Cell(self.format_int(val), align='right')) except ValueError: # Catch no data value. Align left strings. row.add(m.Cell(value, align='left')) if postprocessor not in no_total: row.add( m.Cell(self.format_int(round(total)), align='right')) table.add(row) message.add(table) for note in v['notes']: message.add(m.EmphasizedText(note)) return message
def ready_message(): """Helper to create a message indicating inasafe is ready. :returns Message: A localised message indicating we are ready to run. """ title = m.Heading(tr('Ready'), **PROGRESS_UPDATE_STYLE) notes = m.Paragraph( tr('You can now proceed to run your analysis by clicking the '), m.EmphasizedText(tr('Run'), **KEYWORD_STYLE), tr('button.')) message = m.Message(LOGO_ELEMENT, title, notes) return message
def _generate_tables(self, aoi_mode=True): """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. :param aoi_mode: adds a Total in aggregation areas row to the calculated table :type aoi_mode: bool :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') name = get_postprocessor_human_name(processor).lower() translated_name = tr(name) if name == 'building type': table.caption = tr('Closed buildings') elif name == 'road type': table.caption = tr('Closed roads') elif name == 'people': table.caption = tr('Affected people') # Dirty hack to make "evacuated" come out in the report. # Currently only MinimumNeeds that calculate from evacuation # percentage. if processor == 'MinimumNeeds': if 'evacuation_percentage' in self.function_parameters.keys(): table.caption = tr( 'Detailed %s report ' '(for people needing evacuation)') % translated_name else: table.caption = tr('Detailed %s report ' '(affected people)') % translated_name if processor in ['Gender', 'Age']: table.caption = tr('Detailed %s report ' '(affected people)') % translated_name empty_table = not sorted_results[0][1] if empty_table: # Due to an error? The table is empty. message.add(table) message.add( m.EmphasizedText( tr('Could not compute the %s report.') % translated_name)) continue 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() null_index = 0 # counting how many null value in the data for zone_name, calc in sorted_results: if isinstance(zone_name, QPyNullVariant): # I have made sure that the zone_name won't be Null in # run method. But just in case there is something wrong. zone_name = tr('Unnamed Area %s' % null_index) null_index += 1 if name == 'road type': # We add the unit 'meter' as we are counting roads. # proper format for i186 zone_name = tr('%(zone_name)s (m)') % { 'zone_name': tr(zone_name) } row = m.Row(zone_name) for indicator, calculation_data in calc.iteritems(): value = calculation_data['value'] value = str(unhumanize_number(value)) if value == self.aggregator.get_default_keyword('NO_DATA'): has_no_data = True try: postprocessor_totals[indicator] += 0 except KeyError: postprocessor_totals[indicator] = 0 else: value = int(value) try: postprocessor_totals[indicator] += value except KeyError: postprocessor_totals[indicator] = value row.add(format_int(value)) table.add(row) if not aoi_mode: # add the totals row row = m.Row(self.tr('Total in aggregation areas')) for _, total in postprocessor_totals.iteritems(): row.add(format_int(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.get_default_keyword('NO_DATA')))) caption = m.EmphasizedText( self.tr( 'Columns and rows containing only 0 or "%s" values are ' 'excluded from the tables.' % self.aggregator.get_default_keyword('NO_DATA'))) message.add(m.Paragraph(caption, style_class='caption')) return message
def _generate_tables(self, aoi_mode=True): """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. :param aoi_mode: adds a Total in aggregation areas row to the calculated table :type aoi_mode: bool :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') % (tr( get_postprocessor_human_name(processor)).lower()) # Dirty hack to make "evacuated" comes out in the report. # Currently only MinimumNeeds that calculate from evacuation # percentage. if processor == 'MinimumNeeds': if 'evacuation_percentage' in self.function_parameters.keys(): table.caption = self.tr( 'Detailed %s report (for people needing ' 'evacuation)') % ( tr(get_postprocessor_human_name(processor)).lower() ) else: table.caption = self.tr( 'Detailed %s report (affected people)') % ( tr(get_postprocessor_human_name(processor)).lower() ) if processor in ['Gender', 'Age']: table.caption = self.tr( 'Detailed %s report (affected people)') % ( tr(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'] value = str(unhumanize_number(value)) if value == self.aggregator.get_default_keyword('NO_DATA'): has_no_data = True value += ' *' try: postprocessor_totals[indicator] += 0 except KeyError: postprocessor_totals[indicator] = 0 else: value = int(value) try: postprocessor_totals[indicator] += value except KeyError: postprocessor_totals[indicator] = value row.add(format_int(value)) table.add(row) if not aoi_mode: # add the totals row row = m.Row(self.tr('Total in aggregation areas')) for _, total in postprocessor_totals.iteritems(): row.add(format_int(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.get_default_keyword( 'NO_DATA')))) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() paragraph = m.Paragraph(tr( 'This document describes the usage of the InaSAFE \'dock panel\'' '- which is an interface for running risk scenarios within the QGIS ' 'environment. If you are a new user, you may also consider using the ' '\'Impact Function Centric Wizard\' to run the analysis. You can ' 'launch the wizard by clicking on this icon in the toolbar:'), m.Image( 'file:///%s/img/icons/' 'show-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), ) message.add(paragraph) paragraph = m.Paragraph(tr( 'You can drag and drop the dock panel to reposition it in the user ' 'interface. For example, dragging the panel towards the right margin ' 'of the QGIS application will dock it to the right side of the screen.' )) message.add(paragraph) message.add(m.Paragraph(tr( 'There are three main areas to the dock panel:'))) bullets = m.BulletedList() bullets.add(tr('the Questions area')) bullets.add(tr('the Results area')) bullets.add(tr('the Buttons area')) message.add(bullets) message.add(m.Paragraph(tr( 'At any time you can obtain help in InaSAFE by clicking on the ' 'help buttons provided on each dock and dialog.'))) header = m.Heading(tr('The questions area'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr( 'The intention of InaSAFE is to make it really simple and easy to ' 'perform your impact analysis. The question area provides a simple ' 'way for you to formulate what it is you want to find out? All ' 'questions are formulated in the form:'), m.EmphasizedText(tr( 'In the event of a [hazard], how many [exposure] might be ' 'affected?')))) message.add(m.Paragraph(tr( 'For example: "If there is a flood, how many buildings might be ' 'affected?"'))) message.add(m.Paragraph(tr( 'In order to answer such questions, the InaSAFE developers have ' 'built a number of Impact Functions that cover scenarios such as ' 'flood, tsunami, volcanic fall, earthquake and so on.'))) message.add(m.Paragraph(tr( 'The formulation of these questions if carried out by loading layers ' 'into QGIS that represent either hazard scenarios or exposure data.' 'A hazard, for example, may be represented as, a raster layer in ' 'QGIS where each pixel in the raster represents the current flood ' 'depth following an inundation event. An exposure layer could be ' 'represented, for example, as vector polygon data representing ' 'building outlines, or a raster outline where each pixel represents ' 'the number of people thought to be resident in that cell.'))) message.add(m.Paragraph(tr( 'The impact function will combine these two input layers in a ' 'mathematical model in order to derive what the impacts of the ' 'hazard will be on the exposure infrastructure or people. By ' 'selecting a combination from the hazard and exposure combo boxes, ' 'an appropriate set of impact functions will be listed in the ' 'combo box. You may be wondering how the InaSAFE plugin determines ' 'whether a layer should be listed in the hazard or exposure combo ' 'boxes? The plugin relies on simple keyword metadata to be associated ' 'with each layer. You can define these keywords by selecting a layer ' 'and then clicking the InaSAFE Keywords Wizard icon on the toolbar: '), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr( 'The wizard will guide you through the process of defining the ' 'keywords for that layer.'))) message.add(m.Paragraph(tr( 'Based on the combination of hazard and exposure layers that are ' 'selected, the Impact Function list (shown in the combo box under ' '"Might" in the InaSAFE dock panel) will be updated. Each impact ' 'function can only work with specific combinations of hazard and ' 'exposure types, so the options shown here will be limited ' 'accordingly. The chosen impact function can be configured (if ' 'applicable) by pressing the small ellipses (...) button next to ' 'the chosen impact function. This is explained in more detail below ' 'under the heading "Setting Analysis Parameters".'))) message.add(m.Paragraph(tr( 'Aggregation is the process whereby we group the results of the ' 'analysis by district so that you can see how many people, roads or ' 'buildings were affected in each area. This will help you to ' 'understand where the most critical needs are. Aggregation is ' 'optional in InaSAFE - if you do not use aggregation, the entire ' 'analysis area will be used for the data summaries. Typically ' 'aggregation layers in InaSAFE have as attributes the name of the ' 'district or reporting area. It is also possible to use extended ' 'attributes to indicate the ratio of men and women; youth, adults ' 'and elderly living in each area. Where these are provided and the ' 'exposure layer is population, InaSAFE will provide a demographic ' 'breakdown per aggregation area indicating how many men, women etc. ' 'were probably affected in that area.' ))) header = m.Heading(tr('The results area'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr( 'After running an analysis, the question area is hidden to maximise ' 'the amount of space allocated to the results area. You can ' 're-open the question area at any time by pressing the "show question ' 'form" button.'))) message.add(m.Paragraph(tr( 'The Results area is used to display various useful feedback items to ' 'the user. Once an impact scenario has been run, a summary table will ' 'be shown.'))) message.add(m.Paragraph(tr( 'If you select an impact layer (i.e. a layer that was produced using ' 'an InaSAFE impact function), in the QGIS layers list, this summary ' 'will also be displayed in the results area. When you select a hazard ' 'or exposure layer in the QGIS layers list, the keywords for that ' 'layer will be shown in the Results area, making it easy to ' 'understand what metadata exists for that layer.'))) message.add(m.Paragraph(tr( 'The Results area is also used to display status information. For ' 'example, when a suitable combination of hazard, exposure and impact ' 'function are selected, the results area will be updated to indicate ' 'that you can proceed to run the impact scenario calculation. The Run ' 'Button will be activated.' ))) message.add(m.Paragraph(tr( 'Finally, the Results area is also used to display any error messages ' 'so that the user is informed as to what went wrong and why. You ' 'might want to scroll down a bit in the messaging window to view the ' 'message completely.' ))) message.add(m.Paragraph(tr( 'To have more space for the results available your Question is ' 'automatically hidden to make the results area as large as possible ' 'to display the results. If you want to have a look again what the ' 'question was that you formulated click on the Show question form ' 'button on top of the result area.' ))) message.add(m.Paragraph(tr( 'If you want to hide the question area again to have more space to ' 'display the results again, just make the Layer you just calculated ' 'with InaSAFE active again in the Layers list of QGIS.' ))) header = m.Heading(tr('The Buttons Area'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr( 'The buttons area contains four buttons:'))) bullets = m.BulletedList() bullets.add(m.Text( m.ImportantText(tr('Help')), tr( '- click on this if you need context help, such as the document ' 'you are reading right now!'))) bullets.add(m.Text( m.ImportantText(tr('About')), tr( '- click on this to see short credits for the InaSAFE project.'))) bullets.add(m.Text( m.ImportantText(tr('Help')), tr( 'Print... - click on this if you wish to create a pdf of your ' 'impact scenarion project or just generate report and open it in ' 'composer for further tuning. An impact layer must be active ' 'before the Print button will be enabled.'))) bullets.add(m.Text( m.ImportantText(tr('Run')), tr( '- Run - if the combination of options in the Questions area\'s ' 'combo boxes will allow you to run a scenario, this button is ' 'enabled.'))) message.add(bullets) header = m.Heading(tr('Data conversions'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr( 'When running a scenario, the data being used needs to be processed ' 'into a state where it is acceptable for use by the impact function. ' 'In particular it should be noted that:'))) bullets = m.BulletedList() bullets.add(tr( 'Remote datasets will be copied locally before processing.')) bullets.add(m.Text( tr( 'All datasets will be clipped to the intersection of the hazard ' 'layer, exposure layer and the current view extents unless ' 'you have specified a different clipping behaviour in the ' 'extents selector dialog.'), m.Image( 'file:///%s/img/icons/' 'set-extents-tool.svg' % resources_path(), **SMALL_ICON_STYLE) )) bullets.add(tr( 'All clipped datasets will be converted (reprojected) to Geographic ' '(EPSG:4326) coordinate reference system before analysis.')) message.add(bullets) header = m.Heading(tr('Analysis parameters'), **INFO_STYLE) message.add(header) # this adds the help content from the IF options dialog message.add(options()) header = m.Heading(tr('Generating impact reports'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr( 'When the scenario analysis completed you may want to generate a ' 'report. Usually the "Print..." button will be enabled immediately ' 'after analysis. Selecting an InaSAFE impact layer in QGIS Layers ' 'panel will also enable it.' ))) # This adds the help content of the print dialog message.add(report()) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() paragraph = m.Paragraph(m.Image('file:///%s/img/screenshots/' 'minimum-needs-screenshot.png' % resources_path()), style_class='text-center') message.add(paragraph) message.add( m.Paragraph( tr('During and after a disaster, providing for the basic human minimum ' 'needs of food, water, hygiene and shelter is an important element of ' 'your contingency plan. InaSAFE has a customisable minimum needs ' 'system that allows you to define country or region specific ' 'requirements for compiling a needs report where the exposure ' 'layer represents population.'))) message.add( m.Paragraph( tr('By default InaSAFE uses minimum needs defined for Indonesia - ' 'and ships with additional profiles for the Philippines and Tanzania. ' 'You can customise these or add your own region-specific profiles too.' ))) message.add( m.Paragraph( tr('Minimum needs are grouped into regional or linguistic \'profiles\'. ' 'The default profile is \'BNPB_en\' - the english profile for the ' 'national disaster agency in Indonesia. ' 'You will see that this profile defines requirements for displaced ' 'persons in terms of Rice, Drinking Water, Clean Water (for bathing ' 'etc.), Family Kits (with personal hygiene items) and provision of ' 'toilets.'))) message.add( m.Paragraph( tr('Each item in the profile can be customised or removed. For example ' 'selecting the first item in the list and then clicking on the ' '\'pencil\' icon will show the details of how it was defined. ' 'If you scroll up and down in the panel you will see that for each ' 'item, you can set a name, description, units (in singular, ' 'plural and abbreviated forms), specify maxima and minima for the ' 'quantity of item allowed, a default and a frequency. You would use ' 'the maxima and minima to ensure that disaster managers never ' 'allocate amounts that will not be sufficient for human livelihood, ' 'and also that will not overtax the logistics operation for those ' 'providing humanitarian relief.'))) message.add( m.Paragraph( tr('The final item in the item configuration is the \'readable ' 'sentence\' which bears special discussion. Using a simple system of ' 'tokens you can construct a sentence that will be used in the ' 'generated needs report.'))) message.add(m.Heading(tr('Minimum needs profiles'), **INFO_STYLE)) message.add( m.Paragraph( tr('A profile is a collection of resources that define the minimum needs ' 'for a particular country or region. Typically a profile should be ' 'based on a regional, national or international standard. The ' 'actual definition of which resources are needed in a given ' 'profile is dependent on the local conditions and customs for the ' 'area where the contingency plan is being devised.'))) message.add( m.Paragraph( tr('For example in the middle east, rice is a staple food whereas in ' 'South Africa, maize meal is a staple food and thus the contingency ' 'planning should take these localised needs into account.'))) message.add(m.Heading(tr('Minimum needs resources'), **INFO_STYLE)) message.add( m.Paragraph( tr('Each item in a minimum needs profile is a resource. Each resource ' 'is described as a simple natural language sentence e.g.:'))) message.add( m.EmphasizedText( tr('Each person should be provided with 2.8 kilograms of Rice weekly.' ))) message.add( m.Paragraph( tr('By clicking on a resource entry in the profile window, and then ' 'clicking the black pencil icon you will be able to edit the ' 'resource using the resource editor. Alternatively you can create a ' 'new resource for a profile by clicking on the black + icon in ' 'the profile manager. You can also remove any resource from a ' 'profile using the - icon in the profile manager.'))) message.add(m.Heading(tr('Resource Editor'), **INFO_STYLE)) message.add( m.Paragraph( tr('When switching to edit or add resource mode, the minimum needs ' 'manager will be updated to show the resource editor. Each ' 'resource is described in terms of:'))) bullets = m.BulletedList() bullets.add( m.Text(m.ImportantText(tr('resource name')), tr(' - e.g. Rice'))) bullets.add( m.Text(m.ImportantText(tr('a description of the resource')), tr(' - e.g. Basic food'))) bullets.add( m.Text(m.ImportantText(tr('unit in which the resource is provided')), tr(' - e.g. kilogram'))) bullets.add( m.Text(m.ImportantText(tr('pluralised form of the units')), tr(' - e.g. kilograms'))) bullets.add( m.Text(m.ImportantText(tr('abbreviation for the unit')), tr(' - e.g. kg'))) bullets.add( m.Text( m.ImportantText(tr('the default allocation for the resource')), tr(' - e.g. 2.8. This number can be overridden on a ' 'per-analysis basis'))) bullets.add( m.Text( m.ImportantText( tr('minimum allowed which is used to prevent allocating')), tr(' - e.g. no drinking water to displaced persons'))) bullets.add( m.ImportantText( tr('maximum allowed which is used to set a sensible upper ' 'limit for the resource'))) bullets.add( m.ImportantText( tr('a readable sentence which is used to compile the ' 'sentence describing the resource in reports.'))) message.add(bullets) message.add( m.Paragraph( tr('These parameters are probably all fairly self explanatory, but ' 'the readable sentence probably needs further detail. The ' 'sentence is compiled using a simple keyword token replacement ' 'system. The following tokens can be used:'))) bullets = m.BulletedList() bullets.add(m.Text('{{ Default }}')) bullets.add(m.Text('{{ Unit }}')) bullets.add(m.Text('{{ Units }}')) bullets.add(m.Text('{{ Unit abbreviation }}')) bullets.add(m.Text('{{ Resource name }}')) bullets.add(m.Text('{{ Frequency }}')) bullets.add(m.Text('{{ Minimum allowed }}')) bullets.add(m.Text('{{ Maximum allowed }}')) message.add(bullets) message.add( m.Paragraph( tr('When the token is placed in the sentence it will be replaced with ' 'the actual value at report generation time. This contrived example ' 'shows a tokenised sentence that includes all possible keywords:' ))) message.add( m.EmphasizedText( tr('A displaced person should be provided with {{ %s }} ' '{{ %s }}/{{ %s }}/{{ %s }} of {{ %s }}. Though no less than {{ %s }} ' 'and no more than {{ %s }}. This should be provided {{ %s }}.' % ('Default', 'Unit', 'Units', 'Unit abbreviation', 'Resource name', 'Minimum allowed', 'Maximum allowed', 'Frequency')))) message.add( m.Paragraph(tr('Would generate a human readable sentence like this:'))) message.add( m.ImportantText( tr('A displaced person should be provided with 2.8 kilogram/kilograms/kg ' 'of rice. Though no less than 0 and no more than 100. This should ' 'be provided daily.'))) message.add( m.Paragraph( tr('Once you have populated the resource elements, click the Save ' 'resource button to return to the profile view. You will see the ' 'new resource added in the profile\'s resource list.'))) message.add(m.Heading(tr('Managing profiles'), **INFO_STYLE)) message.add( m.Paragraph( tr('In addition to the profiles that come as standard with InaSAFE, you ' 'can create new ones, either from scratch, or based on an existing ' 'one (which you can then modify).'))) message.add( m.Paragraph( tr('Use the New button to create new profile. When prompted, give your ' 'profile a name e.g. \'JakartaProfile\'.'))) message.add( m.Paragraph( tr('Note: The profile must be saved in your home directory under ' '(QGIS profile path)/minimum_needs in order ' 'for InaSAFE to successfully ' 'detect it.'))) message.add( m.Paragraph( tr('An alternative way to create a new profile is to use the Save as to ' 'clone an existing profile. The clone profile can then be edited ' 'according to your specific needs.'))) message.add(m.Heading(tr('Active profile'), **INFO_STYLE)) message.add( m.Paragraph( tr('It is important to note, that which ever profile you select in the ' 'Profile pick list, will be considered active and will be used as ' 'the basis for all minimum needs analysis. You need to restart ' 'QGIS before the changed profile become active.'))) return message
def content(): """Helper method that returns just the content. This method was added so that the text could be reused in the dock_help module. .. versionadded:: 3.2.2 :returns: A message object without brand element. :rtype: safe.messaging.message.Message """ message = m.Message() paragraph = m.Paragraph( tr('InaSAFE is free software that produces realistic natural hazard ' 'impact scenarios for better planning, preparedness and response ' 'activities. It provides a simple but rigourous way to combine data ' 'from scientists, local governments and communities to provide ' 'insights into the likely impacts of future disaster events.')) message.add(paragraph) paragraph = m.Paragraph( tr('The InaSAFE \'dock panel\' helps you to run hazard impact analysis ' 'within the QGIS environment. It helps you create your hazard impact ' 'analysis question and shows the results of this analysis. If you are ' 'a new user, you may also consider using the \'Impact Function ' 'Centric Wizard\' to run the analysis. This wizard will guide you ' 'through the process of running an InaSAFE assessment, with ' 'interactive step by step instructions. You can launch the wizard ' 'by clicking on this icon in the toolbar:'), m.Image('file:///%s/img/icons/' 'show-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), ) message.add(paragraph) paragraph = m.Paragraph( tr('You can drag and drop the dock panel to reposition it on the screen. ' 'For example, dragging the panel towards the right margin of the QGIS ' 'application will dock it to the right side of the screen.')) message.add(paragraph) message.add( m.Paragraph(tr('There are three main areas to the dock panel:'))) bullets = m.BulletedList() bullets.add( m.Text( # format 'the __questions__ area' for proper i18n tr('the %s area') % (m.ImportantText(tr('questions')).to_html(), ))) bullets.add( m.Text( # format 'the __results__ area' for proper i18n tr('the %s area') % (m.ImportantText(tr('results')).to_html(), ))) bullets.add( m.Text( # format 'the __buttons__ area' for proper i18n tr('the %s area') % (m.ImportantText(tr('buttons')).to_html(), ))) message.add(bullets) message.add( m.Paragraph( tr('You can get help at any time in InaSAFE by clicking on the ' 'help buttons provided on each dock and dialog.'))) header = m.Heading(tr('The questions area'), **INFO_STYLE) message.add(header) message.add( m.Paragraph( tr('The intention of InaSAFE is to make it easy to perform your impact ' 'analysis. We start the analysis in the questions area. This area ' 'contains three drop down menus. You create your question by using ' 'these drop down menus to select the hazard and exposure data you ' 'wish to perform the analysis on. ' 'All questions follow this form:'), m.EmphasizedText( tr('In the event of a [hazard], how many [exposure] might be ' '[impacted]?')))) message.add( m.Paragraph( tr('For example: "If there is a flood, how many buildings might be ' 'flooded?"'))) message.add( m.Paragraph( tr('InaSAFE can be used to answer such questions for hazards such as ' 'flood, tsunami, volcanic ash fall and earthquake and exposures ' 'such as population, roads, structures, land cover etc.'))) message.add( m.Paragraph( tr('The first step in answering these questions is to load layers that ' 'represent either hazard scenarios or exposure data into QGIS. ' 'A hazard, for example, may be represented as a raster layer in ' 'QGIS where each pixel in the raster represents the flood depth ' 'following an inundation event. An exposure layer could be ' 'represented, for example, as vector polygon data representing ' 'building outlines, or a raster outline where each pixel represents ' 'the number of people thought to be living in that cell.'))) message.add( m.Paragraph( tr('InaSAFE will combine these two layers in a ' 'mathematical model. The results of this model will show what the ' 'effect of the hazard will be on the exposed infrastructure or ' 'people. The plugin relies on simple keyword metadata ' 'associated with each layer to determine what kind of information the ' 'layer represents. You can define these keywords by ' 'selecting a layer and then clicking the InaSAFE Keywords Wizard icon ' 'on the toolbar: '), m.Image( 'file:///%s/img/icons/' 'show-keyword-wizard.svg' % resources_path(), **SMALL_ICON_STYLE), tr('The wizard will guide you through the process of defining the ' 'keywords for that layer.'))) message.add( m.Paragraph( tr('Aggregation is the process whereby we group the analysis results ' 'by district so that you can see how many people, roads or ' 'buildings were affected in each area. This will help you to ' 'understand where the most critical needs are. Aggregation is ' 'optional in InaSAFE - if you do not use aggregation, the entire ' 'analysis area will be used for the data summaries. Typically ' 'aggregation layers in InaSAFE have the name of the district or ' 'reporting area as attributes. It is also possible to use extended ' 'attributes to indicate the ratio of men and women; youth, adults ' 'and elderly living in each area. Where these are provided and the ' 'exposure layer is population, InaSAFE will provide a demographic ' 'breakdown per aggregation area indicating how many men, women, etc. ' 'were probably affected in that area.'))) header = m.Heading(tr('The results area'), **INFO_STYLE) message.add(header) message.add( m.Paragraph( tr('After running an analysis, the question area is hidden to maximise ' 'the amount of space allocated to the results area. You can ' 're-open the question area at any time by pressing the \'show ' 'question form\' button.'))) message.add( m.Paragraph( tr('The results area is used to display various useful feedback items to ' 'the user. Once an impact scenario has been run, a summary table will ' 'be shown.'))) message.add( m.Paragraph( tr('If you select an impact layer (i.e. a layer that was produced using ' 'an InaSAFE Impact Function), in the QGIS layers list, this summary ' 'will also be displayed in the results area. When you select a hazard ' 'or exposure layer in the QGIS layers list, the keywords for that ' 'layer will be shown in the results area, making it easy to ' 'understand what metadata exists for that layer.'))) message.add( m.Paragraph( tr('The results area is also used to display status information. For ' 'example, during the analysis process, the status area will display ' 'notes about each step in the analysis process. The \'Run\' ' 'button will be activated when both a valid hazard and valid exposure ' 'layer have been added in QGIS.'))) message.add( m.Paragraph( tr('Finally, the results area is also used to display any error messages ' 'so that you can see what went wrong and why. You may need to ' 'scroll down to view the message completely to see all of the error ' 'message details.'))) message.add( m.Paragraph( tr('After running the impact scenario calculation, the question is ' 'automatically hidden to make the results area as large as possible. ' 'If you want to see what the question used in the analysis was, click ' 'on the \'Show question form\' button at the top of the results area.' ))) message.add( m.Paragraph( tr('If you want to hide the question area again to have more space to ' 'display the results, click on the layer you just calculated ' 'with InaSAFE in the Layers list of QGIS to make it active.'))) header = m.Heading(tr('The buttons area'), **INFO_STYLE) message.add(header) message.add(m.Paragraph(tr('The buttons area contains four buttons:'))) bullets = m.BulletedList() bullets.add( m.Text( m.ImportantText(tr('Help')), tr('- click on this if you need context help, such as the document ' 'you are reading right now!'))) bullets.add( m.Text( m.ImportantText(tr('About')), tr('- click on this to see short credits for the InaSAFE project.') )) bullets.add( m.Text( m.ImportantText(tr('Print')), tr('... - click on this if you wish to create a pdf of your ' 'impact scenario project or generate a report to open in ' 'composer for further tuning. An impact layer must be active ' 'before the \'Print\' button will be enabled.'))) bullets.add( m.Text( m.ImportantText(tr('Run')), tr('- this button is enabled when the combination of hazard and ' 'exposure selected in the questions area\'s drop down menus will ' 'allow you to run a scenario.'))) message.add(bullets) header = m.Heading(tr('Data conversions'), **INFO_STYLE) message.add(header) message.add( m.Paragraph( tr('When running a scenario, the data being used needs to be processed ' 'into a state where it is acceptable for use by InaSAFE. ' 'In particular it should be noted that:'))) bullets = m.BulletedList() bullets.add( tr('Remote datasets will be copied locally before processing.')) bullets.add( m.Text( tr('All datasets will be clipped to the behaviours defined in the ' 'analysis extents dialog if you do not use an aggregation layer.' ), m.Image( 'file:///%s/img/icons/' 'set-extents-tool.svg' % resources_path(), **SMALL_ICON_STYLE))) bullets.add( m.Text( tr('You can visualise the area that will be used for the analysis ' 'by enabling the "Toggle Scenario Outlines" tool. When this tool ' 'is enabled, a line (green by default) will be drawn around the ' 'outermost boundary of the analysis area.'), m.Image( 'file:///%s/img/icons/' 'toggle-rubber-bands.svg' % resources_path(), **SMALL_ICON_STYLE))) bullets.add( m.Text( tr('When you have selected an aggregation layer the analysis area ' 'will be the outline of the aggregation layer. If you select one ' 'or more polygons in the aggregation layer (by using the QGIS ' 'feature selection tools), the analysis boundary will be reduced ' 'to just the outline of these selected polygons. If the "Toggle ' 'Scenario Outlines" tool is enabled, the preview of the effective ' 'analysis area will be updated to reflect the selected features.' ), )) bullets.add( tr('All clipped datasets will be converted (reprojected) to the ' 'Coordinate Reference System of the exposure layer ' 'before analysis.')) message.add(bullets) header = m.Heading(tr('Generating impact reports'), **INFO_STYLE) message.add(header) message.add( m.Paragraph( tr('When the impact analysis has completed you may want to generate a ' 'report. Usually the \'Print...\' button will be enabled immediately ' 'after analysis. Selecting an InaSAFE impact layer in QGIS Layers ' 'panel will also enable it.'))) # This adds the help content of the print dialog message.add(report()) return message