Example #1
0
    def GetSelectedMap(self):
        """Return name of selected map in layer tree"""
        layerList = self._giface.GetLayerList()
        layerSelected = layerList.GetSelectedLayer()
        if layerSelected is None:
            return None

        if not layerSelected.maplayer.IsActive():
            GWarning(_("Selected map <%s> has been disabled for rendering. "
                       "Operation canceled.") % str(layerSelected), parent=self.mapWin)
            return None

        if layerSelected:
            mapName = str(layerSelected)
            if self.mapName is not None:
                if self.mapName != mapName:
                    self.Reset()
        else:
            mapName = None
            self.UnregisterMapEvtHandler()
            GError(_("No map layer selected. Operation canceled."))
        return mapName
Example #2
0
    def UnregisterAllHandlers(self):
        """Unregisters all registered handlers

        @deprecated This method is deprecated. Use Signals or drawing API instead.

        Before each handler is unregistered it is called with string
        value "unregistered" of event parameter.
        """
        for containerEv, handlers in six.iteritems(self.handlersContainer):
            for handler in handlers:
                try:
                    handler("unregistered")
                    handlers.remove(handler)
                except:
                    GError(
                        parent=self,
                        message=
                        _("Error occurred during unregistration of handler: %s \n \
                                       Handler was unregistered.") %
                        handler.__name__,
                    )
                    handlers.remove(handler)
Example #3
0
    def _readJinjaInfo(self):
        '''Parser  of 'comments'({# #}) in jinja template which are represented by jinjainfo::MdDescription
        parsed values initializing list of jinjainfo::MdDesctiption obect
        '''
        try:
            with open(self.template, "r") as f:
                for line in f:
                    # if found start of comments
                    if str(line).find("{#") != -1:
                        values = findBetween(line, "{#", "#}")
                        values1 = findBetween(line, "{%", "#}")
                        values2 = findBetween(line, "{{", "#}")
                        if values1 != '':
                            values += ",selfInfoString='''{%" + values1 + "#}'''"
                        else:
                            values += ",selfInfoString='''{{" + values2 + "#}'''"

                        exe_str = "self.mdDescription.append(MdDescription(%s))" % values
                        exe_str = exe_str.encode("utf-8", 'ignore')
                        eval(exe_str)
        except:
            GError('Cannot open jinja template')
Example #4
0
    def OnCopy(self, event):
        """Copy selected features from (background) vector map"""
        if not self.digit:
            GError(_("No vector map open for editing."), self.parent)
            return
        
        # select background map
        dlg = VectorDialog(self.parent, title = _("Select background vector map"),
                           layerTree = self._giface.GetLayerTree())
        if dlg.ShowModal() != wx.ID_OK:
            dlg.Destroy()
            return
        
        mapName = dlg.GetName(full=True)
        dlg.Destroy()
        
        # close open background map if any
        bgMap = UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
                                 internal = True)
        if bgMap:
            self.digit.CloseBackgroundMap()
            self.editingBgMap.emit(mapName = bgMap, unset=True)

        # open background map for reading
        UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
                         value = str(mapName), internal = True)
        self.digit.OpenBackgroundMap(mapName)
        self.editingBgMap.emit(mapName = mapName)

        if self.action['desc'] == 'copyLine': # select previous action
            self.ToggleTool(self.addPoint, True)
            self.ToggleTool(self.additionalTools, False)
            self.OnAddPoint(event)
            return
        
        Debug.msg(2, "Digittoolbar.OnCopy():")
        self.action = { 'desc' : "copyLine",
                        'id'   : self.additionalTools }
        self.MapWindow.mouse['box'] = 'box'
Example #5
0
    def ImportFile(self, filePath):
        """Tries to import file as vector or raster.

        If successfull sets default region from imported map.
        """
        RunCommand('db.connect', flags='c')
        mapName = os.path.splitext(os.path.basename(filePath))[0]
        vectors = RunCommand('v.in.ogr', input=filePath, flags='l', read=True)

        wx.BeginBusyCursor()
        wx.Yield()
        if mapName in vectors:
            # vector detected
            returncode, error = RunCommand('v.in.ogr',
                                           input=filePath,
                                           output=mapName,
                                           flags='e',
                                           getErrorMsg=True)
        else:
            returncode, error = RunCommand('r.in.gdal',
                                           input=filePath,
                                           output=mapName,
                                           flags='e',
                                           getErrorMsg=True)
        wx.EndBusyCursor()

        if returncode != 0:
            GError(parent=self,
                   message=_("Import of <%(name)s> failed.\n"
                             "Reason: %(msg)s") % ({
                                 'name': filePath,
                                 'msg': error
                             }))
        else:
            GMessage(message=_(
                "Data file <%(name)s> imported successfully. "
                "The location's default region was set from this imported map."
            ) % {'name': filePath},
                     parent=self)
Example #6
0
    def QuerySelectedMap(self):
        """Return w.what info from last clicked coords on display"""
        self.mapName = self.GetSelectedMap()
        if not self.mapName:
            return {}

        mapInfo = self.mapWin.GetMap()
        threshold = 10.0 * (
            (mapInfo.region["e"] - mapInfo.region["w"]) / mapInfo.width)
        try:
            query = grass.vector_what(
                map=[self.mapName],
                coord=self.mapWin.GetLastEN(),
                distance=threshold,
                skip_attributes=True,
            )
        except grass.ScriptError:
            GError(parent=self,
                   message=_("Failed to query vector map(s) <%s>.") % self.map)
            return None

        return query[0]
Example #7
0
    def OnOutputSave(self, event):
        """Save (selected) text from output window to the file"""
        text = self.cmdOutput.GetSelectedText()
        if not text:
            text = self.cmdOutput.GetText()

        # add newline if needed
        if len(text) > 0 and text[-1] != "\n":
            text += "\n"

        dlg = wx.FileDialog(
            self,
            message=_("Save file as..."),
            defaultFile="grass_cmd_output.txt",
            wildcard=_("%(txt)s (*.txt)|*.txt|%(files)s (*)|*")
            % {"txt": _("Text files"), "files": _("Files")},
            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
        )

        # Show the dialog and retrieve the user response. If it is the OK response,
        # process the data.
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

            try:
                output = open(path, "w")
                output.write(text)
            except IOError as e:
                GError(
                    _("Unable to write file '%(path)s'.\n\nDetails: %(error)s")
                    % {"path": path, "error": e}
                )
            finally:
                output.close()
            message = _("Command output saved into '%s'") % path
            self.showNotification.emit(message=message)

        dlg.Destroy()
