示例#1
0
    def __init__(self, ms):
        """ constructor """
        super(MSTableModel, self).__init__(None)

        self.ms = ms
        self.valid_codes = self.ms.taxonomy.codes
        self.headers = [
            get_ui_string("widget.mod.tableheader.zone"),
            get_ui_string("widget.mod.tableheader.path"),
            get_ui_string("widget.mod.tableheader.value"),
            get_ui_string("widget.mod.tableheader.weight"),]
        self.modifiers = []
        self.row_count = 0        # total row count
        
        for zone, stat in self.ms.assignments():
            # get all modifier in the tree
            for node, idx, modifier in stat.get_modifiers(10):
                # each modifier has several values that will be listed in
                # different rows in the table
                # start_count / end_count are start/end row index for the table
                start_count = self.row_count
                self.row_count += len(modifier.keys())
                end_count = self.row_count
                # build the string containing path to the node 
                parent = node
                parent_str = []
                for i in range(node.level):                    
                    parent_str.append(str(parent.value))
                    # move up to next parent
                    parent = parent.parent
                # reverse to put root at the beginning
                parent_str.reverse()
                self.modifiers.append((zone.name, "/".join(parent_str),
                                       start_count, end_count,
                                       idx, modifier, node))
示例#2
0
 def deleteMSBranch(self, node):
     """ delete selected node and children from mapping scheme tree """
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.ms.processing"))
     self.project.ms.delete_branch(node)
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.modified"))
示例#3
0
 def loadProj(self):
     """ open file dialog to load an existing application """
     self.getOpenFileName(self, 
                          get_ui_string("app.window.msg.project.open"),
                          get_ui_string("app.extension.db"), 
                          self.openProjectFile)
     self.ui.statusbar.showMessage(get_ui_string("app.status.project.loaded"))
示例#4
0
    def closeProject(self):
        """ close opened project and update UI elements accordingly """
        # adjust UI in application window
        self.tab_result.closeAll()  # this call must happen first. 
                                    # otherwise, it locks temporary GIS files
        self.ui.mainTabs.setTabEnabled(self.TAB_DATA, False)            
        self.ui.mainTabs.setTabEnabled(self.TAB_MS, False)
        self.ui.mainTabs.setTabEnabled(self.TAB_MOD, False)               
        self.ui.mainTabs.setTabEnabled(self.TAB_RESULT, False) 
        self.showTab(self.TAB_DATA)
        # disable menu/menu items
        self.ui.actionSave.setEnabled(False)
        self.ui.actionSave_as.setEnabled(False)
        self.ui.actionMapping_Schemes.setEnabled(False)
        self.ui.actionResult.setEnabled(False)
        self.ui.actionProcessing_Options.setEnabled(False)

        if getattr(self, 'project', None) is not None:
            # save existing project is needed
            if self.project.require_save:
                ans = QMessageBox.question(self, 
                                           get_ui_string("app.window.msg.project.not_saved"),
                                           get_ui_string("app.window.msg.project.save_or_not"),
                                           buttons=QMessageBox.Yes|QMessageBox.No,
                                           defaultButton=QMessageBox.Yes)
                if ans == QMessageBox.Yes:
                    self.saveProj()
            
            # adjust UI in tabs 
            self.tab_datainput.closeProject()
            self.tab_ms.clearMappingScheme()
            self.tab_mod.closeMappingScheme()
            self.project.clean_up()           
            del self.project
            self.project = None
示例#5
0
    def setProcessingOptions(self):
        if self.project is None:                
            return

        # set options to be those defined in project
        self.proc_options.resetOptions()
        for attribute in dir(self.proc_options):
            try:
                proc_attribute = self.project.operator_options['proc.%s'%attribute]
                setattr(self.proc_options, attribute, proc_attribute)
            except:
                # for empty project, this is the first time proc.options is set
                # just use default from proc_option dialogbox
                pass
            
        if self.proc_options.exec_() == QDialog.Accepted:
            for attribute in dir(self.proc_options):                
                self.project.operator_options['proc.%s'%attribute] = getattr(self.proc_options, attribute)
            # alert user
            answer = QMessageBox.question(self,
                                         get_ui_string("app.confirm.title"),
                                         get_ui_string("app.confirm.build.exposure"),
                                         buttons = QMessageBox.No | QMessageBox.Yes,
                                         defaultButton=QMessageBox.No)
            if answer == QMessageBox.No:
                return
            self.buildExposure()
示例#6
0
 def appendMSBranch(self, node, branch):
     """ append a branch (from library) to a node in a mapping scheme tree """
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.ms.processing"))
     self.project.ms.append_branch(node, branch)
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.modified"))
示例#7
0
 def createEmptyMS(self):
     """ build an empty mapping scheme tree for user to manipulate manually """
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.processing"))
     # invoke asynchronously 
     invoke_async(get_ui_string("app.status.processing"), self.project.create_empty_ms)
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.created"))
示例#8
0
 def exportResults(self, export_format, export_path):
     """ export mapping scheme leaves as CSV """
     self.ui.statusbar.showMessage(get_ui_string("app.status.exposure.exported"))
     # invoke asynchronously
     self.project.set_export(export_format, export_path)        
     invoke_async(get_ui_string("app.status.processing"), self.project.export_data)
     self.ui.statusbar.showMessage(get_ui_string("app.status.exposure.exported"))
示例#9
0
    def setProcessingOptions(self):
        if self.project is None:
            return

        # set options to be those defined in project
        self.proc_options.resetOptions()
        for attribute in dir(self.proc_options):
            try:
                proc_attribute = self.project.operator_options['proc.%s' %
                                                               attribute]
                setattr(self.proc_options, attribute, proc_attribute)
            except:
                # for empty project, this is the first time proc.options is set
                # just use default from proc_option dialogbox
                pass

        if self.proc_options.exec_() == QDialog.Accepted:
            for attribute in dir(self.proc_options):
                self.project.operator_options['proc.%s' % attribute] = getattr(
                    self.proc_options, attribute)
            # alert user
            answer = QMessageBox.question(
                self,
                get_ui_string("app.confirm.title"),
                get_ui_string("app.confirm.build.exposure"),
                buttons=QMessageBox.No | QMessageBox.Yes,
                defaultButton=QMessageBox.No)
            if answer == QMessageBox.No:
                return
            self.buildExposure()
