def __init__(self, **kwargs): Debug.msg(1, "FloatSlider.__init__()") wx.Slider.__init__(self, **kwargs) self.coef = 1. #init range self.minValueOrig = 0 self.maxValueOrig = 1
def OnEditLabel(self, event): """End label editing""" if (self.selected_layer): item = event.GetItem() self.old_name = self.GetItemText(item) Debug.msg(1, "End label edit "+self.old_name) wx.CallAfter(self.afterEdit, self, item)
def OnDelete(self, event): """Delete layer or mapset""" if (self.selected_layer): string = self.GetItemText(self.selected_layer) self.ChangeEnvironment(self.GetItemText(self.selected_location), self.GetItemText(self.selected_mapset)) removed = 0 # TODO: rewrite this that it will tell map type in the dialog if (self._confirmDialog(question=_('Do you really want to delete map <{m}>?').format(m=string), title=_('Delete map')) == wx.ID_YES): label = _("Deleting") + " " + string + " ..." self.showNotification.emit(message=label) if (self.GetItemText(self.selected_type)=='vect'): removed = RunCommand('g.remove', flags='f', type='vect', pattern=string) elif (self.GetItemText(self.selected_type)=='rast'): removed = RunCommand('g.remove', flags='f', type='rast', pattern=string) else: removed = RunCommand('g.remove', flags='f', type='rast3d', pattern=string) if (removed==0): self.Delete(self.selected_layer) Debug.msg(1,"LAYER "+string+" DELETED") label = "g.remove -f type="+self.GetItemText(self.selected_type)+" pattern="+string+" -- completed" # generate this message (command) automatically? self.showNotification.emit(message=label) self.RestoreBackup()
def OnSubmit(self, event): """Submit records""" layer = 1 close = True enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value') if not enc and 'GRASS_DB_ENCODING' in os.environ: enc = os.environ['GRASS_DB_ENCODING'] for sql in self.GetSQLString(updateValues = True): if not sql: close = False continue if enc: sql = sql.encode(enc) else: sql = sql.encode('utf-8') driver, database = self.mapDBInfo.GetDbSettings(layer) Debug.msg(1, "SQL: %s" % sql) RunCommand('db.execute', parent = self, quiet = True, input = '-', stdin = sql, driver = driver, database = database) layer += 1 if close and self.closeDialog.IsChecked(): self.OnClose(event)
def UpdateHist(self, img=None): """Update canvas if histogram options changes or window changes geometry """ Debug.msg( 2, "BufferedWindow.UpdateHist(%s): render=%s" % (img, self.render)) if not self.render: return # render new map images # set default font and encoding environmental variables if "GRASS_FONT" in os.environ: self._oldfont = os.environ["GRASS_FONT"] if self.parent.font: os.environ["GRASS_FONT"] = self.parent.font if "GRASS_ENCODING" in os.environ: self._oldencoding = os.environ["GRASS_ENCODING"] if self.parent.encoding is not None and self.parent.encoding != "ISO-8859-1": os.environ[GRASS_ENCODING] = self.parent.encoding # using active comp region self.Map.GetRegion(update=True) self.Map.width, self.Map.height = self.GetClientSize() self.mapfile = self.Map.Render(force=self.render) self.Map.GetRenderMgr().renderDone.connect(self.UpdateHistDone)
def OnEditLabel(self, node, event): """End label editing""" if self.selected_layer and not event.IsEditCancelled(): self.old_name = node.label Debug.msg(1, "End label edit {name}".format(name=self.old_name)) self.new_name = event.GetLabel() self.Rename()
def OnDelete(self, event): """Delete layer or mapset""" if self.selected_layer: string = self.selected_layer.label gisrc, env = getEnvironment(self.gisdbase, self.selected_location.label, self.selected_mapset.label) removed = 0 # TODO: rewrite this that it will tell map type in the dialog if self._confirmDialog(question=_('Do you really want to delete map <{m}>?').format(m=string), title=_('Delete map')) == wx.ID_YES: label = _("Deleting {name}...").format(name=string) self.showNotification.emit(message=label) if self.selected_type.label == 'vector': removed, cmd = self._runCommand('g.remove', flags='f', type='vector', name=string, env=env) elif self.selected_type.label == 'raster': removed, cmd = self._runCommand('g.remove', flags='f', type='raster', name=string, env=env) else: removed, cmd = self._runCommand('g.remove', flags='f', type='raster_3d', name=string, env=env) if removed == 0: self._model.RemoveNode(self.selected_layer) self.RefreshNode(self.selected_type, recursive=True) Debug.msg(1, "LAYER " + string + " DELETED") self.showNotification.emit(message= _("{cmd} -- completed").format(cmd=cmd)) gscript.try_remove(gisrc)
def _setEnvironment(width, height, filename, transparent, bgcolor): """Sets environmental variables for 2D rendering. :param width: rendering width :param height: rendering height :param filename: file name :param transparent: use transparency :param bgcolor: background color as a tuple of 3 values 0 to 255 """ Debug.msg( 5, "_setEnvironment: width={w}, height={h}, " "filename={f}, transparent={t}, bgcolor={b}".format( w=width, h=height, f=filename, t=transparent, b=bgcolor)) os.environ['GRASS_RENDER_WIDTH'] = str(width) os.environ['GRASS_RENDER_HEIGHT'] = str(height) driver = UserSettings.Get(group='display', key='driver', subkey='type') os.environ['GRASS_RENDER_IMMEDIATE'] = driver os.environ['GRASS_RENDER_BACKGROUNDCOLOR'] = '{r:02x}{g:02x}{b:02x}'.format( r=bgcolor[0], g=bgcolor[1], b=bgcolor[2]) os.environ['GRASS_RENDER_TRUECOLOR'] = "TRUE" if transparent: os.environ['GRASS_RENDER_TRANSPARENT'] = "TRUE" else: os.environ['GRASS_RENDER_TRANSPARENT'] = "FALSE" os.environ['GRASS_RENDER_FILE'] = str(filename)
def LoadOverlay(self, cmd): """Creates raster legend with d.legend :param cmd: d.legend command as a list :return: bitmap with legend """ Debug.msg(5, "BitmapProvider.LoadOverlay: cmd={c}".format(c=cmd)) fileHandler, filename = tempfile.mkstemp(suffix=".png") os.close(fileHandler) # Set the environment variables for this process _setEnvironment(self.imageWidth, self.imageHeight, filename, transparent=True, bgcolor=(0, 0, 0)) Debug.msg(1, "Render raster legend " + str(filename)) cmdTuple = cmdlist_to_tuple(cmd) returncode, stdout, messages = read2_command( cmdTuple[0], **cmdTuple[1]) if returncode == 0: return wx.BitmapFromImage(autoCropImageFromFile(filename)) else: os.remove(filename) raise GException(messages)
def Load(self, force=False, bgcolor=(255, 255, 255), nprocs=4): """Loads data, both 2D and 3D. In case of 2D, it creates composites, even when there is only 1 layer to compose (to be changed for speedup) :param force: if True reload all data, otherwise only missing data :param bgcolor: background color as a tuple of 3 values 0 to 255 :param nprocs: number of procs to be used for rendering """ Debug.msg(2, "BitmapProvider.Load: " "force={f}, bgcolor={b}, nprocs={n}".format(f=force, b=bgcolor, n=nprocs)) cmds = [] regions = [] if self._uniqueCmds: cmds.extend(self._uniqueCmds) regions.extend(self._regionsForUniqueCmds) if self._cmds3D: cmds.extend(self._cmds3D) regions.extend([None] * len(self._cmds3D)) count = self._dryRender(cmds, regions, force=force) self.renderingStarted.emit(count=count) # create no data bitmap if None not in self._bitmapPool or force: self._bitmapPool[None] = createNoDataBitmap( self.imageWidth, self.imageHeight) ok = self._renderer.Render( cmds, regions, regionFor3D=self._regionFor3D, bgcolor=bgcolor, force=force, nprocs=nprocs) self.renderingFinished.emit() if not ok: self.mapsLoaded.emit() # what to do here? return if self._cmdsForComposition: count = self._dryCompose( self._cmdsForComposition, self._regions, force=force) self.compositionStarted.emit(count=count) self._composer.Compose( self._cmdsForComposition, self._regions, self._opacities, bgcolor=bgcolor, force=force, nprocs=nprocs) self.compositionFinished.emit() if self._cmds3D: for cmd in self._cmds3D: self._bitmapPool[HashCmds([cmd], None)] = \ wx.Bitmap(GetFileFromCmd(self._tempDir, cmd, None)) self.mapsLoaded.emit()
def _pageStats(self): """Translation statistics info""" fname = "translation_status.json" statsfile = os.path.join(os.getenv("GISBASE"), fname) if os.path.exists(statsfile): statsFile = open(statsfile) import json jsStats = json.load(statsFile) else: jsStats = None self.statswin = ScrolledPanel(self.aboutNotebook) self.statswin.SetBackgroundColour('WHITE') self.statswin.SetAutoLayout(True) if not jsStats: Debug.msg(5, _("File <%s> not found") % fname) statsSizer = wx.BoxSizer(wx.VERTICAL) statstext = wx.StaticText(self.statswin, id=wx.ID_ANY, label=_('%s file missing') % fname) statsSizer.Add(item=statstext, proportion=1, flag=wx.EXPAND | wx.ALL, border=3) else: languages = sorted(jsStats['langs'].keys()) statsSizer = wx.BoxSizer(wx.VERTICAL) for lang in languages: v = jsStats['langs'][lang] panel = self._langPanel(lang, v) statsSizer.Add(panel) self.statswin.SetSizer(statsSizer) self.statswin.SetupScrolling(scroll_x=False, scroll_y=True) self.statswin.Layout() self.statswin.Fit() return self.statswin
def OnTool(self, event): """Tool selected """ if self.toolSwitcher: Debug.msg(3, "BaseToolbar.OnTool(): id = %s" % event.GetId()) self.toolSwitcher.ToolChanged(event.GetId()) event.Skip()
def OnDeleteMap(self, event): """Delete layer or mapset""" name = self.selected_layer.label gisrc, env = gscript.create_environment( gisenv()["GISDBASE"], self.selected_location.label, self.selected_mapset.label ) if ( self._confirmDialog( question=_( "Do you really want to delete map <{m}> of type <{etype}> from mapset " "<{mapset}> in location <{loc}>?" ).format( m=name, mapset=self.selected_mapset.label, etype=self.selected_type.label, loc=self.selected_location.label, ), title=_("Delete map"), ) == wx.ID_YES ): label = _("Deleting {name}...").format(name=name) self.showNotification.emit(message=label) if self.selected_type.label == "vector": removed, cmd = self._runCommand("g.remove", flags="f", type="vector", name=name, env=env) elif self.selected_type.label == "raster": removed, cmd = self._runCommand("g.remove", flags="f", type="raster", name=name, env=env) else: removed, cmd = self._runCommand("g.remove", flags="f", type="raster_3d", name=name, env=env) if removed == 0: self._model.RemoveNode(self.selected_layer) self.RefreshNode(self.selected_type, recursive=True) Debug.msg(1, "LAYER " + name + " DELETED") self.showNotification.emit(message=_("g.remove completed").format(cmd=cmd)) gscript.try_remove(gisrc)
def AlignExtentFromDisplay(self): """Align region extent based on display size from center point""" # calculate new bounding box based on center of display if self.region["ewres"] > self.region["nsres"]: res = self.region["ewres"] else: res = self.region["nsres"] Debug.msg(3, "Map.AlignExtentFromDisplay(): width=%d, height=%d, res=%f, center=%f,%f" % \ (self.width, self.height, res, self.region['center_easting'], self.region['center_northing'])) ew = (self.width / 2) * res ns = (self.height / 2) * res self.region['n'] = self.region['center_northing'] + ns self.region['s'] = self.region['center_northing'] - ns self.region['e'] = self.region['center_easting'] + ew self.region['w'] = self.region['center_easting'] - ew # LL locations if self.projinfo['proj'] == 'll': self.region['n'] = min(self.region['n'], 90.0) self.region['s'] = max(self.region['s'], -90.0)
def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0,0,0,0]): """Draws histogram or clears window """ if drawid == None: if pdctype == 'image' : drawid = imagedict[img] elif pdctype == 'clear': drawid == None else: drawid = wx.NewId() else: pdc.SetId(drawid) pdc.BeginDrawing() Debug.msg (3, "BufferedWindow.Draw(): id=%s, pdctype=%s, coord=%s" % (drawid, pdctype, coords)) if pdctype == 'clear': # erase the display bg = wx.WHITE_BRUSH pdc.SetBackground(bg) pdc.Clear() self.Refresh() pdc.EndDrawing() return if pdctype == 'image': bg = wx.TRANSPARENT_BRUSH pdc.SetBackground(bg) bitmap = wx.BitmapFromImage(img) w,h = bitmap.GetSize() pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map pdc.SetIdBounds(drawid, (coords[0],coords[1],w,h)) pdc.EndDrawing() self.Refresh()
def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler, pos = -1): """Add tool to the toolbar :param pos: if -1 add tool, if > 0 insert at given pos :return: id of tool """ bmpDisabled = wx.NullBitmap tool = -1 if label: tool = vars(self)[label] = wx.NewId() Debug.msg(3, "CreateTool(): tool=%d, label=%s bitmap=%s" % \ (tool, label, bitmap)) if pos < 0: toolWin = self.AddLabelTool(tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp) else: toolWin = self.InsertLabelTool(pos, tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp) self.handlers[tool] = handler self.Bind(wx.EVT_TOOL, handler, toolWin) self.Bind(wx.EVT_TOOL, self.OnTool, toolWin) else: # separator self.AddSeparator() return tool
def DeleteLayer(self, layer, overlay = False): """Removes layer from list of layers :param layer: layer instance in layer tree :param overlay: delete overlay (use self.DeleteOverlay() instead) :return: removed layer on success or None """ Debug.msg (3, "Map.DeleteLayer(): name=%s" % layer.name) if overlay: list = self.overlays else: list = self.layers if layer in list: if layer.mapfile: base = os.path.split(layer.mapfile)[0] mapfile = os.path.split(layer.mapfile)[1] tempbase = mapfile.split('.')[0] if base == '' or tempbase == '': return None basefile = os.path.join(base, tempbase) + r'.*' for f in glob.glob(basefile): os.remove(f) list.remove(layer) return layer return None
def AddOverlay(self, id, ltype, command, active = True, hidden = True, opacity = 1.0, render = False): """Adds overlay (grid, barscale, legend, etc.) to list of overlays :param id: overlay id (PseudoDC) :param ltype: overlay type (barscale, legend) :param command: GRASS command to render overlay :param active: overlay activated (True) or disabled (False) :param hidden: overlay is not shown in layer tree (if True) :param render: render an image (if True) :return: new layer on success :return: None on failure """ Debug.msg (2, "Map.AddOverlay(): cmd=%s, render=%d" % (command, render)) overlay = Overlay(id = id, ltype = ltype, cmd = command, Map = self, active = active, hidden = hidden, opacity = opacity) # add maplayer to the list of layers self.overlays.append(overlay) if render and command != '' and not overlay.Render(): raise GException(_("Unable to render overlay <%s>.") % ltype) return self.overlays[-1]
def Draw(self, dc): """Draws bitmap.""" Debug.msg(5, "AnimationWindow.Draw()") dc.Clear() # make sure you clear the bitmap! if self.bitmap.GetWidth() > 1: dc.DrawBitmap(self.bitmap, x=self.x, y=self.y)
def ClearOverlay(self): """Clear overlay (legend) """ Debug.msg(3, "AnimationWindow.ClearOverlay()") self._overlay = None self.bitmap_overlay = None self._pdc.RemoveAll() self.UpdateDrawing()
def OnAddPoint(self, event): """Add point to the vector map Laier""" Debug.msg(2, "VDigitToolbar.OnAddPoint()") self.action = {'desc': "addLine", 'type': "point", 'id': self.addPoint} self.MapWindow.mouse['box'] = 'point'
def OnAddLine(self, event): """Add line to the vector map layer""" Debug.msg(2, "VDigitToolbar.OnAddLine()") self.action = {'desc': "addLine", 'type': "line", 'id': self.addLine} self.MapWindow.mouse['box'] = 'line'
def _parseCapFile(self, cap_file): """Parse capabilities data and emits capParsed signal (see class constructor). """ try: self.cap = self.ws_drvs[self.ws]['cap_parser'](cap_file) except (IOError, ParseError) as error: error_msg = _( "%s web service was not found in fetched capabilities file from <%s>:\n%s\n" % (self.ws, self.conn['url'], str(error))) if Debug.GetLevel() != 0: Debug.msg(1, error_msg) self._postCapParsedEvt(None) else: self._postCapParsedEvt(error_msg=error_msg) return self.is_connected = True # WMS standard has formats defined for all layers if 'WMS' in self.ws: self.formats_list = sorted(self._getFormats()) self._updateFormatRadioBox(self.formats_list) self._setDefaultFormatVal() self.list.LoadData(self.cap) self.OnListSelChanged(event=None) self._postCapParsedEvt(None)
def __init__(self, parent, giface=None, id=wx.ID_ANY, title=_("Data catalog"), name='catalog', **kwargs): """Panel constructor """ self.showNotification = Signal('DataCatalog.showNotification') self.changeMapset = Signal('DataCatalog.changeMapset') self.changeLocation = Signal('DataCatalog.changeLocation') self.parent = parent self.baseTitle = title wx.Panel.__init__(self, parent=parent, id=id, **kwargs) self.SetName("DataCatalog") Debug.msg(1, "DataCatalog.__init__()") # toolbar self.toolbar = DataCatalogToolbar(parent=self) # tree with layers self.tree = DataCatalogTree(self, giface=giface) self.thread = gThread() self._loaded = False self.tree.showNotification.connect(self.showNotification) self.tree.changeMapset.connect(self.changeMapset) self.tree.changeLocation.connect(self.changeLocation) # some layout self._layout()
def OnTool(self, event): """Tool selected -> untoggles previusly selected tool in toolbar""" Debug.msg(3, "VDigitToolbar.OnTool(): id = %s" % event.GetId()) # set cursor self.MapWindow.SetNamedCursor('cross') self.MapWindow.mouse['box'] = 'point' self.MapWindow.mouse['use'] = 'pointer' aId = self.action.get('id', -1) BaseToolbar.OnTool(self, event) # clear tmp canvas if self.action['id'] != aId or aId == -1: self.MapWindow.polycoords = [] self.MapWindow.ClearLines(pdc=self.MapWindow.pdcTmp) if self.digit and \ len(self.MapWindow.digit.GetDisplay().GetSelected()) > 0: # cancel action self.MapWindow.OnMiddleDown(None) # set no action if self.action['id'] == -1: self.action = {'desc': '', 'type': '', 'id': -1} # set focus self.MapWindow.SetFocus()
def GetPPM(self): """Get pixel per meter .. todo:: now computed every time, is it necessary? .. todo:: enable user to specify ppm (and store it in UserSettings) """ # TODO: need to be fixed... ### screen X region problem ### user should specify ppm dc = wx.ScreenDC() dpSizePx = wx.DisplaySize() # display size in pixels dpSizeMM = wx.DisplaySizeMM() # display size in mm (system) dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches sysPpi = dc.GetPPI() comPpi = (dpSizePx[0] / dpSizeIn[0], dpSizePx[1] / dpSizeIn[1]) ppi = comPpi # pixel per inch ppm = ((ppi[0] / 2.54) * 100, # pixel per meter (ppi[1] / 2.54) * 100) Debug.msg(4, "MapFrameBase.GetPPM(): size: px=%d,%d mm=%f,%f " "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \ (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1], dpSizeIn[0], dpSizeIn[1], sysPpi[0], sysPpi[1], comPpi[0], comPpi[1], ppm[0], ppm[1])) return ppm
def GetMapScale(self, map = None): """Get current map scale :param map: Map instance (if none self.Map is used) """ if not map: map = self.GetMap() region = map.region ppm = self.GetPPM() heightCm = region['rows'] / ppm[1] * 100 widthCm = region['cols'] / ppm[0] * 100 Debug.msg(4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" % (widthCm, heightCm)) xscale = (region['e'] - region['w']) / (region['cols'] / ppm[0]) yscale = (region['n'] - region['s']) / (region['rows'] / ppm[1]) scale = (xscale + yscale) / 2. Debug.msg(3, "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" % \ (xscale, yscale, scale)) return scale
def OnDisplayLayer(self, event): """Display layer in current graphics view""" layerName = [] if self.selected_location.label == gisenv()["LOCATION_NAME"] and self.selected_mapset: string = self.selected_layer.label + "@" + self.selected_mapset.label layerName.append(string) label = _("Displaying {name}...").format(name=string) self.showNotification.emit(message=label) label = ( "d." + self.selected_type.label[:4] + " --q map=" + string + _(" -- completed. Go to Layers tab for further operations.") ) if self.selected_type.label == "vector": self._giface.lmgr.AddMaps(layerName, "vector", True) elif self.selected_type.label == "raster": self._giface.lmgr.AddMaps(layerName, "raster", True) else: self._giface.lmgr.AddMaps(layerName, "raster_3d", True) # generate this message (command) automatically? label = "d.rast --q map=" + string + _(" -- completed. Go to Layers tab for further operations.") self.showNotification.emit(message=label) Debug.msg(1, "LAYER " + self.selected_layer.label + " DISPLAYED") else: GError(_("Failed to display layer: not in current mapset or invalid layer"), parent=self)
def _resize(self): Debug.msg(1, "MapFrame._resize():") wm, hw = self.MapWindow.GetClientSize() wf, hf = self.GetSize() dw = wf - wm dh = hf - hw self.SetSize((wf + dw, hf + dh))
def OnCmdOutput(self, event): """Manage cmd output. """ if Debug.GetLevel() != 0: Debug.msg(1, event.text) elif event.type != 'message' and event.type != 'warning': self.cmd_err_str += event.text + os.linesep
def __delitem__(self, key): self.referenceCount[key] -= 1 Debug.msg(5, 'DictRefCounter.__delitem__: -1 for key {k}'.format(k=key))
def __init__(self, parent, toolSwitcher, MapWindow, digitClass, giface, tools=[]): self.MapWindow = MapWindow self.Map = MapWindow.GetMap() # Map class instance self.tools = tools self.digitClass = digitClass BaseToolbar.__init__(self, parent, toolSwitcher) self.digit = None self._giface = giface self.fType = None # feature type for simple features editing self.editingStarted = Signal("VDigitToolbar.editingStarted") self.editingStopped = Signal("VDigitToolbar.editingStopped") self.editingBgMap = Signal("VDigitToolbar.editingBgMap") self.quitDigitizer = Signal("VDigitToolbar.quitDigitizer") layerTree = self._giface.GetLayerTree() if layerTree: self.editingStarted.connect(layerTree.StartEditing) self.editingStopped.connect(layerTree.StopEditing) self.editingBgMap.connect(layerTree.SetBgMapForEditing) # bind events self.Bind(wx.EVT_SHOW, self.OnShow) # currently selected map layer for editing (reference to MapLayer # instance) self.mapLayer = None # list of vector layers from Layer Manager (only in the current mapset) self.layers = [] self.comboid = self.combo = None self.undo = -1 self.redo = -1 # only one dialog can be open self.settingsDialog = None # create toolbars (two rows optionally) self.InitToolbar(self._toolbarData()) self._default = -1 # default action (digitize new point, line, etc.) self.action = {'desc': '', 'type': '', 'id': -1} self._currentAreaActionType = None # list of available vector maps self.UpdateListOfLayers(updateTool=True) for tool in ('addPoint', 'addLine', 'addBoundary', 'addCentroid', 'addArea', 'addVertex', 'deleteLine', 'deleteArea', 'displayAttr', 'displayCats', 'editLine', 'moveLine', 'moveVertex', 'removeVertex', 'additionalTools'): if hasattr(self, tool): tool = getattr(self, tool) self.toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self, tool=tool) else: Debug.msg(1, '%s skipped' % tool) # custom button for digitization of area/boundary/centroid # TODO: could this be somehow generalized? nAreaTools = 0 if self.tools and 'addBoundary' in self.tools: nAreaTools += 1 if self.tools and 'addCentroid' in self.tools: nAreaTools += 1 if self.tools and 'addArea' in self.tools: nAreaTools += 1 if nAreaTools != 1: self.areaButton = self.CreateSelectionButton( _("Select area/boundary/centroid tool")) self.areaButtonId = self.InsertControl(5, self.areaButton) self.areaButton.Bind(wx.EVT_BUTTON, self.OnAddAreaMenu) # realize toolbar self.Realize() # workaround for Mac bug. May be fixed by 2.8.8, but not before then. if self.combo: self.combo.Hide() self.combo.Show() # disable undo/redo if self.undo > 0: self.EnableTool(self.undo, False) if self.redo > 0: self.EnableTool(self.redo, False) self.FixSize(width=105)
def OnSashChanging(self, event): """Sash position is changing, slider must be moved too.""" Debug.msg(5, "SwipeMapPanel.OnSashChanging()") self.slider.SetValue(self.splitter.GetSashPosition()) event.Skip()
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 not 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
def OnPasteMap(self, event): """Paste layer""" # copying between mapsets of one location if not self.copy_layer: GMessage(_("No map selected for copying."), parent=self) return if self.selected_location == self.copy_location: gisrc, env = getEnvironment(gisenv()['GISDBASE'], self.selected_location.label, mapset=self.selected_mapset.label) new_name = self._getNewMapName(_('New name'), _('Copy map'), self.copy_layer.label, env=env, mapset=self.selected_mapset.label, element=self.copy_type.label) if not new_name: return if map_exists(new_name, element=self.copy_type.label, env=env, mapset=self.selected_mapset.label): GMessage(_("Failed to copy map: new map has the same name"), parent=self) return if not self.selected_type: found = self._model.SearchNodes(parent=self.selected_mapset, type='element', name=self.copy_type.label) self.selected_type = found[0] if found else None overwrite = False if self.selected_type: found = self._model.SearchNodes(parent=self.selected_type, type=self.copy_type.label, name=new_name) if found and found[0]: dlg = wx.MessageDialog( parent=self, message=_("Map <{map}> already exists " "in the current mapset. " "Do you want to overwrite it?").format( map=new_name), caption=_("Overwrite?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) ret = dlg.ShowModal() dlg.Destroy() if ret == wx.ID_YES: overwrite = True string = self.copy_layer.label + '@' + self.copy_mapset.label + ',' + new_name pasted = 0 label = _("Copying <{name}>...").format(name=string) self.showNotification.emit(message=label) if self.copy_type.label == 'vector': pasted, cmd = self._runCommand('g.copy', vector=string, overwrite=overwrite, env=env) node = 'vector' elif self.copy_type.label == 'raster': pasted, cmd = self._runCommand('g.copy', raster=string, overwrite=overwrite, env=env) node = 'raster' else: pasted, cmd = self._runCommand('g.copy', raster_3d=string, overwrite=overwrite, 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) self.showNotification.emit( message=_("g.copy completed").format(cmd=cmd)) gscript.try_remove(gisrc) else: GError(_( "Failed to copy map: action is allowed only within the same location." ), parent=self) # expand selected mapset self.ExpandNode(self.selected_mapset, recursive=True)
def __init__(self, parent=None, giface=None, title=_("Map Swipe"), name="swipe", **kwargs): DoubleMapPanel.__init__( self, parent=parent, title=title, name=name, firstMap=Map(), secondMap=Map(), **kwargs, ) Debug.msg(1, "SwipeMapPanel.__init__()") # # Add toolbars # for name in ("swipeMain", "swipeMap", "swipeMisc"): self.AddToolbar(name) self._mgr.Update() self._giface = giface # # create widgets # self.splitter = MapSplitter(parent=self, id=wx.ID_ANY) self.sliderH = Slider(self, id=wx.ID_ANY, style=wx.SL_HORIZONTAL) self.sliderV = Slider(self, id=wx.ID_ANY, style=wx.SL_VERTICAL) self.mapWindowProperties = MapWindowProperties() self.mapWindowProperties.setValuesFromUserSettings() self.mapWindowProperties.autoRenderChanged.connect( self.OnAutoRenderChanged) self.firstMapWindow = SwipeBufferedWindow( parent=self.splitter, giface=self._giface, properties=self.mapWindowProperties, Map=self.firstMap, ) self.secondMapWindow = SwipeBufferedWindow( parent=self.splitter, giface=self._giface, properties=self.mapWindowProperties, Map=self.secondMap, ) # bind query signal self.firstMapWindow.mapQueried.connect(self.Query) self.secondMapWindow.mapQueried.connect(self.Query) # bind tracking cursosr to mirror it self.firstMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt)) self.secondMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt)) self.MapWindow = self.firstMapWindow # current by default self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory self.SetBindRegions(True) self._mode = "swipe" # statusbar items statusbarItems = [ sb.SbCoordinates, sb.SbRegionExtent, sb.SbCompRegionExtent, sb.SbShowRegion, sb.SbAlignExtent, sb.SbResolution, sb.SbDisplayGeometry, sb.SbMapScale, sb.SbGoTo, sb.SbProjection, ] self.statusbar = self.CreateStatusbar(statusbarItems) self._addPanes() self._bindWindowsActivation() self._setUpMapWindow(self.firstMapWindow) self._setUpMapWindow(self.secondMapWindow) self._mgr.GetPane("sliderV").Hide() self._mgr.GetPane("sliderH").Show() self.slider = self.sliderH self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_IDLE, self.OnIdle) self.SetSize((800, 600)) self._mgr.Update() self.rasters = {"first": None, "second": None} self._inputDialog = None self._preferencesDialog = None self._queryDialog = None # default action in map toolbar self.GetMapToolbar().SelectDefault() self.resize = False wx.CallAfter(self.CallAfterInit)
def OnSize(self, event): Debug.msg(4, "SwipeMapPanel.OnSize()") self.resize = grass.clock() super(SwipeMapPanel, self).OnSize(event)
def OnSashChanged(self, event): """Sash position changed, slider must be moved too.""" Debug.msg(5, "SwipeMapPanel.OnSashChanged()") self.OnSashChanging(event) event.Skip()
def Render(self, cmd, env): """If it is needed, download missing WMS data. .. todo:: lmgr deletes mapfile and maskfile when order of layers was changed (drag and drop) - if deleted, fetch data again """ if not haveGdal: return Debug.msg( 1, "RenderWMSMgr.Render(%s): force=%d img=%s" % (self.layer, self.layer.forceRender, self.layer.mapfile)) env = copy.copy(env) self.dstSize['cols'] = int(env["GRASS_RENDER_WIDTH"]) self.dstSize['rows'] = int(env["GRASS_RENDER_HEIGHT"]) region = self._getRegionDict(env) self._fitAspect(region, self.dstSize) self.updateMap = True fetchData = True # changed to True when calling Render() zoomChanged = False if self.renderedRegion is None or \ cmd != self.fetched_data_cmd: fetchData = True else: for c in ['north', 'south', 'east', 'west']: if self.renderedRegion and \ region[c] != self.renderedRegion[c]: fetchData = True break for c in ['e-w resol', 'n-s resol']: if self.renderedRegion and \ region[c] != self.renderedRegion[c]: zoomChanged = True break if fetchData: self.fetched_data_cmd = None self.renderedRegion = region try_remove(self.layer.mapfile) try_remove(self.tempMap) self.currentPid = self.thread.GetId() # self.thread.Terminate() self.downloading = True self.fetching_cmd = cmd env["GRASS_RENDER_FILE"] = self.tempMap env["GRASS_REGION"] = self._createRegionStr(region) cmd_render = copy.deepcopy(cmd) cmd_render[1]['quiet'] = True # be quiet self._startTime = time.time() self.thread.Run(callable=self._render, cmd=cmd_render, env=env, ondone=self.OnRenderDone) self.layer.forceRender = False self.updateProgress.emit(layer=self.layer)
def _onMouseMoving(self, event): self.mouse['end'] = event.GetPosition() Debug.msg(5, "VDigitWindow.OnMouseMoving(): coords=%f,%f" % (self.mouse['end'][0], self.mouse['end'][1])) action = self.toolbar.GetAction() if action == "addLine" and \ self.toolbar.GetAction('type') in ["line", "boundary", "area"]: if len(self.polycoords) > 0: self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1])) elif action in ["moveLine", "moveVertex", "editLine"] \ and hasattr(self, "moveInfo"): dx = self.mouse['end'][0] - self.mouse['begin'][0] dy = self.mouse['end'][1] - self.mouse['begin'][1] # draw lines on new position if action == "moveLine" and \ len(self.moveInfo['id']) > 0: # move line for id in self.moveInfo['id']: self.pdcTmp.TranslateId(id, dx, dy) elif action in ["moveVertex", "editLine"]: # move vertex -> # (vertex, left vertex, left line, # right vertex, right line) # do not draw static lines if action == "moveVertex" and \ len(self.moveInfo['id']) > 0: self.polycoords = [] self.pdcTmp.RemoveId(self.moveInfo['id'][0]) if self.moveInfo['id'][1] > 0: # previous vertex x, y = self.Pixel2Cell( self.pdcTmp.GetIdBounds( self.moveInfo['id'][1])[ 0:2]) self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1) self.polycoords.append((x, y)) self.polycoords.append(self.Pixel2Cell(self.mouse['end'])) if self.moveInfo['id'][2] > 0: # next vertex x, y = self.Pixel2Cell( self.pdcTmp.GetIdBounds( self.moveInfo['id'][2])[ 0:2]) self.pdcTmp.RemoveId(self.moveInfo['id'][2] - 1) self.polycoords.append((x, y)) self.ClearLines(pdc=self.pdcTmp) self.DrawLines(pdc=self.pdcTmp) if action == "editLine": self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1])) self.Refresh() # TODO: use RefreshRect() self.mouse['begin'] = self.mouse['end'] elif action == "zbulkLine": if len(self.polycoords) == 1: # draw mouse moving self.MouseDraw(self.pdcTmp)
def OnSliderPositionChanged(self, event): """Slider position changed, sash must be moved too.""" Debug.msg(5, "SwipeMapPanel.OnSliderPositionChanged()") self.splitter.SetSashPosition(event.GetPosition()) self.splitter.OnSashChanged(None)
def __init__(self, parent, map, query=None, cats=None, line=None, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, pos=wx.DefaultPosition, action="add", ignoreError=False): """Standard dialog used to add/update/display attributes linked to the vector map. Attribute data can be selected based on layer and category number or coordinates. :param parent: :param map: vector map :param query: query coordinates and distance (used for v.edit) :param cats: {layer: cats} :param line: feature id (requested for cats) :param style: :param pos: :param action: (add, update, display) :param ignoreError: True to ignore errors """ self.parent = parent # mapdisplay.BufferedWindow self.map = map self.action = action # ids/cats of selected features # fid : {layer : cats} self.cats = {} self.fid = -1 # feature id # get layer/table/column information self.mapDBInfo = VectorDBInfo(self.map) layers = self.mapDBInfo.layers.keys() # get available layers # check if db connection / layer exists if len(layers) <= 0: if not ignoreError: dlg = wx.MessageDialog( parent=self.parent, message=_("No attribute table found.\n\n" "Do you want to create a new attribute table " "and defined a link to vector map <%s>?") % self.map, caption=_("Create table?"), style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: lmgr = self.parent.lmgr lmgr.OnShowAttributeTable(event=None, selection='layers') dlg.Destroy() self.mapDBInfo = None wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title="", style=style, pos=pos) # dialog body mainSizer = wx.BoxSizer(wx.VERTICAL) # notebook self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT) self.closeDialog = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Close dialog on submit")) self.closeDialog.SetValue(True) if self.action == 'display': self.closeDialog.Enable(False) # feature id (text/choice for duplicates) self.fidMulti = wx.Choice(parent=self, id=wx.ID_ANY, size=(150, -1)) self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature) self.fidText = wx.StaticText(parent=self, id=wx.ID_ANY) self.noFoundMsg = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("No attributes found")) self.UpdateDialog(query=query, cats=cats) # set title if self.action == "update": self.SetTitle(_("Update attributes")) elif self.action == "add": self.SetTitle(_("Define attributes")) else: self.SetTitle(_("Display attributes")) # buttons btnCancel = wx.Button(self, wx.ID_CANCEL) btnReset = wx.Button(self, wx.ID_UNDO, _("&Reload")) btnSubmit = wx.Button(self, wx.ID_OK, _("&Submit")) if self.action == 'display': btnSubmit.Enable(False) btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) btnSizer.AddButton(btnReset) btnSizer.SetNegativeButton(btnReset) btnSubmit.SetDefault() btnSizer.AddButton(btnSubmit) btnSizer.Realize() mainSizer.Add(self.noFoundMsg, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) fidSizer = wx.BoxSizer(wx.HORIZONTAL) fidSizer.Add(wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Feature id:")), proportion=0, border=5, flag=wx.ALIGN_CENTER_VERTICAL) fidSizer.Add(self.fidMulti, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) fidSizer.Add(self.fidText, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) mainSizer.Add(fidSizer, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) mainSizer.Add(self.closeDialog, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) mainSizer.Add(btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5) # bindigs btnReset.Bind(wx.EVT_BUTTON, self.OnReset) btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit) btnCancel.Bind(wx.EVT_BUTTON, self.OnClose) self.Bind(wx.EVT_CLOSE, self.OnClose) self.SetSizer(mainSizer) mainSizer.Fit(self) # set min size for dialog w, h = self.GetBestSize() w += 50 if h < 200: self.SetMinSize((w, 200)) else: self.SetMinSize((w, h)) if self.notebook.GetPageCount() == 0: Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
def OnLeftDownUndo(self, event): """Left mouse button pressed with control key - vector digitizer undo functionality """ if self.mouse["use"] != "pointer" or not self.toolbar: return action = self.toolbar.GetAction() if (action == "addLine" and self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or action == "editLine": # add line or boundary -> remove last point from the line try: removed = self.polycoords.pop() Debug.msg( 4, "VDigitWindow.OnMiddleDown(): polycoords_poped=%s" % [removed, ]) # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1]) except: pass if action == "editLine": # remove last vertex & line if len(self.moveInfo['id']) > 1: self.moveInfo['id'].pop() self.UpdateMap(render=False, renderVector=False) elif action in ["deleteLine", "deleteArea", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", "snapLine", "connectLine", "copyLine", "queryLine", "breakLine", "typeConv"]: # various tools -> unselected selected features self.digit.GetDisplay().SetSelected([]) if action in ["moveLine", "moveVertex", "editLine"] and \ hasattr(self, "moveInfo"): del self.moveInfo elif action == "copyCats": try: del self.copyCatsList del self.copyCatsIds except AttributeError: pass elif action == "copyLine": del self.copyIds if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.UpdateMap(render=True, renderVector=False) del self.layerTmp self.polycoords = [] self.UpdateMap(render=False) # render vector elif action == "zbulkLine": # reset polyline self.polycoords = [] self.digit.GetDisplay().SetSelected([]) self.UpdateMap(render=False) self.redrawAll = True self.UpdateMap(render=False, renderVector=False)
continue if name not in grassCmd: grassCmd.add(name) Debug.msg(3, "AddOn commands: %s", name) nCmd += 1 if ext == SCT_EXT and \ ext in grassScripts.keys() and \ name not in grassScripts[ext]: grassScripts[ext].append(name) else: if fname not in grassCmd: grassCmd.add(fname) Debug.msg(3, "AddOn commands: %s", fname) nCmd += 1 Debug.msg(1, "Number of GRASS AddOn commands: %d", nCmd) """@brief Collected GRASS-relared binaries/scripts""" grassCmd, grassScripts = get_commands() Debug.msg(1, "Number of core GRASS commands: %d", len(grassCmd)) UpdateGRASSAddOnCommands() """@Toolbar icon size""" toolbarSize = (24, 24) """@Check version of wxPython, use agwStyle for 2.8.11+""" hasAgw = CheckWxVersion([2, 8, 11, 0]) wxPython3 = CheckWxVersion([3, 0, 0, 0]) """@Add GUIDIR/scripts into path""" os.environ['PATH'] = os.path.join(GUIDIR, 'scripts') + os.pathsep + os.environ['PATH']
def OnRemoveVertex(self, event): """Remove line vertex""" Debug.msg(2, "Digittoolbar.OnRemoveVertex():") self.action = {'desc': "removeVertex", 'id': self.removeVertex} self.MapWindow.mouse['box'] = 'point'
def Render(self, cmdList, regions, regionFor3D, bgcolor, force, nprocs): """Renders all maps and stores files. :param cmdList: list of rendering commands to run :param regions: regions for 2D rendering assigned to commands :param regionFor3D: region for setting 3D view :param bgcolor: background color as a tuple of 3 values 0 to 255 :param force: if True reload all data, otherwise only missing data :param nprocs: number of procs to be used for rendering """ Debug.msg(3, "BitmapRenderer.Render") count = 0 # Variables for parallel rendering proc_count = 0 proc_list = [] queue_list = [] cmd_list = [] filteredCmdList = [] for cmd, region in zip(cmdList, regions): filename = GetFileFromCmd(self._tempDir, cmd, region) if not force and os.path.exists( filename) and self._mapFilesPool.GetSize( HashCmd(cmd, region)) == (self.imageWidth, self.imageHeight): # for reference counting self._mapFilesPool[HashCmd(cmd, region)] = filename continue filteredCmdList.append((cmd, region)) mapNum = len(filteredCmdList) stopped = False self._isRendering = True for cmd, region in filteredCmdList: count += 1 # Queue object for interprocess communication q = Queue() # The separate render process if cmd[0] == 'm.nviz.image': p = Process(target=RenderProcess3D, args=(self.imageWidth, self.imageHeight, self._tempDir, cmd, regionFor3D, bgcolor, q)) else: p = Process(target=RenderProcess2D, args=(self.imageWidth, self.imageHeight, self._tempDir, cmd, region, bgcolor, q)) p.start() queue_list.append(q) proc_list.append(p) cmd_list.append((cmd, region)) proc_count += 1 # Wait for all running processes and read/store the created images if proc_count == nprocs or count == mapNum: for i in range(len(cmd_list)): proc_list[i].join() filename = queue_list[i].get() self._mapFilesPool[HashCmd(cmd_list[i][0], cmd_list[i][1])] = filename self._mapFilesPool.SetSize( HashCmd(cmd_list[i][0], cmd_list[i][1]), (self.imageWidth, self.imageHeight)) proc_count = 0 proc_list = [] queue_list = [] cmd_list = [] self.renderingContinues.emit(current=count, text=_("Rendering map layers")) if self._stopRendering: self._stopRendering = False stopped = True break self._isRendering = False return not stopped
def __init__(self, parent, title, vectorName, query=None, cats=None, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs): """Dialog used to display/modify categories of vector objects :param parent: :param title: dialog title :param query: {coordinates, qdist} - used by v.edit/v.what :param cats: directory of lines (layer/categories) - used by vdigit :param style: dialog style """ self.parent = parent # map window class instance self.digit = parent.digit # map name self.vectorName = vectorName # line : {layer: [categories]} self.cats = {} # do not display dialog if no line is found (-> self.cats) if cats is None: if self._getCategories(query[0], query[1]) == 0 or not self.line: Debug.msg(3, "VDigitCategoryDialog(): nothing found!") else: self.cats = cats for line in cats.keys(): for layer in cats[line].keys(): self.cats[line][layer] = list(cats[line][layer]) layers = [] for layer in self.digit.GetLayers(): layers.append(str(layer)) # make copy of cats (used for 'reload') self.cats_orig = copy.deepcopy(self.cats) wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title, style=style, **kwargs) # list of categories box = wx.StaticBox( parent=self, id=wx.ID_ANY, label=" %s " % _("List of categories - right-click to delete")) listSizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.list = CategoryListCtrl(parent=self, id=wx.ID_ANY, style=wx.LC_REPORT | wx.BORDER_NONE | wx.LC_SORT_ASCENDING | wx.LC_HRULES | wx.LC_VRULES) # sorter self.fid = self.cats.keys()[0] self.itemDataMap = self.list.Populate(self.cats[self.fid]) listmix.ColumnSorterMixin.__init__(self, 2) self.fidMulti = wx.Choice(parent=self, id=wx.ID_ANY, size=(150, -1)) self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature) self.fidText = wx.StaticText(parent=self, id=wx.ID_ANY) if len(self.cats.keys()) == 1: self.fidMulti.Show(False) self.fidText.SetLabel(str(self.fid)) else: self.fidText.Show(False) choices = [] for fid in self.cats.keys(): choices.append(str(fid)) self.fidMulti.SetItems(choices) self.fidMulti.SetSelection(0) listSizer.Add(item=self.list, proportion=1, flag=wx.EXPAND) # add new category box = wx.StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Add new category")) addSizer = wx.StaticBoxSizer(box, wx.VERTICAL) flexSizer = wx.FlexGridSizer(cols=5, hgap=5, vgap=5) flexSizer.AddGrowableCol(3) layerNewTxt = wx.StaticText(parent=self, id=wx.ID_ANY, label="%s:" % _("Layer")) self.layerNew = wx.Choice(parent=self, id=wx.ID_ANY, size=(75, -1), choices=layers) if len(layers) > 0: self.layerNew.SetSelection(0) catNewTxt = wx.StaticText(parent=self, id=wx.ID_ANY, label="%s:" % _("Category")) try: newCat = max(self.cats[self.fid][1]) + 1 except KeyError: newCat = 1 self.catNew = SpinCtrl(parent=self, id=wx.ID_ANY, size=(75, -1), initial=newCat, min=0, max=1e9) btnAddCat = wx.Button(self, wx.ID_ADD) flexSizer.Add(item=layerNewTxt, proportion=0, flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item=self.layerNew, proportion=0, flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item=catNewTxt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border=10) flexSizer.Add(item=self.catNew, proportion=0, flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item=btnAddCat, proportion=0, flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) addSizer.Add( item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) # buttons btnApply = wx.Button(self, wx.ID_APPLY) btnApply.SetToolTipString(_("Apply changes")) btnCancel = wx.Button(self, wx.ID_CANCEL) btnCancel.SetToolTipString(_("Ignore changes and close dialog")) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetToolTipString(_("Apply changes and close dialog")) btnOk.SetDefault() # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) # btnSizer.AddButton(btnReload) # btnSizer.SetNegativeButton(btnReload) btnSizer.AddButton(btnApply) btnSizer.AddButton(btnOk) btnSizer.Realize() mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(item=listSizer, proportion=1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5) mainSizer.Add(item=addSizer, proportion=0, flag=wx.EXPAND | wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) fidSizer = wx.BoxSizer(wx.HORIZONTAL) fidSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Feature id:")), proportion=0, border=5, flag=wx.ALIGN_CENTER_VERTICAL) fidSizer.Add(item=self.fidMulti, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) fidSizer.Add(item=self.fidText, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) mainSizer.Add(item=fidSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5) self.SetSizer(mainSizer) mainSizer.Fit(self) self.SetAutoLayout(True) # set min size for dialog self.SetMinSize(self.GetBestSize()) # bindings btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnOk.Bind(wx.EVT_BUTTON, self.OnOK) btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat) btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) self.Bind(wx.EVT_CLOSE, lambda evt: self.Hide()) # list self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) # wxMSW self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) # wxGTK self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list) self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
def Compose(self, cmdLists, regions, opacityList, bgcolor, force, nprocs): """Performs the composition of ppm/pgm files. :param cmdLists: lists of rendering commands lists to compose :param regions: regions for 2D rendering assigned to commands :param opacityList: list of lists of opacity values :param bgcolor: background color as a tuple of 3 values 0 to 255 :param force: if True reload all data, otherwise only missing data :param nprocs: number of procs to be used for rendering """ Debug.msg(3, "BitmapComposer.Compose") count = 0 # Variables for parallel rendering proc_count = 0 proc_list = [] queue_list = [] cmd_lists = [] filteredCmdLists = [] for cmdList, region in zip(cmdLists, regions): if not force and HashCmds( cmdList, region) in self._bitmapPool and self._bitmapPool[HashCmds( cmdList, region)].GetSize() == (self.imageWidth, self.imageHeight): # TODO: find a better way than to assign the same to increase # the reference self._bitmapPool[HashCmds(cmdList, region)] = self._bitmapPool[HashCmds( cmdList, region)] continue filteredCmdLists.append((cmdList, region)) num = len(filteredCmdLists) self._isComposing = True for cmdList, region in filteredCmdLists: count += 1 # Queue object for interprocess communication q = Queue() # The separate render process p = Process(target=CompositeProcess, args=(self.imageWidth, self.imageHeight, self._tempDir, cmdList, region, opacityList, bgcolor, q)) p.start() queue_list.append(q) proc_list.append(p) cmd_lists.append((cmdList, region)) proc_count += 1 # Wait for all running processes and read/store the created images if proc_count == nprocs or count == num: for i in range(len(cmd_lists)): proc_list[i].join() filename = queue_list[i].get() if filename is None: self._bitmapPool[HashCmds( cmd_lists[i][0], cmd_lists[i][1])] = createNoDataBitmap( self.imageWidth, self.imageHeight, text="Failed to render") else: self._bitmapPool[HashCmds( cmd_lists[i][0], cmd_lists[i][1])] = BitmapFromImage( wx.Image(filename)) os.remove(filename) proc_count = 0 proc_list = [] queue_list = [] cmd_lists = [] self.compositionContinues.emit(current=count, text=_("Overlaying map layers")) if self._stopComposing: self._stopComposing = False break self._isComposing = False
def RunCmd(self, command, compReg=True, env=None, skipInterface=False, onDone=None, onPrepare=None, userData=None, addLayer=None, notification=Notification.MAKE_VISIBLE): """Run command typed into console command prompt (GPrompt). .. todo:: Document the other event. .. todo:: Solve problem with the other event (now uses gOutputText event but there is no text, use onPrepare handler instead?) .. todo:: Skip interface is ignored and determined always automatically. Posts event EVT_IGNORED_CMD_RUN when command which should be ignored (according to ignoredCmdPattern) is run. For example, see layer manager which handles d.* on its own. :param command: command given as a list (produced e.g. by utils.split()) :param compReg: True use computation region :param notification: form of notification :param bool skipInterface: True to do not launch GRASS interface parser when command has no arguments given :param onDone: function to be called when command is finished :param onPrepare: function to be called before command is launched :param addLayer: to be passed in the mapCreated signal :param userData: data defined for the command """ if len(command) == 0: Debug.msg(2, "GPrompt:RunCmd(): empty command") return # update history file self.UpdateHistoryFile(' '.join(command)) if command[0] in globalvar.grassCmd: # send GRASS command without arguments to GUI command interface # except ignored commands (event is emitted) if self._ignoredCmdPattern and \ re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \ '--help' not in command and '--ui' not in command: event = gIgnoredCmdRun(cmd=command) wx.PostEvent(self, event) return else: # other GRASS commands (r|v|g|...) try: task = GUI(show=None).ParseCommand(command) except GException as e: GError(parent=self._guiparent, message=unicode(e), showTraceback=False) return hasParams = False if task: options = task.get_options() hasParams = options['params'] and options['flags'] # check for <input>=- for p in options['params']: if p.get('prompt', '') == 'input' and \ p.get('element', '') == 'file' and \ p.get('age', 'new') == 'old' and \ p.get('value', '') == '-': GError( parent=self._guiparent, message= _("Unable to run command:\n%(cmd)s\n\n" "Option <%(opt)s>: read from standard input is not " "supported by wxGUI") % { 'cmd': ' '.join(command), 'opt': p.get('name', '') }) return if len(command) == 1: if command[0].startswith('g.gui.'): import imp import inspect pyFile = command[0] if sys.platform == 'win32': pyFile += '.py' pyPath = os.path.join(os.environ['GISBASE'], 'scripts', pyFile) if not os.path.exists(pyPath): pyPath = os.path.join( os.environ['GRASS_ADDON_BASE'], 'scripts', pyFile) if not os.path.exists(pyPath): GError(parent=self._guiparent, message=_("Module <%s> not found.") % command[0]) pymodule = imp.load_source( command[0].replace('.', '_'), pyPath) pymain = inspect.getargspec(pymodule.main) if pymain and 'giface' in pymain.args: pymodule.main(self._giface) return # no arguments given if hasParams and \ not isinstance(self._guiparent, FormNotebook): # also parent must be checked, see #3135 for details try: GUI(parent=self._guiparent, giface=self._giface).ParseCommand(command) except GException as e: print(e, file=sys.stderr) return if env: env = env.copy() else: env = os.environ.copy() # activate computational region (set with g.region) # for all non-display commands. if compReg and "GRASS_REGION" in env: del env["GRASS_REGION"] # process GRASS command with argument self.cmdThread.RunCmd(command, stdout=self.cmdStdOut, stderr=self.cmdStdErr, onDone=onDone, onPrepare=onPrepare, userData=userData, addLayer=addLayer, env=env, notification=notification) self.cmdOutputTimer.Start(50) # we don't need to change computational region settings # because we work on a copy else: # Send any other command to the shell. Send output to # console output window # # Check if the script has an interface (avoid double-launching # of the script) # check if we ignore the command (similar to grass commands part) if self._ignoredCmdPattern and \ re.compile(self._ignoredCmdPattern).search(' '.join(command)): event = gIgnoredCmdRun(cmd=command) wx.PostEvent(self, event) return skipInterface = True if os.path.splitext(command[0])[1] in ('.py', '.sh'): try: sfile = open(command[0], "r") for line in sfile.readlines(): if len(line) < 2: continue if line[0] is '#' and line[1] is '%': skipInterface = False break sfile.close() except IOError: pass if len(command) == 1 and not skipInterface: try: task = gtask.parse_interface(command[0]) except: task = None else: task = None if task: # process GRASS command without argument GUI(parent=self._guiparent, giface=self._giface).ParseCommand(command) else: self.cmdThread.RunCmd(command, stdout=self.cmdStdOut, stderr=self.cmdStdErr, onDone=onDone, onPrepare=onPrepare, userData=userData, addLayer=addLayer, env=env, notification=notification) self.cmdOutputTimer.Start(50)
def RequestStopRendering(self): """Requests to stop rendering/composition""" Debug.msg(2, "BitmapProvider.RequestStopRendering") self._renderer.RequestStopRendering() self._composer.RequestStopComposing()
def __init__( self, cmd, stdin=None, verbose=None, wait=True, rerr=False, stdout=None, stderr=None, ): """ :param cmd: command given as list :param stdin: standard input stream :param verbose: verbose level [0, 3] (--q, --v) :param wait: wait for child execution terminated :param rerr: error handling (when GException raised). True for redirection to stderr, False for GUI dialog, None for no operation (quiet mode) :param stdout: redirect standard output or None :param stderr: redirect standard error output or None """ Debug.msg(1, "gcmd.Command(): %s" % " ".join(cmd)) self.cmd = cmd self.stderr = stderr # # set verbosity level # verbose_orig = None if ("--q" not in self.cmd and "--quiet" not in self.cmd) and ( "--v" not in self.cmd and "--verbose" not in self.cmd ): if verbose is not None: if verbose == 0: self.cmd.append("--quiet") elif verbose == 3: self.cmd.append("--verbose") else: verbose_orig = os.getenv("GRASS_VERBOSE") os.environ["GRASS_VERBOSE"] = str(verbose) # # create command thread # self.cmdThread = CommandThread(cmd, stdin, stdout, stderr) self.cmdThread.start() if wait: self.cmdThread.join() if self.cmdThread.module: self.cmdThread.module.wait() self.returncode = self.cmdThread.module.returncode else: self.returncode = 1 else: self.cmdThread.join(0.5) self.returncode = None if self.returncode is not None: Debug.msg( 3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % (" ".join(cmd), wait, self.returncode, self.cmdThread.isAlive()), ) if rerr is not None and self.returncode != 0: if rerr is False: # GUI dialog raise GException( "%s '%s'%s%s%s %s%s" % ( _("Execution failed:"), " ".join(self.cmd), os.linesep, os.linesep, _("Details:"), os.linesep, _("Error: ") + self.__GetError(), ) ) elif rerr == sys.stderr: # redirect message to sys stderr.write("Execution failed: '%s'" % (" ".join(self.cmd))) stderr.write( "%sDetails:%s%s" % (os.linesep, _("Error: ") + self.__GetError(), os.linesep) ) else: pass # nop else: Debug.msg( 3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % (" ".join(cmd), wait, self.cmdThread.isAlive()), ) if verbose_orig: os.environ["GRASS_VERBOSE"] = verbose_orig elif "GRASS_VERBOSE" in os.environ: del os.environ["GRASS_VERBOSE"]
def OnCmdDone(self, event): """Command done (or aborted) Sends signal mapCreated if map is recognized in output parameters or for specific modules (as r.colors). """ # Process results here try: ctime = time.time() - event.time if ctime < 60: stime = _("%d sec") % int(ctime) else: mtime = int(ctime / 60) stime = _("%(min)d min %(sec)d sec") % { 'min': mtime, 'sec': int(ctime - (mtime * 60)) } except KeyError: # stopped deamon stime = _("unknown") if event.aborted: # Thread aborted (using our convention of None return) self.WriteWarning( _('Please note that the data are left in' ' inconsistent state and may be corrupted')) msg = _('Command aborted') else: msg = _('Command finished') self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime), notification=event.notification) if event.onDone: event.onDone(event) self.cmdOutputTimer.Stop() if event.cmd[0] == 'g.gisenv': Debug.SetLevel() self.Redirect() # do nothing when no map added if event.returncode != 0 or event.aborted: event.Skip() return if event.cmd[0] not in globalvar.grassCmd: return # find which maps were created try: task = GUI(show=None).ParseCommand(event.cmd) except GException as e: print(e, file=sys.stderr) task = None return name = task.get_name() for p in task.get_options()['params']: prompt = p.get('prompt', '') if prompt in ('raster', 'vector', 'raster_3d') and p.get( 'value', None): if p.get('age', 'old') == 'new' or name in ('r.colors', 'r3.colors', 'v.colors', 'v.proj', 'r.proj'): # if multiple maps (e.g. r.series.interp), we need add each if p.get('multiple', False): lnames = p.get('value').split(',') # in case multiple input (old) maps in r.colors # we don't want to rerender it multiple times! just # once if p.get('age', 'old') == 'old': lnames = lnames[0:1] else: lnames = [p.get('value')] for lname in lnames: if '@' not in lname: lname += '@' + grass.gisenv()['MAPSET'] if grass.find_file( lname, element=p.get('element'))['fullname']: self.mapCreated.emit(name=lname, ltype=prompt, add=event.addLayer) if name == 'r.mask': self.updateMap.emit() event.Skip()
def OnPaint(self, event): Debug.msg(5, "AnimationWindow.OnPaint()") # All that is needed here is to draw the buffer to screen dc = wx.BufferedPaintDC(self, self._Buffer) if self._overlay: self._pdc.DrawToDC(dc)
def RunCommand( prog, flags="", overwrite=False, quiet=False, verbose=False, parent=None, read=False, parse=None, stdin=None, getErrorMsg=False, env=None, **kwargs, ): """Run GRASS command :param prog: program to run :param flags: flags given as a string :param overwrite, quiet, verbose: flags :param parent: parent window for error messages :param read: fetch stdout :param parse: fn to parse stdout (e.g. grass.parse_key_val) or None :param stdin: stdin or None :param getErrorMsg: get error messages on failure :param env: environment (optional, uses os.environ if not provided) :param kwargs: program parameters The environment passed to the function (env or os.environ) is not modified (a copy is used internally). :return: returncode (read == False and getErrorMsg == False) :return: returncode, messages (read == False and getErrorMsg == True) :return: stdout (read == True and getErrorMsg == False) :return: returncode, stdout, messages (read == True and getErrorMsg == True) :return: stdout, stderr """ cmdString = " ".join( grass.make_command(prog, flags, overwrite, quiet, verbose, **kwargs) ) Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString) kwargs["stderr"] = subprocess.PIPE if read: kwargs["stdout"] = subprocess.PIPE if stdin: kwargs["stdin"] = subprocess.PIPE # Do not change the environment, only a local copy. if env: env = env.copy() else: env = os.environ.copy() if parent: env["GRASS_MESSAGE_FORMAT"] = "standard" start = time.time() ps = grass.start_command(prog, flags, overwrite, quiet, verbose, env=env, **kwargs) if stdin: ps.stdin.write(encode(stdin)) ps.stdin.close() ps.stdin = None stdout, stderr = ps.communicate() stderr = decode(stderr) stdout = decode(stdout) if read else stdout ret = ps.returncode Debug.msg( 1, "gcmd.RunCommand(): get return code %d (%.6f sec)" % (ret, (time.time() - start)), ) if ret != 0: if stderr: Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr) else: Debug.msg(2, "gcmd.RunCommand(): nothing to print ???") if parent: GError(parent=parent, caption=_("Error in %s") % prog, message=stderr) if not read: if not getErrorMsg: return ret else: return ret, _formatMsg(stderr) if stdout: Debug.msg(3, "gcmd.RunCommand(): return stdout\n'%s'" % stdout) else: Debug.msg(3, "gcmd.RunCommand(): return stdout = None") if parse: stdout = parse(stdout) if not getErrorMsg: return stdout if read and getErrorMsg: return ret, stdout, _formatMsg(stderr) return stdout, _formatMsg(stderr)
def StatusbarUpdate(self): """Update statusbar content""" if self.statusbarManager: Debug.msg(5, "MapFrameBase.StatusbarUpdate()") self.statusbarManager.Update()
def OnPaint(self, event): Debug.msg(5, "BufferedWindow.OnPaint()") # All that is needed here is to draw the buffer to screen dc = wx.BufferedPaintDC(self, self._Buffer)
def _initTreeItems(self, locations=None, mapsets=None): """Add locations, mapsets and layers to the tree. Runs in multiple processes. Saves resulting data and error.""" # mapsets param currently unused genv = gisenv() if not locations: locations = GetListOfLocations(genv['GISDBASE']) loc_count = proc_count = 0 queue_list = [] proc_list = [] loc_list = [] nprocs = 4 try: nprocs = cpu_count() except NotImplementedError: nprocs = 4 results = dict() errors = [] location_nodes = [] nlocations = len(locations) grassdata_node = self._model.AppendNode( parent=self._model.root, label=_('GRASS locations in {0}').format(genv['GISDBASE']), data=dict(type='grassdata')) for location in locations: results[location] = dict() varloc = self._model.AppendNode(parent=grassdata_node, label=location, data=dict(type='location', name=location)) location_nodes.append(varloc) loc_count += 1 Debug.msg( 3, "Scanning location <{0}> ({1}/{2})".format( location, loc_count, nlocations)) q = Queue() p = Process(target=getLocationTree, args=(genv['GISDBASE'], location, q)) p.start() queue_list.append(q) proc_list.append(p) loc_list.append(location) proc_count += 1 # Wait for all running processes if proc_count == nprocs or loc_count == nlocations: Debug.msg(4, "Process subresults") for i in range(len(loc_list)): maps, error = queue_list[i].get() proc_list[i].join() if error: errors.append(error) for key in sorted(maps.keys()): mapset_node = self._model.AppendNode( parent=location_nodes[i], label=key, data=dict(type='mapset', name=key)) self._populateMapsetItem(mapset_node, maps[key]) proc_count = 0 proc_list = [] queue_list = [] loc_list = [] location_nodes = [] if errors: wx.CallAfter(GWarning, '\n'.join(errors)) Debug.msg(1, "Tree filled") self.RefreshItems()
def OnSize(self, event): Debug.msg(5, "AnimationWindow.OnSize()") BufferedWindow.OnSize(self, event) if event: event.Skip()