Example #8
0
    def OnExportMap(self, event):
        """Export selected features to a new map

        Add new map layer to layer tree and checked it

        @todo: set color of map to higlight color
        """

        if len(self.selectedFeatures) == 0:
            GMessage(_('No features selected'))
            return
        lst = ''
        for cat in self.selectedFeatures:  # build text string of categories for v.extract input
            lst += str(cat['Category']) + ','
        lst = lst[:-1]
        outMap = str(self.selectedFeatures[0]['Map']) + '_selection' + str(
            self._id_generator(3))
        ret, err = RunCommand('v.extract',
                              input=self.selectedFeatures[0]['Map'],
                              layer=self.selectedFeatures[0]['Layer'],
                              output=outMap,
                              cats=lst,
                              getErrorMsg=True)
        if ret == 0:
            tree = self._giface.GetLayerTree()
            if tree:
                tree.AddLayer(ltype='vector',
                              lname=outMap,
                              lcmd=['d.vect', 'map=%s' % outMap],
                              lchecked=True)

                # TODO colorize new map
                self.Reset()
            else:
                GMessage(_('Vector map <%s> was created') % outMap)
                self.Reset()
        else:
            GError(_("Unable to create a new vector map.\n\nReason: %s") % err)
Example #9
0
    def UpdateLocations(self, dbase):
        """Update list of locations"""
        try:
            self.listOfLocations = GetListOfLocations(dbase)
        except UnicodeEncodeError:
            GError(parent=self,
                   message=_("Unable to set GRASS database. "
                             "Check your locale settings."))

        self.lblocations.Clear()
        self.lblocations.InsertItems(self.listOfLocations, 0)

        if len(self.listOfLocations) > 0:
            self._hideMessage()
            self.lblocations.SetSelection(0)
        else:
            self.lblocations.SetSelection(wx.NOT_FOUND)
            self._showWarning(
                _("No GRASS Location found in '%s'."
                  " Create a new Location or choose different"
                  " GRASS database directory.") % self.gisdbase)

        return self.listOfLocations
Example #10
0
    def GetOptData(self, dcmd, layer, params, propwin):
        """Handler for module dialogs."""
        if dcmd:
            layer.cmd = dcmd
            layer.selected = True
            mapName, found = GetLayerNameFromCmd(dcmd)
            if found:
                try:
                    if layer.hidden:
                        layer.hidden = False
                        signal = self.layerAdded
                    else:
                        signal = self.cmdChanged

                    layer.name = mapName
                    signal.emit(index=self._layerList.GetLayerIndex(layer),
                                layer=layer)
                except ValueError as e:
                    self._layerList.RemoveLayer(layer)
                    GError(parent=self, message=str(e), showTraceback=False)

            self._update()
            self.anyChange.emit()
Example #11
0
    def OnApplyInputChanges(self):
        first, second = self._inputDialog.GetValues()
        if self._inputDialog.IsSimpleMode():
            self.rasters["first"], self.rasters["second"] = first, second
            res1 = self.SetFirstRaster(name=self.rasters["first"])
            res2 = self.SetSecondRaster(name=self.rasters["second"])
            if not (res1 and res2) and (first or second):
                message = ""
                if first and not res1:
                    message += _("Map <%s> not found. ") % self.rasters["first"]
                if second and not res2:
                    message += _("Map <%s> not found.") % self.rasters["second"]
                if message:
                    GError(parent=self, message=message)
                    return
            self.ZoomToMap()
        else:
            LayerListToRendererConverter(self.GetFirstMap()).ConvertAll(first)
            LayerListToRendererConverter(self.GetSecondMap()).ConvertAll(second)

        self.SetRasterNames()
        if self.IsAutoRendered():
            self.OnRender(event=None)