示例#10
0
 def loadMS(self, path):
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.ms.processing"))
     # invoke asynchronously
     invoke_async(get_ui_string("app.status.processing"),
                  self.project.load_ms, path)
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.created"))
示例#11
0
 def loadProj(self):
     """ open file dialog to load an existing application """
     self.getOpenFileName(self,
                          get_ui_string("app.window.msg.project.open"),
                          get_ui_string("app.extension.db"),
                          self.openProjectFile)
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.project.loaded"))
示例#12
0
 def exportMS(self, path, format):
     """ export mapping scheme leaves as CSV """
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.ms.processing"))
     # invoke asynchronously
     invoke_async(get_ui_string("app.status.processing"),
                  self.project.export_ms, path, format)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.exported"))
示例#13
0
 def createEmptyMS(self):
     """ build an empty mapping scheme tree for user to manipulate manually """
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.ms.processing"))
     # invoke asynchronously
     invoke_async(get_ui_string("app.status.processing"),
                  self.project.create_empty_ms)
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.created"))
示例#14
0
 def exportResults(self, export_format, export_path):
     """ export mapping scheme leaves as CSV """
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.exposure.exported"))
     # invoke asynchronously
     self.project.set_export(export_format, export_path)
     invoke_async(get_ui_string("app.status.processing"),
                  self.project.export_data)
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.exposure.exported"))
示例#15
0
 def buildMappingScheme(self):
     """ build mapping scheme with given data """
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.processing"))
     # invoke asynchronously
     try:
         invoke_async(get_ui_string("app.status.processing"), self.project.build_ms)
     except SIDDException as err:
         # different error message used in this case
         raise SIDDUIException(get_ui_string('project.error.sampling', str(err)))
     
     self.visualizeMappingScheme(self.project.ms)
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.created"))
示例#16
0
 def saveProjAs(self):
     if self.project is None:
         return
     filename = QFileDialog.getSaveFileName(
         self, get_ui_string("app.window.msg.project.create"),
         get_app_dir(), get_ui_string("app.extension.db"))
     # no need to check for file overwrite, because QFileDialog return always confirmed overwrite
     if not filename.isNull():
         filename = str(filename)
         self.project.set_project_path(filename)
         self.project.sync(SyncModes.Write)
         self.saveLastOpenDir(filename[0:filename.rfind("/")])
         self.ui.statusbar.showMessage(
             get_ui_string("app.status.project.saved"))
示例#17
0
 def saveProjAs(self):
     if self.project is None:
         return
     filename = QFileDialog.getSaveFileName(self,
                                            get_ui_string("app.window.msg.project.create"),
                                            get_app_dir(),
                                            get_ui_string("app.extension.db"))
     # no need to check for file overwrite, because QFileDialog return always confirmed overwrite       
     if not filename.isNull():
         filename = str(filename)
         self.project.set_project_path(filename)                
         self.project.sync(SyncModes.Write)
         self.saveLastOpenDir(filename[0:filename.rfind("/")])            
         self.ui.statusbar.showMessage(get_ui_string("app.status.project.saved"))                
示例#18
0
文件: wdg_data.py 项目: gem/sidd
    def showVerificationResults(self):
        """
        show the result of data verification
        """            
        NO_KEY = ":/imgs/icons/no.png"
        YES_KEY = ":/imgs/icons/yes.png"
        
        project = self.project # 
        if project is None or project.fp_type == FootprintTypes.None:
            self.ui.img_lb_verify_fp.setPixmap(QPixmap(NO_KEY))
        else:
            self.ui.img_lb_verify_fp.setPixmap(QPixmap(YES_KEY))

        if project is None or project.survey_type == SurveyTypes.None:
            self.ui.img_lb_verify_svy.setPixmap(QPixmap(NO_KEY))
        else:
            self.ui.img_lb_verify_svy.setPixmap(QPixmap(YES_KEY))
        
        if project is None or project.zone_type == ZonesTypes.None:
            self.ui.img_lb_verify_zones.setPixmap(QPixmap(NO_KEY))
        else:
            self.ui.img_lb_verify_zones.setPixmap(QPixmap(YES_KEY))
        
        if project is None or project.popgrid_type == PopGridTypes.None:
            self.ui.img_lb_verify_pop.setPixmap(QPixmap(NO_KEY))
        else:
            self.ui.img_lb_verify_pop.setPixmap(QPixmap(YES_KEY))        
            
        if project is None or project.output_type == OutputTypes.Grid:
            self.ui.img_lb_verify_agg_grid.setPixmap(QPixmap(YES_KEY))
            self.ui.img_lb_verify_agg_zone.setPixmap(QPixmap(NO_KEY))
        else:
            self.ui.img_lb_verify_agg_zone.setPixmap(QPixmap(YES_KEY))
            self.ui.img_lb_verify_agg_grid.setPixmap(QPixmap(NO_KEY))
        
        if project is None:
            self.ui.txt_verify_text.setText('') 
        elif project.status == ProjectStatus.ReadyForExposure:
            self.ui.txt_verify_text.setText(get_ui_string('widget.input.verify.sucess'))
        elif project.status == ProjectStatus.ReadyForMS:
            self.ui.txt_verify_text.setText(get_ui_string('widget.input.verify.datarequired'))
            # append error messages
            for err in project.errors:                
                errMsg = get_ui_string('project.error.%s' % str(err))
                if errMsg == '':
                    errMsg = get_ui_string('widget.input.verify.unknownerror')                 
                self.ui.txt_verify_text.append('-%s' % errMsg)
                                                                
        else: #project.status == ProjectStatus.NotVerified:
            self.ui.txt_verify_text.setText(get_ui_string('widget.input.verify.noaction'))            