Example #12
0
    def CreateNewMapset(self, mapset):
        if mapset in self.listOfMapsets:
            GMessage(parent=self,
                     message=_("Mapset <%s> already exists.") % mapset)
            return False

        if mapset.lower() == 'ogr':
            dlg1 = wx.MessageDialog(
                parent=self,
                message=_(
                    "Mapset <%s> is reserved for direct "
                    "read access to OGR layers. Please consider to use "
                    "another name for your mapset.\n\n"
                    "Are you really sure that you want to create this mapset?")
                % mapset,
                caption=_("Reserved mapset name"),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            ret = dlg1.ShowModal()
            dlg1.Destroy()
            if ret == wx.ID_NO:
                dlg1.Destroy()
                return False

        try:
            self.gisdbase = self.tgisdbase.GetValue()
            location = self.listOfLocations[self.lblocations.GetSelection()]
            create_mapset(self.gisdbase, location, mapset)
            self.OnSelectLocation(None)
            self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
            self.bstart.SetFocus()

            return True
        except Exception as e:
            GError(parent=self,
                   message=_("Unable to create new mapset: %s") % e,
                   showTraceback=False)
            return False
Example #13
0
    def UpdateLocations(self, dbase):
        """Update list of locations"""
        try:
            self.listOfLocations = GetListOfLocations(dbase)
        except (UnicodeEncodeError, UnicodeDecodeError) as e:
            GError(parent=self,
                   message=_("Unicode error detected. "
                             "Check your locale settings. Details: {0}").format(e),
                   showTraceback=False)

        self.lblocations.Clear()
        self.lblocations.InsertItems(self.listOfLocations, 0)

        if len(self.listOfLocations) > 0:
            self._hideMessage()
            self.lblocations.SetSelection(0)
        else:
            self.lblocations.SetSelection(wx.NOT_FOUND)
            self._showWarning(_("No GRASS Location found in '%s'."
                                " Create a new Location or choose different"
                                " GRASS database directory.")
                              % self.gisdbase)

        return self.listOfLocations
Example #14
0
    def CmdProtocolSave(self):
        """Save list of manually entered commands into a text log file"""
        if not hasattr(self, 'cmdFileProtocol'):
            return  # it should not happen

        try:
            output = open(self.cmdFileProtocol, "a")
            cmds = self.cmdPrompt.GetCommands()
            output.write('\n'.join(cmds))
            if len(cmds) > 0:
                output.write('\n')
        except IOError as e:
            GError(
                _("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s")
                % {
                    'filePath': self.cmdFileProtocol,
                    'error': e
                })
        finally:
            output.close()

        message = _("Command log saved to '%s'") % self.cmdFileProtocol
        self.showNotification.emit(message=message)
        del self.cmdFileProtocol
Example #15
0
    def OnRun(self, event):
        """Run Python script"""
        if not self.filename:
            self.filename = gscript.tempfile() + '.py'
            self.tempfile = True
            try:
                fd = open(self.filename, "w")
                fd.write(self.body.GetText())
            except IOError as e:
                GError(_("Unable to launch Python script. %s") % e,
                       parent=self.guiparent)
                return
            finally:
                fd.close()
                mode = stat.S_IMODE(os.lstat(self.filename)[stat.ST_MODE])
                os.chmod(self.filename, mode | stat.S_IXUSR)
        else:
            # always save automatically before running
            fd = open(self.filename, "w")
            try:
                fd.write(self.body.GetText())
            finally:
                fd.close()
            # set executable file
            # (not sure if needed every time but useful for opened files)
            os.chmod(self.filename, stat.S_IRWXU | stat.S_IWUSR)

        # run in console as other modules, avoid Python shell which
        # carries variables over to the next execution
        env = os.environ.copy()
        if self.overwrite:
            env['GRASS_OVERWRITE'] = '1'
        cmd = [fd.name]
        if self.parameters:
            cmd.extend(self.parameters)
        self.giface.RunCmd(cmd, env=env)
Example #16
0
    def OpenRecentFile(self, path, file_exists, file_history):
        """Try open recent file and read content

        :param str path: file path
        :param bool file_exists: file path exists
        :param bool file_history: file history obj instance

        :return: None
        """
        if not file_exists:
            GError(
                _("File <{}> doesn't exist."
                  "It was probably moved or deleted.".format(path)),
                parent=self.guiparent,
            )
        else:
            if self.CanReplaceContent(by_message="file"):
                self.filename = path
                content = self._openFile(file_path=path)
                if content:
                    self.body.SetText(content)
                    file_history.AddFileToHistory(
                        filename=path)  # move up the list
                    self.tempfile = False
Example #17
0
    def OnAddCat(self, event):
        """Button 'Add' new category pressed
        """
        try:
            layer = int(self.layerNew.GetStringSelection())
            cat = int(self.catNew.GetValue())
            if layer <= 0:
                raise ValueError
        except ValueError:
            GError(
                parent=self,
                message=_(
                    "Unable to add new layer/category <%(layer)s/%(category)s>.\n"
                    "Layer and category number must be integer.\n"
                    "Layer number must be greater than zero.") % {
                    'layer': str(
                        self.layerNew.GetValue()),
                    'category': str(
                        self.catNew.GetValue())})
            return False

        if layer not in self.cats[self.fid].keys():
            self.cats[self.fid][layer] = []

        self.cats[self.fid][layer].append(cat)

        # reload list
        self.itemDataMap = self.list.Populate(self.cats[self.fid],
                                              update=True)

        # update category number for add
        self.catNew.SetValue(cat + 1)

        event.Skip()

        return True
Example #18
0
    def UpdateCategoryRaster(self, cat_id, attrs, render=True):

        cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
        if not grass.find_file(cat_rast, element='cell', mapset='.')['file']:
            return
        cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)

        if "color" in attrs:
            ret, err_msg = RunCommand('r.colors',
                                      map=cat_rast,
                                      rules="-",
                                      stdin="1 %s" % cats_attrs["color"],
                                      getErrorMsg=True)

            if ret != 0:
                GError("r.colors failed\n%s" % err_msg)
            if render:
                self.giface.updateMap.emit()

        if "name" in attrs:
            # TODO hack
            self.giface.GetLayerList()._tree.SetItemText(
                self.added_cats_rasts[cat_id], cats_attrs['name'])
            cats_attrs["name"]
Example #19
0
    def AddScattPlot(self):
        if not self.data_set and self.iclass_conn:
            self.show_add_scatt_plot = True
            self.iclass_conn.SetData()
            self.show_add_scatt_plot = False
            return
        if not self.data_set:
            GError(_('No data set.'))
            return

        self.computingStarted.emit()

        bands = self.core.GetBands()

        #added_bands_ids = []
        # for scatt_id in self.plots):
        #    added_bands_ids.append[idBandsToidScatt(scatt_id)]

        self.digit_conn.Update()

        ncells = self.region["rows"] * self.region["cols"]
        if ncells > MAX_NCELLS:
            GError(
                _(
                    parent=self.guiparent, mmessage=_(
                        "Interactive Scatter Plot Tool can not be used.\n"
                        "Number of cells (rows*cols) <%d> in current region"
                        "is higher than maximum limit <%d>.\n\n"
                        "You can reduce number of cells in current region using <g.region> command." %
                        (ncells, MAX_NCELLS))))
            return
        elif ncells > WARN_NCELLS:
            dlg = wx.MessageDialog(
                parent=self.guiparent,
                message=_("Number of cells (rows*cols) <%d> in current region is "
                          "higher than recommended threshold <%d>.\n"
                          "It is strongly advised to reduce number of cells "
                          "in current region below recommend threshold.\n "
                          "It can be done by <g.region> command.\n\n"
                          "Do you want to continue using "
                          "Interactive Scatter Plot Tool with this region?"
                          % (ncells, WARN_NCELLS)),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING)
            ret = dlg.ShowModal()
            if ret != wx.ID_YES:
                return

        dlg = AddScattPlotDialog(parent=self.guiparent,
                                 bands=self.all_bands,
                                 check_bands_callback=self.CheckBands)

        if dlg.ShowModal() == wx.ID_OK:

            scatt_ids = []
            sel_bands = dlg.GetBands()

            for b_1, b_2 in sel_bands:
                transpose = False
                if b_1 > b_2:
                    transpose = True
                    tmp_band = b_2
                    b_2 = b_1
                    b_1 = tmp_band

                b_1_id = self.all_bands_to_bands[self.all_bands[b_1]]
                b_2_id = self.all_bands_to_bands[self.all_bands[b_2]]

                scatt_id = idBandsToidScatt(b_1_id, b_2_id, len(bands))
                if scatt_id in self.plots:
                    continue

                self.plots[scatt_id] = {'transpose': transpose,
                                        'scatt': None}
                scatt_ids.append(scatt_id)

            self._addScattPlot(scatt_ids)

        dlg.Destroy()
Example #20
0
    def OnPasteMap(self, event):
        # copying between mapsets of one location
        if not self.copy_layer:
            if self.copy_mode:
                GMessage(_("No map selected for copying."), parent=self)
            else:
                GMessage(_("No map selected for moving."), parent=self)
            return

        gisrc, env = gscript.create_environment(
            gisenv()['GISDBASE'],
            self.selected_location.label,
            mapset=self.selected_mapset.label)
        gisrc2, env2 = gscript.create_environment(
            gisenv()['GISDBASE'],
            self.copy_location.label,
            mapset=self.copy_mapset.label)
        new_name = self.copy_layer.label
        if self.selected_location == self.copy_location:
            # within one mapset
            if self.selected_mapset == self.copy_mapset:
                # ignore when just moves map
                if self.copy_mode is False:
                    return
                new_name = self._getNewMapName(
                    _('New name'),
                    _('Select new name'),
                    self.copy_layer.label,
                    env=env,
                    mapset=self.selected_mapset.label,
                    element=self.copy_type.label)
                if not new_name:
                    return
            # within one location, different mapsets
            else:
                if map_exists(new_name,
                              element=self.copy_type.label,
                              env=env,
                              mapset=self.selected_mapset.label):
                    new_name = self._getNewMapName(
                        _('New name'),
                        _('Select new name'),
                        self.copy_layer.label,
                        env=env,
                        mapset=self.selected_mapset.label,
                        element=self.copy_type.label)
                    if not new_name:
                        return

            string = self.copy_layer.label + '@' + self.copy_mapset.label + ',' + new_name
            pasted = 0
            if self.copy_mode:
                label = _("Copying <{name}>...").format(name=string)
            else:
                label = _("Moving <{name}>...").format(name=string)
            self.showNotification.emit(message=label)
            if self.copy_type.label == 'vector':
                pasted, cmd = self._runCommand('g.copy',
                                               vector=string,
                                               env=env)
                node = 'vector'
            elif self.copy_type.label == 'raster':
                pasted, cmd = self._runCommand('g.copy',
                                               raster=string,
                                               env=env)
                node = 'raster'
            else:
                pasted, cmd = self._runCommand('g.copy',
                                               raster_3d=string,
                                               env=env)
                node = 'raster_3d'
            if pasted == 0:
                self.InsertLayer(name=new_name,
                                 mapset_node=self.selected_mapset,
                                 element_name=node)
                Debug.msg(1, "COPIED TO: " + new_name)
                if self.copy_mode:
                    self.showNotification.emit(
                        message=_("g.copy completed").format(cmd=cmd))
                else:
                    self.showNotification.emit(
                        message=_("g.copy completed").format(cmd=cmd))

                # remove old
                if not self.copy_mode:
                    self._removeMapAfterCopy(env2)

            gscript.try_remove(gisrc)
            gscript.try_remove(gisrc2)
            # expand selected mapset
            self.ExpandNode(self.selected_mapset, recursive=True)
            self._initVariablesCatalog()
        else:
            if self.copy_type.label == 'raster_3d':
                GError(_("Reprojection is not implemented for 3D rasters"),
                       parent=self)
                return
            if map_exists(new_name,
                          element=self.copy_type.label,
                          env=env,
                          mapset=self.selected_mapset.label):
                new_name = self._getNewMapName(
                    _('New name'),
                    _('Select new name'),
                    self.copy_layer.label,
                    env=env,
                    mapset=self.selected_mapset.label,
                    element=self.copy_type.label)
                if not new_name:
                    return
            gisdbase = gisenv()['GISDBASE']
            callback = lambda: self._onDoneReprojection(
                iEnv=env2, iGisrc=gisrc2, oGisrc=gisrc)
            dlg = CatalogReprojectionDialog(
                self, self._giface, gisdbase, self.copy_location.label,
                self.copy_mapset.label, self.copy_layer.label, env2, gisdbase,
                self.selected_location.label, self.selected_mapset.label,
                new_name, self.copy_type.label, env, callback)
            dlg.ShowModal()
Example #21
0
    def GetRegion(self,
                  rast=[],
                  zoom=False,
                  vect=[],
                  regionName=None,
                  n=None,
                  s=None,
                  e=None,
                  w=None,
                  default=False,
                  update=False):
        """!Get region settings (g.region -upgc)
        
        Optionally extent, raster or vector map layer can be given.
        
        @param rast list of raster maps
        @param zoom zoom to raster map (ignore NULLs)
        @param vect list of vector maps
        @param regionName  named region or None
        @param n,s,e,w force extent
        @param default force default region settings
        @param update if True update current display region settings
        
        @return region settings as directory, e.g. {
        'n':'4928010', 's':'4913700', 'w':'589980',...}
        
        @see GetCurrentRegion()
        """
        region = {}

        tmpreg = os.getenv("GRASS_REGION")
        if tmpreg:
            del os.environ["GRASS_REGION"]

        # use external gisrc if defined
        gisrc_orig = os.getenv("GISRC")
        if self.gisrc:
            os.environ["GISRC"] = self.gisrc

        # do not update & shell style output
        cmd = {}
        cmd['flags'] = 'ugpc'

        if default:
            cmd['flags'] += 'd'

        if regionName:
            cmd['region'] = regionName

        if n:
            cmd['n'] = n
        if s:
            cmd['s'] = s
        if e:
            cmd['e'] = e
        if w:
            cmd['w'] = w

        if rast:
            if zoom:
                cmd['zoom'] = rast[0]
            else:
                cmd['rast'] = ','.join(rast)

        if vect:
            cmd['vect'] = ','.join(vect)

        ret, reg, msg = RunCommand('g.region',
                                   read=True,
                                   getErrorMsg=True,
                                   **cmd)

        if ret != 0:
            if rast:
                message = _("Unable to zoom to raster map <%s>.") % rast[0] + \
                    "\n\n" + _("Details:") + " %s" % msg
            elif vect:
                message = _("Unable to zoom to vector map <%s>.") % vect[0] + \
                    "\n\n" + _("Details:") + " %s" % msg
            else:
                message = _(
                    "Unable to get current geographic extent. "
                    "Force quiting wxGUI. Please manually run g.region to "
                    "fix the problem.")
            GError(message)
            return self.region

        for r in reg.splitlines():
            key, val = r.split("=", 1)
            try:
                region[key] = float(val)
            except ValueError:
                region[key] = val

        # back to original gisrc
        if self.gisrc:
            os.environ["GISRC"] = gisrc_orig

        # restore region
        if tmpreg:
            os.environ["GRASS_REGION"] = tmpreg

        Debug.msg(3, "Map.GetRegion(): %s" % region)

        if update:
            self.region = region

        return region