示例#19
0
    def buildMappingScheme(self):
        """ build mapping scheme with given data """
        self.ui.statusbar.showMessage(
            get_ui_string("app.status.ms.processing"))
        # invoke asynchronously
        try:
            invoke_async(get_ui_string("app.status.processing"),
                         self.project.build_ms)
        except SIDDException as err:
            # different error message used in this case
            raise SIDDUIException(
                get_ui_string('project.error.sampling', str(err)))

        self.visualizeMappingScheme(self.project.ms)
        self.ui.statusbar.showMessage(get_ui_string("app.status.ms.created"))
示例#20
0
    def __init__(self, values, weights, parser, valid_codes, is_editable=[True, True]):
        """ constructor """
        super(MSLevelTableModel, self).__init__()

        # table header 
        self.headers = [
            get_ui_string('dlg.msbranch.edit.tableheader.value'),
            get_ui_string('dlg.msbranch.edit.tableheader.weight'),
            'Value', 'Weight (%)'
        ]        
        self.parser=parser
        self.valid_codes=valid_codes
        self.values, self.weights = self.do_sort(values, weights)
        self.is_editable = is_editable
        self.editable_indices = {}
示例#21
0
    def __init__(self, values, weights, parser, valid_codes, is_editable=[True, True]):
        """ constructor """
        super(MSLevelTableModel, self).__init__()

        # table header
        self.headers = [
            get_ui_string("dlg.msbranch.edit.tableheader.value"),
            get_ui_string("dlg.msbranch.edit.tableheader.weight"),
            "Value",
            "Weight (%)",
        ]
        self.parser = parser
        self.valid_codes = valid_codes
        self.values, self.weights = self.do_sort(values, weights)
        self.is_editable = is_editable
        self.editable_indices = {}
示例#22
0
    def editModifier(self):
        """ edit selected modifier """
        mod = self.getSelectedModifier()
        # make sure there is mod selected
        if mod is None:
            logUICall.log(get_ui_string("widget.ms.warning.node.required"),
                          logUICall.WARNING)
            return

        # show edit dialog box for selected modifier
        self.dlgEditMod.setNode(self.ms, mod)
        ans = self.dlgEditMod.exec_()

        # accepted means apply change
        if ans == QDialog.Accepted:
            # NOTE: dlgEditMod already should have performed all the checks on
            #       values/weights pair, we can safely assume that data is clean
            #       to be used
            #[zone_name, bldg_type, startIdx, endIdx, modidx, modifier, node] = mod
            if self.dlgEditMod.node is not None:
                modifier = StatisticModifier(self.dlgEditMod.modifier_name)
                for value, weight in map(None, self.dlgEditMod.values,
                                         self.dlgEditMod.weights):
                    modifier.values[value] = weight
                self.dlgEditMod.node.set_modifier(self.dlgEditMod.modidx,
                                                  modifier)
            self.app.visualizeMappingScheme(self.ms)
示例#23
0
    def createWizard(self):
        try:
            # should not update preview while using wizard
            self.setVisible(False)
            self.previewInput = False

            wizard = WidgetDataWizard(self,
                                      Project(self.app_config, self.taxonomy))
            if wizard.exec_() == QDialog.Accepted:
                # setProject makes call to GIS component that requires visibility
                self.setVisible(True)
                self.previewInput = True
                self.setProject(wizard.project)
                self.ui.statusbar.showMessage(
                    get_ui_string("app.status.project.created"))
            # else
            # do nothing?
        except:
            pass
        finally:
            # return to normal window
            # these calls are reached
            # 1. in case any exception occurs,
            # 2. wizard finished or cancelled
            self.setVisible(True)
            self.previewInput = True
示例#24
0
 def verifyData(self, item):
     """ 
     callback at each table value update. two checks
     - value is integer
     - range is valid with new value
     """
     item_val = item.data(Qt.DisplayRole)
     if item_val == QVariant('None'):
         return
     int_val = item_val.toInt()
     row, col = item.row(), item.column()        
     if int_val[1]:  # is integer            
         # set value
         self.range_values[col][row] = int_val[0]
         
         # allow set range only if is valid 
         range_is_valid = False
         try:
             range_is_valid = self.is_range_valid()
         except SIDDRangeGroupException as err:
             # error means not valid 
             self.ui.lb_notes.setText(err.message)
         except Exception as err:
             # error means not valid
             self.ui.lb_notes.setText(err.message)
         self.ui.buttons.button(QDialogButtonBox.Ok).setEnabled(range_is_valid)
     else:
         # not integer
         # restore
         logUICall.log(get_ui_string('dlg.attr.value.error'), logUICall.WARNING)
         self.ui.table_ranges.setItem(row, col, QTableWidgetItem('%s'%self.range_values[col][row]))
示例#25
0
 def createBlank(self):
     """ create a new project """
     # create new project file
     project = Project(self.app_config, self.taxonomy)
     # open project and sync UI
     self.setProject(project, skipVerify=True)
     self.ui.statusbar.showMessage(get_ui_string("app.status.project.created"))
示例#26
0
    def mapEditTheme(self):
        """ event handler for btn_edit - identify item on map """
        cur_layer_name = self.ui.cb_layer_selector.currentText()
        if cur_layer_name.isEmpty():
            return
        try:
            cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)
            
            # build layer render property Dialog for selected layer  
            dlg_render = QDialog()
            dlg_render.setWindowTitle(get_ui_string('widget.result.renderer.settings'))
            dlg_render.setModal(True)
            dlg_render.setFixedSize(530, 370)
            dlg_render.renderer = QgsRendererV2PropertiesDialog(self.map_layers[cur_layer_idx], self.style, True)
            dlg_render.renderer.setParent(dlg_render)        
            dlg_render.renderer.setGeometry(QRect(10, 10, 510, 325))
            dlg_render.buttonBox = QDialogButtonBox(dlg_render)
            dlg_render.buttonBox.setGeometry(QRect(10, 335, 510, 25))
            dlg_render.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
            dlg_render.buttonBox.accepted.connect(dlg_render.accept)
            dlg_render.buttonBox.accepted.connect(dlg_render.renderer.onOK)
            dlg_render.buttonBox.rejected.connect(dlg_render.reject)
            dlg_render.setVisible(True)

            # get user input and update renderer
            answer = dlg_render.exec_()
            if answer == QDialog.Accepted:
                self.map_layer_renderer[cur_layer_idx] = None
                self.map_layer_renderer[cur_layer_idx] = self.map_layers[cur_layer_idx].rendererV2().clone()             
                self.canvas.refresh()
            dlg_render.destroy()
            del dlg_render
        except Exception as err:
            # thematic is not-critical, allow continue on exception
            logUICall.log(str(err), logUICall.WARNING)