Example #22
0
    def _export(self, exportInfo, decorations):
        size = self.frame.animationPanel.GetSize()
        if self.temporalMode == TemporalMode.TEMPORAL:
            timeLabels, mapNamesDict = self.temporalManager.GetLabelsAndMaps()
            frameCount = len(timeLabels)
        else:
            frameCount = self.animationData[
                0].mapCount  # should be the same for all

        animWinSize = []
        animWinPos = []
        animWinIndex = []
        legends = [anim.legendCmd for anim in self.animationData]
        # determine position and sizes of bitmaps
        for i, (win, anim) in enumerate(zip(self.mapwindows, self.animations)):
            if anim.IsActive():
                pos = win.GetPosition()
                animWinPos.append(pos)
                animWinSize.append(win.GetSize())
                animWinIndex.append(i)

        images = []
        busy = wx.BusyInfo(
            _("Preparing export, please wait..."),
            parent=self.frame)
        wx.Yield()
        lastBitmaps = {}
        fgcolor = UserSettings.Get(
            group='animation',
            key='font',
            subkey='fgcolor')
        bgcolor = UserSettings.Get(
            group='animation',
            key='font',
            subkey='bgcolor')
        for frameIndex in range(frameCount):
            image = wx.EmptyImage(*size)
            image.Replace(0, 0, 0, 255, 255, 255)
            # collect bitmaps of all windows and paste them into the one
            for i in animWinIndex:
                frameId = self.animations[i].GetFrame(frameIndex)
                if not UserSettings.Get(group='animation', key='temporal',
                                        subkey=['nodata', 'enable']):
                    if frameId is not None:
                        bitmap = self.bitmapProvider.GetBitmap(frameId)
                        lastBitmaps[i] = bitmap
                    else:
                        if i not in lastBitmaps:
                            lastBitmaps[i] = wx.NullBitmap()
                else:
                    bitmap = self.bitmapProvider.GetBitmap(frameId)
                    lastBitmaps[i] = bitmap

                im = wx.ImageFromBitmap(lastBitmaps[i])

                # add legend if used
                legend = legends[i]
                if legend:
                    legendBitmap = self.bitmapProvider.LoadOverlay(legend)
                    x, y = self.mapwindows[i].GetOverlayPos()
                    legImage = wx.ImageFromBitmap(legendBitmap)
                    # not so nice result, can we handle the transparency
                    # otherwise?
                    legImage.ConvertAlphaToMask()
                    im.Paste(legImage, x, y)

                if im.GetSize() != animWinSize[i]:
                    im.Rescale(*animWinSize[i])
                image.Paste(im, *animWinPos[i])
            # paste decorations
            for decoration in decorations:
                # add image
                x = decoration['pos'][0] / 100. * size[0]
                y = decoration['pos'][1] / 100. * size[1]
                if decoration['name'] == 'image':
                    decImage = wx.Image(decoration['file'])
                elif decoration['name'] == 'time':
                    timeLabel = timeLabels[frameIndex]
                    if timeLabel[1]:  # interval
                        text = _("%(from)s %(dash)s %(to)s") % {
                            'from': timeLabel[0],
                            'dash': u"\u2013", 'to': timeLabel[1]}
                    else:
                        if self.temporalManager.GetTemporalType() == TemporalType.ABSOLUTE:
                            text = timeLabel[0]
                        else:
                            text = _("%(start)s %(unit)s") % \
                                {'start': timeLabel[0], 'unit': timeLabel[2]}

                    decImage = RenderText(
                        text, decoration['font'],
                        bgcolor, fgcolor).ConvertToImage()
                elif decoration['name'] == 'text':
                    text = decoration['text']
                    decImage = RenderText(
                        text, decoration['font'],
                        bgcolor, fgcolor).ConvertToImage()

                image.Paste(decImage, x, y)

            images.append(image)
        del busy

        # export
        pilImages = [WxImageToPil(image) for image in images]
        busy = wx.BusyInfo(_("Exporting animation, please wait..."),
                           parent=self.frame)
        wx.Yield()
        try:
            if exportInfo['method'] == 'sequence':
                filename = os.path.join(
                    exportInfo['directory'],
                    exportInfo['prefix'] +
                    '.' +
                    exportInfo['format'].lower())
                writeIms(filename=filename, images=pilImages)
            elif exportInfo['method'] == 'gif':
                writeGif(filename=exportInfo['file'], images=pilImages,
                         duration=self.timeTick / float(1000), repeat=True)
            elif exportInfo['method'] == 'swf':
                writeSwf(filename=exportInfo['file'], images=pilImages,
                         duration=self.timeTick / float(1000), repeat=True)
            elif exportInfo['method'] == 'avi':
                writeAvi(filename=exportInfo['file'], images=pilImages,
                         duration=self.timeTick / float(1000),
                         encoding=exportInfo['encoding'],
                         inputOptions=exportInfo['options'])
        except Exception as e:
            del busy
            GError(parent=self.frame, message=str(e))
            return
        del busy
Example #23
0
    def _export(self, exportInfo, decorations):
        size = self.frame.animationPanel.GetSize()
        if self.temporalMode == TemporalMode.TEMPORAL:
            timeLabels, mapNamesDict = self.temporalManager.GetLabelsAndMaps()
            frameCount = len(timeLabels)
        else:
            frameCount = self.animationData[
                0].mapCount  # should be the same for all

        animWinSize = []
        animWinPos = []
        animWinIndex = []
        legends = [anim.legendCmd for anim in self.animationData]
        # determine position and sizes of bitmaps
        for i, (win, anim) in enumerate(zip(self.mapwindows, self.animations)):
            if anim.IsActive():
                pos = win.GetPosition()
                animWinPos.append(pos)
                animWinSize.append(win.GetSize())
                animWinIndex.append(i)

        images = []
        busy = wx.BusyInfo(_("Preparing export, please wait..."),
                           parent=self.frame)
        wx.GetApp().Yield()
        lastBitmaps = {}
        fgcolor = UserSettings.Get(group="animation",
                                   key="font",
                                   subkey="fgcolor")
        bgcolor = UserSettings.Get(group="animation",
                                   key="font",
                                   subkey="bgcolor")
        for frameIndex in range(frameCount):
            image = EmptyImage(*size)
            image.Replace(0, 0, 0, 255, 255, 255)
            # collect bitmaps of all windows and paste them into the one
            for i in animWinIndex:
                frameId = self.animations[i].GetFrame(frameIndex)
                if not UserSettings.Get(group="animation",
                                        key="temporal",
                                        subkey=["nodata", "enable"]):
                    if frameId is not None:
                        bitmap = self.bitmapProvider.GetBitmap(frameId)
                        lastBitmaps[i] = bitmap
                    else:
                        if i not in lastBitmaps:
                            lastBitmaps[i] = wx.NullBitmap()
                else:
                    bitmap = self.bitmapProvider.GetBitmap(frameId)
                    lastBitmaps[i] = bitmap

                im = ImageFromBitmap(lastBitmaps[i])

                # add legend if used
                legend = legends[i]
                if legend:
                    legendBitmap = self.bitmapProvider.LoadOverlay(legend)
                    x, y = self.mapwindows[i].GetOverlayPos()
                    legImage = ImageFromBitmap(legendBitmap)
                    # not so nice result, can we handle the transparency
                    # otherwise?
                    legImage.ConvertAlphaToMask()
                    im.Paste(legImage, x, y)

                if im.GetSize() != animWinSize[i]:
                    im.Rescale(*animWinSize[i])
                image.Paste(im, *animWinPos[i])
            # paste decorations
            for decoration in decorations:
                # add image
                x = decoration["pos"][0] / 100.0 * size[0]
                y = decoration["pos"][1] / 100.0 * size[1]
                if decoration["name"] == "image":
                    decImage = wx.Image(decoration["file"])
                elif decoration["name"] == "time":
                    timeLabel = timeLabels[frameIndex]
                    if timeLabel[1]:  # interval
                        text = _("%(from)s %(dash)s %(to)s") % {
                            "from": timeLabel[0],
                            "dash": "\u2013",
                            "to": timeLabel[1],
                        }
                    else:
                        if (self.temporalManager.GetTemporalType() ==
                                TemporalType.ABSOLUTE):
                            text = timeLabel[0]
                        else:
                            text = _("%(start)s %(unit)s") % {
                                "start": timeLabel[0],
                                "unit": timeLabel[2],
                            }

                    decImage = RenderText(text, decoration["font"], bgcolor,
                                          fgcolor).ConvertToImage()
                elif decoration["name"] == "text":
                    text = decoration["text"]
                    decImage = RenderText(text, decoration["font"], bgcolor,
                                          fgcolor).ConvertToImage()

                image.Paste(decImage, x, y)

            images.append(image)
        del busy

        # export
        pilImages = [WxImageToPil(image) for image in images]
        self.busy = wx.BusyInfo(_("Exporting animation, please wait..."),
                                parent=self.frame)
        wx.GetApp().Yield()
        try:

            def export_avi_callback(event):
                error = event.ret
                del self.busy
                if error:
                    GError(parent=self.frame, message=error)
                    return

            if exportInfo["method"] == "sequence":
                filename = os.path.join(
                    exportInfo["directory"],
                    exportInfo["prefix"] + "." + exportInfo["format"].lower(),
                )
                writeIms(filename=filename, images=pilImages)
            elif exportInfo["method"] == "gif":
                writeGif(
                    filename=exportInfo["file"],
                    images=pilImages,
                    duration=self.timeTick / float(1000),
                    repeat=True,
                )
            elif exportInfo["method"] == "swf":
                writeSwf(
                    filename=exportInfo["file"],
                    images=pilImages,
                    duration=self.timeTick / float(1000),
                    repeat=True,
                )
            elif exportInfo["method"] == "avi":
                thread = gThread()
                thread.Run(
                    callable=writeAvi,
                    filename=exportInfo["file"],
                    images=pilImages,
                    duration=self.timeTick / float(1000),
                    encoding=exportInfo["encoding"],
                    inputOptions=exportInfo["options"],
                    bg_task=True,
                    ondone=export_avi_callback,
                )
        except Exception as e:
            del self.busy
            GError(parent=self.frame, message=str(e))
            return
        if exportInfo["method"] in ("sequence", "gif", "swf"):
            del self.busy
 def errMsg(self, label):
     print(label)
     GError(label)
Example #25
0
 def export_avi_callback(event):
     error = event.ret
     del self.busy
     if error:
         GError(parent=self.frame, message=error)
         return
Example #26
0
    def StartEditing(self, mapLayer):
        """Start editing selected vector map layer.

        :param mapLayer: MapLayer to be edited
        """
        # check if topology is available (skip for hidden - temporary
        # maps, see iclass for details)
        if (
            not mapLayer.IsHidden()
            and grass.vector_info(mapLayer.GetName())["level"] != 2
        ):
            dlg = wx.MessageDialog(
                parent=self.MapWindow,
                message=_(
                    "Topology for vector map <%s> is not available. "
                    "Topology is required by digitizer.\nDo you want to "
                    "rebuild topology (takes some time) and open the vector map "
                    "for editing?"
                )
                % mapLayer.GetName(),
                caption=_("Digitizer error"),
                style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE,
            )
            if dlg.ShowModal() == wx.ID_YES:
                RunCommand("v.build", map=mapLayer.GetName())
            else:
                return

        # deactive layer
        self.Map.ChangeLayerActive(mapLayer, False)

        # clean map canvas
        self.MapWindow.EraseMap()

        # unset background map if needed
        if mapLayer:
            if (
                UserSettings.Get(
                    group="vdigit",
                    key="bgmap",
                    subkey="value",
                    settings_type="internal",
                )
                == mapLayer.GetName()
            ):
                UserSettings.Set(
                    group="vdigit",
                    key="bgmap",
                    subkey="value",
                    value="",
                    settings_type="internal",
                )

            self.parent.SetStatusText(
                _("Please wait, " "opening vector map <%s> for editing...")
                % mapLayer.GetName(),
                0,
            )

        self.MapWindow.pdcVector = PseudoDC()
        self.digit = self.MapWindow.digit = self.digitClass(mapwindow=self.MapWindow)

        self.mapLayer = mapLayer
        # open vector map (assume that 'hidden' map layer is temporary vector
        # map)
        if self.digit.OpenMap(mapLayer.GetName(), tmp=mapLayer.IsHidden()) is None:
            self.mapLayer = None
            self.StopEditing()
            return False

        # check feature type (only for OGR layers)
        self.fType = self.digit.GetFeatureType()
        self.EnableAll()
        self.EnableUndo(False)
        self.EnableRedo(False)

        if self.fType == "point":
            for tool in (
                self.addLine,
                self.addArea,
                self.moveVertex,
                self.addVertex,
                self.removeVertex,
                self.editLine,
            ):
                self.EnableTool(tool, False)
        elif self.fType == "linestring":
            for tool in (self.addPoint, self.addArea):
                self.EnableTool(tool, False)
        elif self.fType == "polygon":
            for tool in (self.addPoint, self.addLine):
                self.EnableTool(tool, False)
        elif self.fType:
            GError(
                parent=self,
                message=_(
                    "Unsupported feature type '%(type)s'. Unable to edit "
                    "OGR layer <%(layer)s>."
                )
                % {"type": self.fType, "layer": mapLayer.GetName()},
            )
            self.digit.CloseMap()
            self.mapLayer = None
            self.StopEditing()
            return False

        # update toolbar
        if self.combo:
            self.combo.SetValue(mapLayer.GetName())
        if "map" in self.parent.toolbars:
            self.parent.toolbars["map"].combo.SetValue(_("Vector digitizer"))

        # here was dead code to enable vdigit button in toolbar
        # with if to ignore iclass
        # some signal (DigitizerStarted) can be emitted here

        Debug.msg(4, "VDigitToolbar.StartEditing(): layer=%s" % mapLayer.GetName())

        # change cursor
        if self.MapWindow.mouse["use"] == "pointer":
            self.MapWindow.SetNamedCursor("cross")

        if not self.MapWindow.resize:
            self.MapWindow.UpdateMap(render=True)

        # respect opacity
        opacity = mapLayer.GetOpacity()

        if opacity < 1.0:
            alpha = int(opacity * 255)
            self.digit.GetDisplay().UpdateSettings(alpha=alpha)

        # emit signal
        layerTree = self._giface.GetLayerTree()
        if layerTree:
            item = layerTree.FindItemByData("maplayer", self.mapLayer)
        else:
            item = None
        self.editingStarted.emit(
            vectMap=mapLayer.GetName(), digit=self.digit, layerItem=item
        )

        return True