示例#27
0
 def wrapper(*args, **kw):
     self.main_window.setEnabled(False)
     try:
         logUICall.log('function call %s from module %s' % (f.__name__, f.__module__), logUICall.DEBUG)                                        
         return f(*args, **kw)
     except SIDDUIException as uie:
         logUICall.log(uie, logUICall.WARNING)
         self.main_window.ui.statusbar.showMessage(get_ui_string('app.error.ui'))
     except SIDDException as se:
         logUICall.log(se, logUICall.WARNING)
         self.main_window.ui.statusbar.showMessage(get_ui_string('app.error.model'))
     except Exception as e:
         logUICall.log(e, logUICall.ERROR)
         self.main_window.ui.statusbar.showMessage(get_ui_string('app.error.unexpected'))
     finally:
         self.main_window.setEnabled(True)
示例#28
0
 def setModelData(self, editor, model, index):
     existing_values = index.model().values
     code = self.valid_codes[str(editor.currentText())]
     if self.allow_repeats:
         model.setData(index, QVariant(code), Qt.EditRole)
     else:
         try:
             existing_values.index(code)
             # check to see if it is the same one
             if index.data().toString() != code:
                 # not the same one, show warning
                 QMessageBox.warning(None,
                                     get_ui_string("app.warning.title"), 
                                     get_ui_string("dlg.msbranch.error.attribute.exists", (code)))
         except:
             # code not in existing values list
             model.setData(index, QVariant(code), Qt.EditRole)
示例#29
0
 def createBlank(self):
     """ create a new project """
     # create new project file
     project = Project(self.app_config, self.taxonomy)
     # open project and sync UI
     self.setProject(project, skipVerify=True)
     self.ui.statusbar.showMessage(
         get_ui_string("app.status.project.created"))
示例#30
0
文件: wdg_data.py 项目: gem/sidd
 def wrapper(*args, **kw):
     if self.project_is_required and self.project is None:
         logUICall.log(get_ui_string("app.error.project.missing"), logUICall.ERROR)
         return
     try:
         logUICall.log('function call %s from module %s' % (f.__name__, f.__module__), logUICall.DEBUG)
         return f(*args, **kw)
     except Exception as err:
         logUICall.log(err, logUICall.ERROR)
示例#31
0
 def selectExportFile(self):
     """
     event handler for btn_export_select_path 
     - open save file dialog box to select file name for export 
     """
     filename = QFileDialog.getSaveFileName(self,
                                            get_ui_string("widget.result.export.file.open"),
                                            ".", 
                                            self.ui.cb_export_format.currentText())
     if not filename.isNull():
示例#32
0
文件: wdg_mod.py 项目: gem/sidd
 def deleteModifier(self):
     """ delete selected modifier from mapping scheme. update table view """
     mod = self.getSelectedModifier()
     # make sure there is mod selected
     if mod is None:
         logUICall.log(get_ui_string("widget.ms.warning.node.required"), logUICall.WARNING)
         return
     # confirm delete 
     answer = QMessageBox.warning(self,
                                  get_ui_string("app.confirm.title"),
                                  get_ui_string("widget.mod.warning.delete"),
                                  QMessageBox.Yes | QMessageBox.No)
     if answer == QMessageBox.Yes:
         # see MSTableModel about data in mod variable
         modidx, src_node = mod[4], mod[6]
         if src_node is not None:
             # remove modifier
             src_node.remove_modifier(modidx)
         self.app.visualizeMappingScheme(self.ms)
示例#33
0
 def is_range_valid(self):
     is_valid = True
     self.ui.lb_notes.setText("")
     for i in range(len(self.range_values[0])):
         # minimum must be less than maximum in same row
         max_val = self.range_values[1][i]
         min_val = self.range_values[0][i]                         
         is_valid = (min_val <= max_val)
         if not is_valid:
             # use exception to stop additional checks 
             raise SIDDRangeGroupException(get_ui_string("dlg.attr.error.max", (max_val, min_val)))
         # and minimum must be exactly 1 larger than maximum from previous row  
         if i > 0:   # first row does not have previous
             max_last = self.range_values[1][i-1]
             is_valid = (min_val == max_last+1)
             if not is_valid:
                 # use exception to stop additional checks
                 raise SIDDRangeGroupException(get_ui_string("dlg.attr.error.range", (max_last, min_val)))
     return is_valid                
示例#34
0
 def verifyInputs(self):
     """ perform checks on current dataset provided and update UI accordingly """                
     # remove result
     self.tab_result.closeResult()
     
     # verify current dataset
     self.ui.statusbar.showMessage(get_ui_string("app.status.ms.processing"))
     # invoke asynchronously 
     invoke_async(get_ui_string("app.status.processing"), self.project.verify_data)       
     self.tab_datainput.showVerificationResults()
     
     # always allow mapping scheme
     self.ui.mainTabs.setTabEnabled(self.TAB_MS, True)
     self.ui.mainTabs.setTabEnabled(self.TAB_MOD, True)
     self.ui.actionMapping_Schemes.setEnabled(True)
     self.ui.actionResult.setEnabled(True)      
     self.ui.actionProcessing_Options.setEnabled(True)   
     
     self.ui.statusbar.showMessage(get_ui_string("app.status.input.verified"))       
示例#35
0
 def selectExportFile(self):
     """
     event handler for btn_export_select_path 
     - open save file dialog box to select file name for export 
     """
     filename = QFileDialog.getSaveFileName(
         self, get_ui_string("widget.result.export.file.open"), ".",
         self.ui.cb_export_format.currentText())
     if not filename.isNull():
         self.ui.txt_export_select_path.setText(filename)
示例#36
0
 def saveProj(self):
     """ save active project """
     if self.project is None:
         return
     try: 
         self.project.sync(SyncModes.Write)
         self.ui.statusbar.showMessage(get_ui_string("app.status.project.saved"))
     except SIDDProjectException as se:
         if se.error == ProjectErrors.FileNotSet:
             self.saveProjAs()