Example #27
0
    def _pageContributors(self, extra=False):
        """Contributors info"""
        if extra:
            contribfile = os.path.join(os.getenv("GISBASE"),
                                       "contributors_extra.csv")
        else:
            contribfile = os.path.join(os.getenv("GISBASE"),
                                       "contributors.csv")
        if os.path.exists(contribfile):
            contribFile = codecs.open(contribfile, encoding='utf-8', mode='r')
            contribs = list()
            errLines = list()
            for line in contribFile.readlines()[1:]:
                line = line.rstrip('\n')
                try:
                    if extra:
                        name, email, country, rfc2_agreed = line.split(',')
                    else:
                        cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(
                            ',')
                except ValueError:
                    errLines.append(line)
                    continue
                if extra:
                    contribs.append((name, email, country))
                else:
                    contribs.append((name, email, country, osgeo_id))

            contribFile.close()

            if errLines:
                GError(
                    parent=self,
                    message=_("Error when reading file '%s'.") % contribfile +
                    "\n\n" + _("Lines:") +
                    " %s" % os.linesep.join(map(DecodeString, errLines)))
        else:
            contribs = None

        contribwin = ScrolledPanel(self.aboutNotebook)
        contribwin.SetAutoLayout(True)
        contribwin.SetupScrolling()
        contribwin.sizer = wx.BoxSizer(wx.VERTICAL)

        if not contribs:
            contribtxt = StaticText(contribwin,
                                    id=wx.ID_ANY,
                                    label=_('%s file missing') % contribfile)
            contribwin.sizer.Add(contribtxt,
                                 proportion=1,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=3)
        else:
            if extra:
                items = (_('Name'), _('E-mail'), _('Country'))
            else:
                items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
            contribBox = wx.FlexGridSizer(cols=len(items), vgap=5, hgap=5)
            for item in items:
                text = StaticText(parent=contribwin, id=wx.ID_ANY, label=item)
                text.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0,
                                     ""))
                contribBox.Add(text)
            for vals in sorted(contribs, key=lambda x: x[0]):
                for item in vals:
                    contribBox.Add(
                        StaticText(parent=contribwin, id=wx.ID_ANY,
                                   label=item))
            contribwin.sizer.Add(contribBox,
                                 proportion=1,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=3)

        contribwin.SetSizer(contribwin.sizer)
        contribwin.Layout()

        return contribwin
Example #28
0
    def GetSQLString(self, updateValues=False):
        """Create SQL statement string based on self.sqlStatement

        Show error message when invalid values are entered.

        If updateValues is True, update dataFrame according to values
        in textfields.
        """
        sqlCommands = []
        # find updated values for each layer/category
        for layer in self.mapDBInfo.layers.keys():  # for each layer
            table = self.mapDBInfo.GetTable(layer)
            key = self.mapDBInfo.GetKeyColumn(layer)
            columns = self.mapDBInfo.GetTableDesc(table)
            for idx in range(len(columns[key]['values'])):  # for each category
                updatedColumns = []
                updatedValues = []
                for name in columns.keys():
                    if name == key:
                        cat = columns[name]['values'][idx]
                        continue
                    ctype = columns[name]['ctype']
                    value = columns[name]['values'][idx]
                    id = columns[name]['ids'][idx]
                    try:
                        newvalue = self.FindWindowById(id).GetValue()
                    except:
                        newvalue = self.FindWindowById(id).GetLabel()

                    if newvalue:
                        try:
                            if ctype == int:
                                newvalue = int(newvalue)
                            elif ctype == float:
                                newvalue = float(newvalue)
                        except ValueError:
                            GError(
                                parent=self,
                                message=
                                _("Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s."
                                  ) % {
                                      'col': name,
                                      'value': str(newvalue),
                                      'type': columns[name]['type'].lower()
                                  },
                                showTraceback=False)
                            sqlCommands.append(None)
                            continue
                    else:
                        if self.action == 'add':
                            continue

                    if newvalue != value:
                        updatedColumns.append(name)
                        if newvalue == '':
                            updatedValues.append('NULL')
                        else:
                            if ctype != str:
                                updatedValues.append(str(newvalue))
                            else:
                                updatedValues.append(
                                    "'" + newvalue.replace("'", "''") + "'")
                        columns[name]['values'][idx] = newvalue

                if self.action != "add" and len(updatedValues) == 0:
                    continue

                if self.action == "add":
                    sqlString = "INSERT INTO %s (%s," % (table, key)
                else:
                    sqlString = "UPDATE %s SET " % table

                for idx in range(len(updatedColumns)):
                    name = updatedColumns[idx]
                    if self.action == "add":
                        sqlString += name + ","
                    else:
                        sqlString += name + "=" + updatedValues[idx] + ","

                sqlString = sqlString[:-1]  # remove last comma

                if self.action == "add":
                    sqlString += ") VALUES (%s," % cat
                    for value in updatedValues:
                        sqlString += value + ","
                    sqlString = sqlString[:-1]  # remove last comma
                    sqlString += ")"
                else:
                    sqlString += " WHERE %s=%s" % (key, cat)
                sqlCommands.append(sqlString)
            # for each category
        # for each layer END

        Debug.msg(3,
                  "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)

        return sqlCommands
Example #29
0
    def _getData(self, timeseries):
        """Load data and read properties"""
        self.timeData = {}
        mode = None
        unit = None

        for series in timeseries:
            name = series[0] + '@' + series[1]
            etype = series[2]
            sp = tgis.dataset_factory(etype, name)
            if not sp.is_in_db(dbif=self.dbif):
                GError(
                    self,
                    message=_("Dataset <%s> not found in temporal database") %
                    (name))
                return

            sp.select(dbif=self.dbif)

            self.timeData[name] = {}
            self.timeData[name]['elementType'] = series[2]
            self.timeData[name][
                'temporalType'] = sp.get_temporal_type()  # abs/rel

            if mode is None:
                mode = self.timeData[name]['temporalType']
            elif self.timeData[name]['temporalType'] != mode:
                GError(
                    parent=self, message=_(
                        "Datasets have different temporal type "
                        "(absolute x relative), which is not allowed."))
                return

            # check topology
            maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
            self.timeData[name]['validTopology'] = sp.check_temporal_topology(
                maps=maps, dbif=self.dbif)

            self.timeData[name][
                'temporalMapType'] = sp.get_map_time()  # point/interval
            self.timeData[name]['unit'] = None  # only with relative
            if self.timeData[name]['temporalType'] == 'relative':
                start, end, self.timeData[name][
                    'unit'] = sp.get_relative_time()
                if unit is None:
                    unit = self.timeData[name]['unit']
                elif self.timeData[name]['unit'] != unit:
                    GError(
                        self, _("Datasets have different time unit which is not allowed."))
                    return

            self.timeData[name]['start_datetime'] = []
            # self.timeData[name]['start_plot'] = []
            self.timeData[name]['end_datetime'] = []
            # self.timeData[name]['end_plot'] = []
            self.timeData[name]['names'] = []
            self.timeData[name]['north'] = []
            self.timeData[name]['south'] = []
            self.timeData[name]['west'] = []
            self.timeData[name]['east'] = []

            columns = ','.join(['name', 'start_time', 'end_time',
                                'north', 'south', 'west', 'east'])

            rows = sp.get_registered_maps(columns=columns, where=None,
                                          order='start_time', dbif=self.dbif)
            if not rows:
                GError(
                    parent=self,
                    message=_("Dataset <{name}> is empty").format(
                        name=series[0] +
                        '@' +
                        series[1]))
                return
            for row in rows:
                mapName, start, end, north, south, west, east = row
                self.timeData[name]['start_datetime'].append(start)
                self.timeData[name]['end_datetime'].append(end)
                self.timeData[name]['names'].append(mapName)
                self.timeData[name]['north'].append(north)
                self.timeData[name]['south'].append(south)
                self.timeData[name]['west'].append(west)
                self.timeData[name]['east'].append(east)

        self.temporalType = mode
        self.unit = unit
Example #30
0
    def _pageTranslators(self):
        """Translators info"""
        translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
        if os.path.exists(translatorsfile):
            translatorsFile = codecs.open(translatorsfile,
                                          encoding='utf-8',
                                          mode='r')
            translators = dict()
            errLines = list()
            for line in translatorsFile.readlines()[1:]:
                line = line.rstrip('\n')
                try:
                    name, email, languages = line.split(',')
                except ValueError:
                    errLines.append(line)
                    continue
                for language in languages.split(' '):
                    if language not in translators:
                        translators[language] = list()
                    translators[language].append((name, email))
            translatorsFile.close()

            if errLines:
                GError(parent=self,
                       message=_("Error when reading file '%s'.") %
                       translatorsfile + "\n\n" + _("Lines:") +
                       " %s" % os.linesep.join(map(DecodeString, errLines)))
        else:
            translators = None

        translatorswin = ScrolledPanel(self.aboutNotebook)
        translatorswin.SetBackgroundColour('WHITE')
        translatorswin.SetAutoLayout(True)
        translatorswin.SetupScrolling()
        translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)

        if not translators:
            translatorstxt = StaticText(translatorswin,
                                        id=wx.ID_ANY,
                                        label=_('%s file missing') %
                                        'translators.csv')
            translatorswin.sizer.Add(translatorstxt,
                                     proportion=1,
                                     flag=wx.EXPAND | wx.ALL,
                                     border=3)
        else:
            translatorsBox = wx.FlexGridSizer(cols=4, vgap=5, hgap=5)
            languages = sorted(translators.keys())
            tname = StaticText(parent=translatorswin,
                               id=wx.ID_ANY,
                               label=_('Name'))
            tname.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
            translatorsBox.Add(tname)
            temail = StaticText(parent=translatorswin,
                                id=wx.ID_ANY,
                                label=_('E-mail'))
            temail.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
            translatorsBox.Add(temail)
            tlang = StaticText(parent=translatorswin,
                               id=wx.ID_ANY,
                               label=_('Language'))
            tlang.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
            translatorsBox.Add(tlang)
            tnat = StaticText(parent=translatorswin,
                              id=wx.ID_ANY,
                              label=_('Nation'))
            tnat.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
            translatorsBox.Add(tnat)
            for lang in languages:
                for translator in translators[lang]:
                    name, email = translator
                    translatorsBox.Add(
                        StaticText(parent=translatorswin,
                                   id=wx.ID_ANY,
                                   label=name))
                    translatorsBox.Add(
                        StaticText(parent=translatorswin,
                                   id=wx.ID_ANY,
                                   label=email))
                    translatorsBox.Add(
                        StaticText(parent=translatorswin,
                                   id=wx.ID_ANY,
                                   label=lang))
                    flag = os.path.join(globalvar.ICONDIR, "flags",
                                        "%s.png" % lang.lower())
                    if os.path.exists(flag):
                        flagBitmap = wx.StaticBitmap(
                            translatorswin, wx.ID_ANY,
                            wx.Bitmap(name=flag, type=wx.BITMAP_TYPE_PNG))
                        translatorsBox.Add(flagBitmap)
                    else:
                        translatorsBox.Add(
                            StaticText(parent=translatorswin,
                                       id=wx.ID_ANY,
                                       label=lang))

            translatorswin.sizer.Add(translatorsBox,
                                     proportion=1,
                                     flag=wx.EXPAND | wx.ALL,
                                     border=3)

        translatorswin.SetSizer(translatorswin.sizer)
        translatorswin.Layout()

        return translatorswin