示例#37
0
 @pyqtSlot()
 def exportData(self):
     """ 
     event handler for btn_export
     - do export data 
     """
     export_path = str(self.ui.txt_export_select_path.text())
     if export_path == "":
         logUICall.log(get_ui_string("app.error.path.is.null"), logUICall.WARNING)
         return
示例#38
0
    @pyqtSlot(QPoint, QObject)
    def showInfo(self, point, mouseButton):
        """
        event handler for toolInfo
        @see QGIS tutorial for detail
        point-polygon search on currently selected layer  
        """
        cur_layer_name = self.ui.cb_layer_selector.currentText()
        if cur_layer_name.isEmpty():
            return
        try:
            cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)
            cur_layer = self.map_layers[cur_layer_idx]
            
            # if layer is not in same projection as map canvas
            # need to project query point
            if cur_layer.crs() != self.canvas.mapRenderer().destinationCrs():
                transform = QgsCoordinateTransform(self.canvas.mapRenderer().destinationCrs(), cur_layer.crs())
                point = transform.transform(point)
            
            # do query
            provider = cur_layer.dataProvider() 
            provider.rewind()
            feature = QgsFeature()
            colonIndexes = provider.attributeIndexes()
        
            # search using point as center of rectangle polygon
            search_buffer_x = self.canvas.extent().width() * self.SEARCH_BUFFER / self.canvas.width()
            search_buffer_y = self.canvas.extent().height() * self.SEARCH_BUFFER / self.canvas.height()
            provider.select(colonIndexes,
                            QgsRectangle(point.x()-search_buffer_x,
                                         point.y()-search_buffer_y,
                                         point.x()+search_buffer_x,
                                         point.y()+search_buffer_y),
                            True)
            # get selected and display in result detail dialog box 
            selected = []        
            while provider.nextFeature(feature):            
                # for polygons, only show geometry containing query point            
                if cur_layer.geometryType() == QGis.Polygon:                
                    if feature.geometry() is not None and not feature.geometry().contains (point):
                        continue
                selected.append(feature.attributeMap())

            if len(selected)>0:
                # display result if exists
                if cur_layer_idx == self.EXPOSURE:
                    self.dlgResultDetail.showExposureData(provider.fields(), selected)                    
                else:
                    self.dlgResultDetail.showInfoData(provider.fields(), selected)
                self.dlgResultDetail.exec_()
            else:
                logUICall.log(get_ui_string("widget.result.info.notfound"), logUICall.WARNING)
        except Exception as err:
            # point-in-polygon search is not critical, continue on error 
示例#39
0
 def saveProj(self):
     """ save active project """
     if self.project is None:
         return
     try:
         self.project.sync(SyncModes.Write)
         self.ui.statusbar.showMessage(
             get_ui_string("app.status.project.saved"))
     except SIDDProjectException as se:
         if se.error == ProjectErrors.FileNotSet:
             self.saveProjAs()
示例#40
0
 def exportData(self):
     """ 
     event handler for btn_export
     - do export data 
     """
     export_path = str(self.ui.txt_export_select_path.text())
     if export_path == "":
         logUICall.log(get_ui_string("app.error.path.is.null"),
                       logUICall.WARNING)
         return
     self.app.exportResults(self.export_format, export_path)
示例#41
0
 def deleteModifier(self):
     """ delete selected modifier from mapping scheme. update table view """
     mod = self.getSelectedModifier()
     # make sure there is mod selected
     if mod is None:
         logUICall.log(get_ui_string("widget.ms.warning.node.required"),
                       logUICall.WARNING)
         return
     # confirm delete
     answer = QMessageBox.warning(
         self, get_ui_string("app.confirm.title"),
         get_ui_string("widget.mod.warning.delete"),
         QMessageBox.Yes | QMessageBox.No)
     if answer == QMessageBox.Yes:
         # see MSTableModel about data in mod variable
         modidx, src_node = mod[4], mod[6]
         if src_node is not None:
             # remove modifier
             src_node.remove_modifier(modidx)
         self.app.visualizeMappingScheme(self.ms)
示例#42
0
 def wrapper(*args, **kw):
     self.main_window.setEnabled(False)
     try:
         logUICall.log(
             'function call %s from module %s' %
             (f.__name__, f.__module__), logUICall.DEBUG)
         return f(*args, **kw)
     except SIDDUIException as uie:
         logUICall.log(uie, logUICall.WARNING)
         self.main_window.ui.statusbar.showMessage(
             get_ui_string('app.error.ui'))
     except SIDDException as se:
         logUICall.log(se, logUICall.WARNING)
         self.main_window.ui.statusbar.showMessage(
             get_ui_string('app.error.model'))
     except Exception as e:
         logUICall.log(e, logUICall.ERROR)
         self.main_window.ui.statusbar.showMessage(
             get_ui_string('app.error.unexpected'))
     finally:
         self.main_window.setEnabled(True)
示例#43
0
    def setMS(self, ms, isBranch=False):
        """
        set mapping scheme to be saved
        set mapping scheme type as 'single-level' if isBranch=True
        set to 'multi-level' otherwise 
        """
        self.ms_to_save = ms
        self.ui.tree_ms_view.setModel(MSTreeModel(ms))
        self.ui.tree_ms_view.setSelectionMode(QAbstractItemView.NoSelection)
        
        self.ui.txt_ms_create_date.setText(datetime.now().strftime("%Y-%m-%d %H:%M"))
        self.ui.txt_ms_create_date.setReadOnly(True)
        
        if isBranch:
            self.ui.lb_title.setText(get_ui_string("dlg.savems.title.branch"))
            self.ui.txt_ms_type.setText(get_ui_string("app.mslibrary.user.singlelevel"))
        else:
            self.ui.lb_title.setText(get_ui_string("dlg.savems.title.tree"))
            self.ui.txt_ms_type.setText(get_ui_string("app.mslibrary.user.multilevel"))      

        self.ui.txt_ms_type.setReadOnly(True)
        
示例#44
0
    def setData(self, index, value, role):
        """ set data modified by cell edit """
        if role == Qt.EditRole:
            if (index.column() == 0):
                # first column, change value
                taxStr = str(value.toString())                
                # make sure there is no repeat
                try:                    
                    self.values.index(taxStr)
                    # no error means taxStr already in self.value
                    found = True                    
                except:
                    found = False
                if found:
                    raise SIDDException(get_ui_string("dlg.msbranch.error.attribute.exists") % taxStr)
                # do nothing for empty string
                if taxStr == "":
                    return False           
                # verify taxonomy
                                
                # passed all checks. set value
                self.values[index.row()] = taxStr
            else:
                # second column, change weight
                (dVal, sucess) = value.toDouble()
                # conversion to double failed
                if not sucess:
                    raise SIDDException(get_ui_string("dlg.msbranch.edit.warning.invalidweight"))
                # make sure 0 <= dVal <= 100
                if dVal < 0 or dVal > 100:
                    raise SIDDException(get_ui_string("dlg.msbranch.edit.warning.invalidweight"))
                                    
                # passed all checks. set value
                self.weights[index.row()] = round(dVal, 1)

            self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(self.rowCount(0),self.columnCount(0)))
            return True
        return False
示例#45
0
    def setData(self, index, value, role):
        """ set data modified by cell edit """
        if role == Qt.EditRole:
            if index.column() == 0:
                # first column, change value
                taxStr = str(value.toString())
                # make sure there is no repeat
                try:
                    self.values.index(taxStr)
                    # no error means taxStr already in self.value
                    found = True
                except:
                    found = False
                if found:
                    raise SIDDException(get_ui_string("dlg.msbranch.error.attribute.exists") % taxStr)
                # do nothing for empty string
                if taxStr == "":
                    return False
                # verify taxonomy

                # passed all checks. set value
                self.values[index.row()] = taxStr
            else:
                # second column, change weight
                (dVal, sucess) = value.toDouble()
                # conversion to double failed
                if not sucess:
                    raise SIDDException(get_ui_string("dlg.msbranch.edit.warning.invalidweight"))
                # make sure 0 <= dVal <= 100
                if dVal < 0 or dVal > 100:
                    raise SIDDException(get_ui_string("dlg.msbranch.edit.warning.invalidweight"))

                # passed all checks. set value
                self.weights[index.row()] = round(dVal, 1)

            self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(self.rowCount(0), self.columnCount(0)))
            return True
        return False
示例#46
0
    def verifyInputs(self):
        """ perform checks on current dataset provided and update UI accordingly """
        # remove result
        self.tab_result.closeResult()

        # verify current dataset
        self.ui.statusbar.showMessage(
            get_ui_string("app.status.ms.processing"))
        # invoke asynchronously
        invoke_async(get_ui_string("app.status.processing"),
                     self.project.verify_data)
        self.tab_datainput.showVerificationResults()

        # always allow mapping scheme
        self.ui.mainTabs.setTabEnabled(self.TAB_MS, True)
        self.ui.mainTabs.setTabEnabled(self.TAB_MOD, True)

        self.ui.actionMapping_Schemes.setEnabled(True)
        self.ui.actionResult.setEnabled(True)
        self.ui.actionProcessing_Options.setEnabled(True)

        self.ui.statusbar.showMessage(
            get_ui_string("app.status.input.verified"))
示例#47
0
    def closeProject(self):
        """ close opened project and update UI elements accordingly """
        # adjust UI in application window
        self.tab_result.closeAll()  # this call must happen first.
        # otherwise, it locks temporary GIS files
        self.ui.mainTabs.setTabEnabled(self.TAB_DATA, False)
        self.ui.mainTabs.setTabEnabled(self.TAB_MS, False)
        self.ui.mainTabs.setTabEnabled(self.TAB_MOD, False)
        self.ui.mainTabs.setTabEnabled(self.TAB_RESULT, False)
        self.showTab(self.TAB_DATA)
        # disable menu/menu items
        self.ui.actionSave.setEnabled(False)
        self.ui.actionSave_as.setEnabled(False)
        self.ui.actionMapping_Schemes.setEnabled(False)
        self.ui.actionResult.setEnabled(False)
        self.ui.actionProcessing_Options.setEnabled(False)

        if getattr(self, 'project', None) is not None:
            # save existing project is needed
            if self.project.require_save:
                ans = QMessageBox.question(
                    self,
                    get_ui_string("app.window.msg.project.not_saved"),
                    get_ui_string("app.window.msg.project.save_or_not"),
                    buttons=QMessageBox.Yes | QMessageBox.No,
                    defaultButton=QMessageBox.Yes)
                if ans == QMessageBox.Yes:
                    self.saveProj()

            # adjust UI in tabs
            self.tab_datainput.closeProject()
            self.tab_ms.clearMappingScheme()
            self.tab_mod.closeMappingScheme()
            self.project.clean_up()
            del self.project
            self.project = None
示例#48
0
    def setMS(self, ms, isBranch=False):
        """
        set mapping scheme to be saved
        set mapping scheme type as 'single-level' if isBranch=True
        set to 'multi-level' otherwise 
        """
        self.ms_to_save = ms
        self.ui.tree_ms_view.setModel(MSTreeModel(ms))
        self.ui.tree_ms_view.setSelectionMode(QAbstractItemView.NoSelection)

        self.ui.txt_ms_create_date.setText(
            datetime.now().strftime("%Y-%m-%d %H:%M"))
        self.ui.txt_ms_create_date.setReadOnly(True)

        if isBranch:
            self.ui.lb_title.setText(get_ui_string("dlg.savems.title.branch"))
            self.ui.txt_ms_type.setText(
                get_ui_string("app.mslibrary.user.singlelevel"))
        else:
            self.ui.lb_title.setText(get_ui_string("dlg.savems.title.tree"))
            self.ui.txt_ms_type.setText(
                get_ui_string("app.mslibrary.user.multilevel"))

        self.ui.txt_ms_type.setReadOnly(True)
示例#49
0
 def searchFeature(self):        
     cur_layer_name = self.ui.cb_layer_selector.currentText()
     if cur_layer_name.isEmpty():
         return
     try:
         cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)            
         layer = self.map_layers[cur_layer_idx]
         fields = []
         for fidx in layer.dataProvider().fields():
             fields.append(layer.dataProvider().fields()[fidx].name())
         dlg_search = DialogSearchFeature(fields)           
         answer = dlg_search.exec_()
         if answer == QDialog.Accepted:
             extent = self.findFeatureExtentByAttribute(layer, dlg_search.attribute, dlg_search.value)
             if extent is not None:
                 self.zoomToExtent(extent)
             else:
                 logUICall.log(get_ui_string("widget.result.info.notfound"), logUICall.WARNING)
         dlg_search.destroy()
     except Exception as err:
         # thematic is not-critical, allow continue on exception
         logUICall.log(str(err), logUICall.WARNING)
示例#50
0
    def mapEditTheme(self):
        """ event handler for btn_edit - identify item on map """
        cur_layer_name = self.ui.cb_layer_selector.currentText()
        if cur_layer_name.isEmpty():
            return
        try:
            cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)

            # build layer render property Dialog for selected layer
            dlg_render = QDialog()
            dlg_render.setWindowTitle(
                get_ui_string('widget.result.renderer.settings'))
            dlg_render.setModal(True)
            dlg_render.setFixedSize(530, 370)
            dlg_render.renderer = QgsRendererV2PropertiesDialog(
                self.map_layers[cur_layer_idx], self.style, True)
            dlg_render.renderer.setParent(dlg_render)
            dlg_render.renderer.setGeometry(QRect(10, 10, 510, 325))
            dlg_render.buttonBox = QDialogButtonBox(dlg_render)
            dlg_render.buttonBox.setGeometry(QRect(10, 335, 510, 25))
            dlg_render.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                                    | QDialogButtonBox.Ok)
            dlg_render.buttonBox.accepted.connect(dlg_render.accept)
            dlg_render.buttonBox.accepted.connect(dlg_render.renderer.onOK)
            dlg_render.buttonBox.rejected.connect(dlg_render.reject)
            dlg_render.setVisible(True)

            # get user input and update renderer
            answer = dlg_render.exec_()
            if answer == QDialog.Accepted:
                self.map_layer_renderer[cur_layer_idx] = None
                self.map_layer_renderer[cur_layer_idx] = self.map_layers[
                    cur_layer_idx].rendererV2().clone()
                self.canvas.refresh()
            dlg_render.destroy()
            del dlg_render
        except Exception as err:
            # thematic is not-critical, allow continue on exception
            logUICall.log(str(err), logUICall.WARNING)
示例#51
0
 def createWizard(self):
     try:
         # should not update preview while using wizard
         self.setVisible(False)
         self.previewInput = False   
                     
         wizard = WidgetDataWizard(self, Project(self.app_config, self.taxonomy))            
         if wizard.exec_() == QDialog.Accepted:
             # setProject makes call to GIS component that requires visibility 
             self.setVisible(True)
             self.previewInput = True                
             self.setProject(wizard.project)
             self.ui.statusbar.showMessage(get_ui_string("app.status.project.created"))
         # else
         # do nothing?
     except:
         pass            
     finally:
         # return to normal window
         # these calls are reached 
         # 1. in case any exception occurs,
         # 2. wizard finished or cancelled  
         self.setVisible(True)
         self.previewInput = True
示例#52
0
文件: wdg_mod.py 项目: gem/sidd
 def editModifier(self):
     """ edit selected modifier """
     mod = self.getSelectedModifier()
     # make sure there is mod selected
     if mod is None:
         logUICall.log(get_ui_string("widget.ms.warning.node.required"), logUICall.WARNING)
         return
     
     # show edit dialog box for selected modifier
     self.dlgEditMod.setNode(self.ms, mod)
     ans = self.dlgEditMod.exec_()
     
     # accepted means apply change
     if ans == QDialog.Accepted:
         # NOTE: dlgEditMod already should have performed all the checks on 
         #       values/weights pair, we can safely assume that data is clean 
         #       to be used
         #[zone_name, bldg_type, startIdx, endIdx, modidx, modifier, node] = mod
         if self.dlgEditMod.node is not None:
             modifier = StatisticModifier(self.dlgEditMod.modifier_name)
             for value, weight in map(None, self.dlgEditMod.values, self.dlgEditMod.weights):
                 modifier.values[value] = weight
             self.dlgEditMod.node.set_modifier(self.dlgEditMod.modidx, modifier)
         self.app.visualizeMappingScheme(self.ms)
示例#53
0
 def searchFeature(self):
     cur_layer_name = self.ui.cb_layer_selector.currentText()
     if cur_layer_name.isEmpty():
         return
     try:
         cur_layer_idx = self.LAYER_NAMES.index(cur_layer_name)
         layer = self.map_layers[cur_layer_idx]
         fields = []
         for fidx in layer.dataProvider().fields():
             fields.append(layer.dataProvider().fields()[fidx].name())
         dlg_search = DialogSearchFeature(fields)
         answer = dlg_search.exec_()
         if answer == QDialog.Accepted:
             extent = self.findFeatureExtentByAttribute(
                 layer, dlg_search.attribute, dlg_search.value)
             if extent is not None:
                 self.zoomToExtent(extent)
             else:
                 logUICall.log(get_ui_string("widget.result.info.notfound"),
                               logUICall.WARNING)
         dlg_search.destroy()
     except Exception as err:
         # thematic is not-critical, allow continue on exception
         logUICall.log(str(err), logUICall.WARNING)
示例#54
0
    def __init__(self, qtapp, app_config):
        """
        constructor
        - initialize UI elements
        - connect UI elements to callback            
        """
        # create UI
        super(AppMainWindow, self).__init__()
        AppMainWindow.apiCallChecker.setWindow(self)
        
        self.qtapp = qtapp
        self.app_config = app_config
        self.taxonomy = get_taxonomy(app_config.get('options', 'taxonomy', 'gem'))
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)
        
        self.settings = QSettings(SIDD_COMPANY, '%s %s' %(SIDD_APP_NAME, SIDD_VERSION));
        self.restoreGeometry(self.settings.value(self.UI_WINDOW_GEOM).toByteArray());
        self.restoreState(self.settings.value(self.UI_WINDOW_STATE).toByteArray());
        
        self.lb_map_location = QLabel(self)
        self.lb_map_location.resize(self.ui.statusbar.width()/3, self.ui.statusbar.height())
        self.ui.statusbar.addPermanentWidget(self.lb_map_location)
        
        self.msdb_dao = MSDatabaseDAO(FILE_MS_DB)
        
        self.tab_datainput = WidgetDataInput(self)
        self.ui.mainTabs.addTab(self.tab_datainput, get_ui_string("app.window.tab.input"))

        self.tab_ms = WidgetMappingSchemes(self)
        self.ui.mainTabs.addTab(self.tab_ms, get_ui_string("app.window.tab.ms"))

        self.tab_mod = WidgetSecondaryModifier(self)
        self.ui.mainTabs.addTab(self.tab_mod, get_ui_string("app.window.tab.mod"))

        self.tab_result = WidgetResult(self)
        self.ui.mainTabs.addTab(self.tab_result, get_ui_string("app.window.tab.result"))
        self.previewInput = True
        
        self.about = DialogAbout(self)
        self.about.setModal(True)        
        
        self.dlgAttrRange = DialogAttrRanges()
        self.dlgAttrRange.setModal(True)
        
        self.progress = DialogApply(self)
        self.progress.setModal(True)
        
        self.proc_options = DialogProcessingOptions(self)
        self.proc_options.setModal(True)
        
        # connect menu action to slots (ui events)        
        self.ui.mainTabs.currentChanged.connect(self.tabChanged)
        
        self.ui.actionProject_Blank.triggered.connect(self.createBlank)
        self.ui.actionUsing_Data_Wizard.triggered.connect(self.createWizard)
        self.ui.actionOpen_Existing.triggered.connect(self.loadProj)
        self.ui.actionSave.triggered.connect(self.saveProj)
        self.ui.actionSave_as.triggered.connect(self.saveProjAs)
        self.ui.actionExit.triggered.connect(self.close)
        
        self.ui.actionData_Input.triggered.connect(self.changeTab)
        self.ui.actionMapping_Schemes.triggered.connect(self.changeTab)
        self.ui.actionResult.triggered.connect(self.changeTab)
        
        self.ui.actionProcessing_Options.triggered.connect(self.setProcessingOptions)
        
        self.ui.actionAbout.triggered.connect(self.showAbout)
        
        # set project to None and adjust ui as needed
        self.closeProject()        
        self.ui.statusbar.showMessage(get_ui_string("app.status.ready"))

        # perform clean up from previous runs
        try:
            delete_folders_in_dir(get_temp_dir(), "tmp*")
        except:
            # cleanup is not-critical. no action taken even if fails
            pass

        # hide features 
        if not app_config.get('options', 'parse_modifier', True, bool):
            self.tab_mod.setVisible(False)
            self.ui.mainTabs.removeTab(self.TAB_MOD) 
            self.TAB_MOD = self.TAB_MS
            self.TAB_RESULT -= 1             
            
        # hide view menu
        self.ui.menuView.menuAction().setVisible(False)
        # hide data wizard
        self.ui.actionUsing_Data_Wizard.setVisible(False)
示例#55
0
    def buildExposure(self):        
        """ build exposure """
        self.ui.statusbar.showMessage(get_ui_string("app.status.ms.processing"))
                
        # verify current dataset to make sure can process exposure
        self.project.verify_data()
        
        # can not proceed if project is not ready for exposure
        if self.project.status != ProjectStatus.ReadyForExposure:
            logUICall.log(get_ui_string("project.error.NotEnoughData"), logUICall.WARNING)

            # show result 
            self.tab_datainput.showVerificationResults()
            self.ui.mainTabs.setCurrentIndex(self.TAB_DATA)
            return
        
        # close current results
        self.tab_result.closeResult()
        self.ui.mainTabs.setTabEnabled(self.TAB_RESULT, True)

        # reset progress dialog
        self.progress.setVisible(True)
        self.progress.ui.pb_progress.setRange(0, self.project.build_exposure_total_steps())        
        self.progress.ui.txt_progress.clear()
        self.progress.ui.txt_progress.appendPlainText(get_ui_string("app.status.processing"))        
        self.qtapp.processEvents()
        
        cancelled = False
        error_occured = False
        error_message = ""
        curStep = 0
        try:
            for step in self.project.build_exposure_steps():
                if cancelled or error_occured:
                    break
                
                # use introspection to get operator class                           
                class_name = str(step.__class__)
                # result of above call has format 
                # <class '...'> where ... is the class name of interest
                class_name = class_name[class_name.find("'")+1:class_name.rfind("'")]
                
                # update UI
                logAPICall.log('\t %s' % step.name, logAPICall.DEBUG)
                self.progress.ui.txt_progress.appendPlainText(get_ui_string('message.%s'% class_name))
                self.progress.ui.pb_progress.setValue(curStep)                        
                self.qtapp.processEvents()
                sleep(0.5)
                
                # perform operation
                step.do_operation()
                if not self.progress.isVisible():
                    cancelled = True
                
                # operation successful
                curStep+=1
        except Exception as err:
            # exception are thrown if data is not ready for exposure 
            error_message = err.message
            error_occured = True
            self.progress.setVisible(False)
            
        if error_occured:
            # processing cancelled
            logUICall.log(error_message, logUICall.WARNING)
            self.ui.statusbar.showMessage(get_ui_string("app.status.cancelled"))
        elif cancelled:
            # processing cancelled
            logUICall.log(get_ui_string("app.status.cancelled"), logUICall.WARNING)
            self.ui.statusbar.showMessage(get_ui_string("app.status.cancelled"))
        else:
            # processing completed            
            self.project.verify_result()
            self.progress.setVisible(False)
        
            # show result
            self.tab_result.refreshResult()
            self.ui.mainTabs.setTabEnabled(self.TAB_RESULT, True)
            self.ui.mainTabs.setCurrentIndex(self.TAB_RESULT)
            self.ui.statusbar.showMessage(get_ui_string("app.status.exposure.created"))