def __init__(self, layer, mapfile, maskfile): if not haveGdal: sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\ "WMS layers can not be displayed without the bindings.\n")) self.layer = layer wx.EvtHandler.__init__(self) # thread for d.wms commands self.thread = CmdThread(self) self.Bind(EVT_CMD_DONE, self.OnDataFetched) self.downloading = False self.renderedRegion = None self.updateMap = True self.fetched_data_cmd = None self.cmdStdErr = GStderr(self) self.mapfile = mapfile self.maskfile = maskfile self.tempMap = grass.tempfile() self.dstSize = {} self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.dataFetched = Signal('RenderWMSMgr.dataFetched') self.updateProgress = Signal('RenderWMSMgr.updateProgress')
def __init__(self, parent, layer, giface): wx.Dialog.__init__(self, parent=parent, title=("Save web service layer as raster map"), id=wx.ID_ANY) self.layer = layer self._giface = giface self.cmd = self.layer.GetCmd() self.thread = CmdThread(self) self.cmdStdErr = GStderr(self) self._createWidgets()
def __init__(self, parent, layer, giface): wx.Dialog.__init__(self, parent = parent, title = ("Save web service layer as raster map"), id = wx.ID_ANY) self.layer = layer self._giface = giface self.cmd = self.layer.GetCmd() self.thread = CmdThread(self) self.cmdStdErr = GStderr(self) self._createWidgets()
class RenderWMSMgr(wx.EvtHandler): """Fetch and prepare WMS data for rendering. """ def __init__(self, layer, mapfile, maskfile): if not haveGdal: sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\ "WMS layers can not be displayed without the bindings.\n")) self.layer = layer wx.EvtHandler.__init__(self) # thread for d.wms commands self.thread = CmdThread(self) self.Bind(EVT_CMD_DONE, self.OnDataFetched) self.downloading = False self.renderedRegion = None self.updateMap = True self.fetched_data_cmd = None self.cmdStdErr = GStderr(self) self.mapfile = mapfile self.maskfile = maskfile self.tempMap = grass.tempfile() self.dstSize = {} self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.dataFetched = Signal('RenderWMSMgr.dataFetched') self.updateProgress = Signal('RenderWMSMgr.updateProgress') def __del__(self): try_remove(self.tempMap) 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 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 = False 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.mapfile) try_remove(self.tempMap) self.currentPid = self.thread.GetId() self.thread.abort() self.downloading = True self.fetching_cmd = cmd cmdList = utils.CmdTupleToList(cmd) if Debug.GetLevel() < 3: cmdList.append('--quiet') env["GRASS_RENDER_FILE"] = self.tempMap env["GRASS_REGION"] = self._createRegionStr(region) self.thread.RunCmd(cmdList, env=env, stderr=self.cmdStdErr) def OnCmdOutput(self, event): """Print cmd output according to debug level. """ if Debug.GetLevel() == 0: if event.type == 'error': sys.stderr.write(event.text) sys.stderr.flush() else: Debug.msg(1, event.text) def OnDataFetched(self, event): """Fetch data """ if event.pid != self.currentPid: return self.downloading = False if not self.updateMap: self.updateProgress.emit(layer=self.layer) self.renderedRegion = None self.fetched_data_cmd = None return self.mapMerger = GDALRasterMerger(targetFile = self.mapfile, region = self.renderedRegion, bandsNum = 3, gdalDriver = 'PNM', fillValue = 0) self.mapMerger.AddRasterBands(self.tempMap, {1 : 1, 2 : 2, 3 : 3}) del self.mapMerger self.maskMerger = GDALRasterMerger(targetFile = self.maskfile, region = self.renderedRegion, bandsNum = 1, gdalDriver = 'PNM', fillValue = 0) #{4 : 1} alpha channel (4) to first and only channel (1) in mask self.maskMerger.AddRasterBands(self.tempMap, {4 : 1}) del self.maskMerger self.fetched_data_cmd = self.fetching_cmd self.dataFetched.emit() def _getRegionDict(self, env): """Parse string from GRASS_REGION env variable into dict. """ region = {} parsedRegion = env["GRASS_REGION"].split(';') for r in parsedRegion: r = r.split(':') r[0] = r[0].strip() if len(r) < 2: continue try: if r[0] in ['cols', 'rows']: region[r[0]] = int(r[1]) else: region[r[0]] = float(r[1]) except ValueError: region[r[0]] = r[1] return region def _createRegionStr(self, region): """Create string for GRASS_REGION env variable from dict created by _getRegionDict. """ regionStr = '' for k, v in region.iteritems(): item = k + ': ' + str(v) if regionStr: regionStr += '; ' regionStr += item return regionStr def IsDownloading(self): """Is it downloading any data from WMS server? """ return self.downloading def _fitAspect(self, region, size): """Compute region parameters to have direction independent resolution. """ if region['n-s resol'] > region['e-w resol']: delta = region['n-s resol'] * size['cols'] / 2 center = (region['east'] - region['west'])/2 region['east'] = center + delta + region['west'] region['west'] = center - delta + region['west'] region['e-w resol'] = region['n-s resol'] else: delta = region['e-w resol'] * size['rows'] / 2 center = (region['north'] - region['south'])/2 region['north'] = center + delta + region['south'] region['south'] = center - delta + region['south'] region['n-s resol'] = region['e-w resol'] def Abort(self): """Abort process""" self.updateMap = False self.thread.abort(abortall = True)
def ComputeNodes(self, activate): """Start/stop snapping mode""" if not haveCtypes: GMessage(parent=self, message=_("Unable to use ctypes. \n") + _("Snapping mode can not be activated.")) return -1 if not activate: if self.tmp_maps.HasTmpVectMap("vnet_snap_points"): self.snapPts.DeleteRenderLayer() self.giface.updateMap.emit(render=False, renderVector=False) if 'cmdThread' in self.snapData: self.snapData['cmdThread'].abort() self.data.SetSnapping(False) self.snapping.emit(evt="deactivated") return -1 self.data.SetSnapping(activate) params, inv_params, flags = self.data.GetParams() if not self.data.InputsErrorMsgs( msg=_("Snapping mode can not be activated."), analysis=None, params=params, inv_params=inv_params, flags=flags, relevant_params=["input", "node_layer"]): return -1 if not self.tmp_maps.HasTmpVectMap("vnet_snap_points"): endStr = _( "Do you really want to activate snapping and overwrite it?") self.snapPts = self.tmp_maps.AddTmpVectMap("vnet_snap_points", endStr) if not self.snapPts: return -1 elif self.snapPts.VectMapState() == 0: dlg = wx.MessageDialog( message=_("Temporary map '%s' was changed outside " + "vector analysis tool.\n" "Do you really want to activate " + "snapping and overwrite it? ") % self.snapPts.GetVectMapName(), caption=_("Overwrite map"), style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE) ret = dlg.ShowModal() dlg.Destroy() if ret == wx.ID_NO: self.tmp_maps.DeleteTmpMap(self.snapPts) return -1 self.data.SetSnapping(True) inpFullName = params["input"] inpName, mapSet = inpFullName.split("@") computeNodes = True if "inputMap" not in self.snapData: pass elif inpFullName != self.snapData["inputMap"].GetVectMapName(): self.snapData["inputMap"] = VectMap(None, inpFullName) elif self.snapData["inputMap"].VectMapState() == 1: computeNodes = False # new map needed if computeNodes: if 'cmdThread' not in self.snapData: self.snapData['cmdThread'] = CmdThread(self) else: self.snapData['cmdThread'].abort() cmd = [ "v.to.points", "input=" + params['input'], "output=" + self.snapPts.GetVectMapName(), "use=node", "--overwrite" ] # process GRASS command with argument self.snapData["inputMap"] = VectMap(None, inpFullName) self.snapData["inputMap"].SaveVectMapState() self.Bind(EVT_CMD_DONE, self._onNodesDone) self.snapData['cmdThread'].RunCmd(cmd) self.snapping.emit(evt="computing_points") return 0 # map is already created and up to date for input data else: self.snapPts.AddRenderLayer() self.giface.updateMap.emit(render=True, renderVector=True) self.snapping.emit(evt="computing_points_done") return 1
class SaveWMSLayerDialog(wx.Dialog): """Dialog for saving web service layer into GRASS vector/raster layer. .. todo:: Implement saving data in region of map display. """ def __init__(self, parent, layer, giface): wx.Dialog.__init__( self, parent=parent, title=("Save web service layer as raster map"), id=wx.ID_ANY, ) self.layer = layer self._giface = giface self.cmd = self.layer.GetCmd() self.thread = CmdThread(self) self.cmdStdErr = GStderr(self) self._createWidgets() def _createWidgets(self): self.labels = {} self.params = {} self.labels["output"] = StaticText( parent=self, id=wx.ID_ANY, label=_("Name for output raster map:")) self.params["output"] = Select( parent=self, type="raster", mapsets=[grass.gisenv()["MAPSET"]], size=globalvar.DIALOG_GSELECT_SIZE, ) self.regionStBoxLabel = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Export region")) self.region_types_order = ["display", "comp", "named"] self.region_types = {} self.region_types["display"] = RadioButton(parent=self, label=_("Map display"), style=wx.RB_GROUP) self.region_types["comp"] = RadioButton( parent=self, label=_("Computational region")) self.region_types["named"] = RadioButton(parent=self, label=_("Named region")) self.region_types["display"].SetToolTip( _("Extent and resolution" " are based on Map Display geometry.")) self.region_types["comp"].SetToolTip( _("Extent and resolution" " are based on computational region.")) self.region_types["named"].SetToolTip( _("Extent and resolution" " are based on named region.")) self.region_types["display"].SetValue( True) # set default as map display self.overwrite = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Overwrite existing raster map")) self.named_reg_panel = wx.Panel(parent=self, id=wx.ID_ANY) self.labels["region"] = StaticText(parent=self.named_reg_panel, id=wx.ID_ANY, label=_("Choose named region:")) self.params["region"] = Select( parent=self.named_reg_panel, type="region", size=globalvar.DIALOG_GSELECT_SIZE, ) # buttons self.btn_close = Button(parent=self, id=wx.ID_CLOSE) self.SetEscapeId(self.btn_close.GetId()) self.btn_close.SetToolTip(_("Close dialog")) self.btn_ok = Button(parent=self, label=_("&Save layer")) self.btn_ok.SetToolTip(_("Save web service layer as raster map")) # statusbar self.statusbar = wx.StatusBar(parent=self, id=wx.ID_ANY) self._layout() def _layout(self): self._border = wx.BoxSizer(wx.VERTICAL) dialogSizer = wx.BoxSizer(wx.VERTICAL) regionSizer = wx.BoxSizer(wx.HORIZONTAL) dialogSizer.Add( self._addSelectSizer(title=self.labels["output"], sel=self.params["output"])) regionSizer = wx.StaticBoxSizer(self.regionStBoxLabel, wx.VERTICAL) regionTypeSizer = wx.BoxSizer(wx.HORIZONTAL) for r_type in self.region_types_order: regionTypeSizer.Add(self.region_types[r_type], flag=wx.RIGHT, border=8) regionSizer.Add(regionTypeSizer) self.named_reg_panel.SetSizer( self._addSelectSizer(title=self.labels["region"], sel=self.params["region"])) regionSizer.Add(self.named_reg_panel) self.named_reg_panel.Hide() dialogSizer.Add(regionSizer, flag=wx.EXPAND) dialogSizer.Add(self.overwrite, flag=wx.TOP, border=10) # buttons self.btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL) self.btnsizer.Add(self.btn_close, proportion=0, flag=wx.ALL | wx.ALIGN_CENTER, border=10) self.btnsizer.Add(self.btn_ok, proportion=0, flag=wx.ALL | wx.ALIGN_CENTER, border=10) dialogSizer.Add(self.btnsizer, proportion=0, flag=wx.ALIGN_CENTER) self._border.Add(dialogSizer, proportion=0, flag=wx.ALL, border=5) self._border.Add(self.statusbar, proportion=0) self.SetSizer(self._border) self.Layout() self.Fit() # bindings self.btn_ok.Bind(wx.EVT_BUTTON, self.OnSave) self.Bind(EVT_CMD_DONE, self.OnCmdDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) for r_type in self.region_types_order: self.Bind(wx.EVT_RADIOBUTTON, self.OnRegionType, self.region_types[r_type]) def _addSelectSizer(self, title, sel): """Helper layout function.""" selSizer = wx.BoxSizer(orient=wx.VERTICAL) selTitleSizer = wx.BoxSizer(wx.HORIZONTAL) selTitleSizer.Add(title, proportion=1, flag=wx.LEFT | wx.TOP | wx.EXPAND, border=5) selSizer.Add(selTitleSizer, proportion=0, flag=wx.EXPAND) selSizer.Add( sel, proportion=1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5, ) return selSizer def OnRegionType(self, event): selected = event.GetEventObject() if selected == self.region_types["named"]: self.named_reg_panel.Show() else: self.named_reg_panel.Hide() self._border.Layout() self.Fit() def OnSave(self, event): """Import WMS raster data into GRASS as raster layer.""" self.thread.abort(abortall=True) currmapset = grass.gisenv()["MAPSET"] self.output = self.params["output"].GetValue().strip() l_spl = self.output.strip().split("@") # check output layer msg = None if not self.output: msg = _("Missing output raster.") elif len(l_spl) > 1 and l_spl[1] != currmapset: msg = _("Output map can be added only to current mapset.") elif (not self.overwrite.IsChecked() and grass.find_file(self.output, "cell", ".")["fullname"]): msg = _("Output map <%s> already exists" % self.output) if msg: GMessage(parent=self, message=msg) return self.output = l_spl[0] # check region region = self.params["region"].GetValue().strip() reg_spl = region.strip().split("@") reg_mapset = "." if len(reg_spl) > 1: reg_mapset = reg_spl[1] if self.region_types["named"].GetValue(): if not grass.find_file(reg_spl[0], "windows", reg_mapset)["fullname"]: msg = _("Region <%s> does not exist." % self.params["region"].GetValue()) GWarning(parent=self, message=msg) return # create r.in.wms command cmd = ("r.in.wms", deepcopy(self.cmd[1])) if "map" in cmd[1]: del cmd[1]["map"] cmd[1]["output"] = self.output if self.overwrite.IsChecked(): cmd[1]["overwrite"] = True env = os.environ.copy() if self.region_types["named"].GetValue(): cmd[1]["region"] = region elif self.region_types["display"].GetValue(): region = self._giface.GetMapWindow().GetMap().SetRegion() env["GRASS_REGION"] = region cmdList = cmdtuple_to_list(cmd) self.currentPid = self.thread.GetId() self.thread.RunCmd(cmdList, env=env, stderr=self.cmdStdErr) self.statusbar.SetStatusText(_("Downloading data...")) def OnCmdDone(self, event): """When data are fetched.""" if event.pid != self.currentPid: return self._addLayer() self.statusbar.SetStatusText("") def _addLayer(self): """Add layer into layer tree.""" llist = self._giface.GetLayerList() if len(llist.GetLayersByName(self.output)) == 0: cmd = ["d.rast", "map=" + self.output] llist.AddLayer(ltype="raster", name=self.output, cmd=cmd, checked=True) def OnCmdOutput(self, event): """Handle cmd output according to debug level.""" if Debug.GetLevel() == 0: if event.type == "error": msg = _("Unable to fetch data.\n") msg += event.text GWarning(parent=self, message=msg) else: Debug.msg(1, event.text)
class SaveWMSLayerDialog(wx.Dialog): """Dialog for saving web service layer into GRASS vector/raster layer. .. todo:: Implement saving data in region of map display. """ def __init__(self, parent, layer, giface): wx.Dialog.__init__(self, parent = parent, title = ("Save web service layer as raster map"), id = wx.ID_ANY) self.layer = layer self._giface = giface self.cmd = self.layer.GetCmd() self.thread = CmdThread(self) self.cmdStdErr = GStderr(self) self._createWidgets() def _createWidgets(self): self.labels = {} self.params = {} self.labels['output'] = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Name for output raster map:")) self.params['output'] = Select(parent = self, type = 'raster', mapsets = [grass.gisenv()['MAPSET']], size = globalvar.DIALOG_GSELECT_SIZE) self.regionStBoxLabel = wx.StaticBox(parent = self, id = wx.ID_ANY, label = " %s " % _("Export region")) self.region_types_order = ['display', 'comp', 'named'] self.region_types = {} self.region_types['display'] = wx.RadioButton(parent=self, label=_("Map display"), style=wx.RB_GROUP) self.region_types['comp'] = wx.RadioButton(parent=self, label=_("Computational region")) self.region_types['named'] = wx.RadioButton(parent=self, label=_("Named region")) self.region_types['display'].SetToolTipString(_("Extent and resolution" " are based on Map Display geometry.")) self.region_types['comp'].SetToolTipString(_("Extent and resolution" " are based on computational region.")) self.region_types['named'].SetToolTipString(_("Extent and resolution" " are based on named region.")) self.region_types['display'].SetValue(True) # set default as map display self.overwrite = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Overwrite existing raster map")) self.named_reg_panel = wx.Panel(parent = self, id = wx.ID_ANY) self.labels['region'] = wx.StaticText(parent = self.named_reg_panel, id = wx.ID_ANY, label = _("Choose named region:")) self.params['region'] = Select(parent = self.named_reg_panel, type = 'region', size = globalvar.DIALOG_GSELECT_SIZE) # buttons self.btn_close = wx.Button(parent = self, id = wx.ID_CLOSE) self.btn_close.SetToolTipString(_("Close dialog")) self.btn_ok = wx.Button(parent=self, id=wx.ID_OK, label=_("&Save layer")) self.btn_ok.SetToolTipString(_("Save web service layer as raster map")) # statusbar self.statusbar = wx.StatusBar(parent = self, id = wx.ID_ANY) self._layout() def _layout(self): self._border = wx.BoxSizer(wx.VERTICAL) dialogSizer = wx.BoxSizer(wx.VERTICAL) regionSizer = wx.BoxSizer(wx.HORIZONTAL) dialogSizer.Add(item = self._addSelectSizer(title = self.labels['output'], sel = self.params['output'])) regionSizer = wx.StaticBoxSizer(self.regionStBoxLabel, wx.VERTICAL) regionTypeSizer = wx.BoxSizer(wx.HORIZONTAL) for r_type in self.region_types_order: regionTypeSizer.Add(item=self.region_types[r_type], flag=wx.RIGHT, border=8) regionSizer.Add(item = regionTypeSizer) self.named_reg_panel.SetSizer(self._addSelectSizer(title = self.labels['region'], sel = self.params['region'])) regionSizer.Add(item = self.named_reg_panel) self.named_reg_panel.Hide() dialogSizer.Add(item = regionSizer, flag = wx.EXPAND) dialogSizer.Add(item=self.overwrite, flag=wx.TOP, border=10) # buttons self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL) self.btnsizer.Add(item = self.btn_close, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10) self.btnsizer.Add(item = self.btn_ok, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10) dialogSizer.Add(item = self.btnsizer, proportion = 0, flag = wx.ALIGN_CENTER) self._border.Add(item=dialogSizer, proportion=0, flag=wx.ALL, border=5) self._border.Add(item=self.statusbar, proportion=0) self.SetSizer(self._border) self.Layout() self.Fit() # bindings self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) self.btn_ok.Bind(wx.EVT_BUTTON, self.OnSave) self.Bind(EVT_CMD_DONE, self.OnCmdDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) for r_type in self.region_types_order: self.Bind(wx.EVT_RADIOBUTTON, self.OnRegionType, self.region_types[r_type]) def _addSelectSizer(self, title, sel): """Helper layout function. """ selSizer = wx.BoxSizer(orient = wx.VERTICAL) selTitleSizer = wx.BoxSizer(wx.HORIZONTAL) selTitleSizer.Add(item = title, proportion = 1, flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5) selSizer.Add(item = selTitleSizer, proportion = 0, flag = wx.EXPAND) selSizer.Add(item = sel, proportion = 1, flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL, border = 5) return selSizer def OnClose(self, event): """Close dialog """ if not self.IsModal(): self.Destroy() event.Skip() def OnRegionType(self, event): selected = event.GetEventObject() if selected == self.region_types['named']: self.named_reg_panel.Show() else: self.named_reg_panel.Hide() self._border.Layout() self.Fit() def OnSave(self, event): """Import WMS raster data into GRASS as raster layer. """ self.thread.abort(abortall = True) currmapset = grass.gisenv()['MAPSET'] self.output = self.params['output'].GetValue().strip() l_spl = self.output.strip().split("@") # check output layer msg = None if not self.output: msg = _('Missing output raster.') elif len(l_spl) > 1 and \ l_spl[1] != currmapset: msg = _('Output map can be added only to current mapset.') elif not self.overwrite.IsChecked() and\ grass.find_file(self.output, 'cell', '.')['fullname']: msg = _('Output map <%s> already exists' % self.output) if msg: GMessage(parent = self, message = msg) return self.output = l_spl[0] # check region region = self.params['region'].GetValue().strip() reg_spl = region.strip().split("@") reg_mapset = '.' if len(reg_spl) > 1: reg_mapset = reg_spl[1] if self.region_types['named'].GetValue(): if not grass.find_file(reg_spl[0], 'windows', reg_mapset)['fullname']: msg = _('Region <%s> does not exist.' % self.params['region'].GetValue()) GWarning(parent=self, message=msg) return # create r.in.wms command cmd = ('r.in.wms', deepcopy(self.cmd[1])) if cmd[1].has_key('map'): del cmd[1]['map'] cmd[1]['output'] = self.output if self.overwrite.IsChecked(): cmd[1]['overwrite'] = True env = os.environ.copy() if self.region_types['named'].GetValue(): cmd[1]['region'] = region elif self.region_types['display'].GetValue(): region = self._giface.GetMapWindow().GetMap().SetRegion() env['GRASS_REGION'] = region cmdList = CmdTupleToList(cmd) self.currentPid = self.thread.GetId() self.thread.RunCmd(cmdList, env=env, stderr=self.cmdStdErr) self.statusbar.SetStatusText(_("Downloading data...")) def OnCmdDone(self, event): """When data are fetched. """ if event.pid != self.currentPid: return self._addLayer() self.statusbar.SetStatusText("") def _addLayer(self): """Add layer into layer tree. """ llist = self._giface.GetLayerList() if len(llist.GetLayersByName(self.output)) == 0: cmd = ['d.rast', 'map=' + self.output] llist.AddLayer(ltype='raster', name=self.output, cmd=cmd, checked=True) def OnCmdOutput(self, event): """Handle cmd output according to debug level. """ if Debug.GetLevel() == 0: if event.type == 'error': msg = _('Unable to fetch data.\n') msg += event.text GWarning(parent = self, message = msg) else: Debug.msg(1, event.text)
def __init__(self, parent, web_service, **kwargs): """Show data from capabilities file. Signal: capParsed - this signal is emitted when capabilities file is downloaded (after ConnectToServer method was called) :param parent: parent widget :param web_service: web service to be panel generated for """ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.parent = parent self.ws = web_service self.capParsed = Signal('WSPanel.capParsed') # stores widgets, which represents parameters/flags of d.wms self.params = {} self.flags = {} self.o_layer_name = '' # stores err output from r.in.wms during getting capabilities self.cmd_err_str = '' # stores selected layer from layer list self.sel_layers = [] # downloaded and parsed data from server successfully? self.is_connected = False # common part of command for r.in.wms -c and d.wms self.ws_cmdl = None # provides information about driver parameters self.drv_info = WMSDriversInfo() self.drv_props = self.drv_info.GetDrvProperties(self.ws) self.ws_drvs = { 'WMS_1.1.1': { 'cmd': [ 'wms_version=1.1.1', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.1.1'), }, 'WMS_1.3.0': { 'cmd': [ 'wms_version=1.3.0', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.3.0'), }, 'WMTS': { 'cmd': ['driver=WMTS_GRASS'], 'cap_parser': WMTSCapabilities, }, 'OnEarth': { 'cmd': ['driver=OnEarth_GRASS'], 'cap_parser': OnEarthCapabilities, }} self.cmdStdErr = GStderr(self) self.cmd_thread = CmdThread(self) self.cap_file = grass.tempfile() reqDataBox = StaticBox( parent=self, label=_(" Requested data settings ")) self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL) self.notebook = GNotebook( parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG) self._requestPage() self._advancedSettsPage() self._layout() self.layerSelected = self.list.layerSelected self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.SetMinSize((-1, 300))
class WSPanel(wx.Panel): def __init__(self, parent, web_service, **kwargs): """Show data from capabilities file. Signal: capParsed - this signal is emitted when capabilities file is downloaded (after ConnectToServer method was called) :param parent: parent widget :param web_service: web service to be panel generated for """ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.parent = parent self.ws = web_service self.capParsed = Signal('WSPanel.capParsed') # stores widgets, which represents parameters/flags of d.wms self.params = {} self.flags = {} self.o_layer_name = '' # stores err output from r.in.wms during getting capabilities self.cmd_err_str = '' # stores selected layer from layer list self.sel_layers = [] # downloaded and parsed data from server successfully? self.is_connected = False # common part of command for r.in.wms -c and d.wms self.ws_cmdl = None # provides information about driver parameters self.drv_info = WMSDriversInfo() self.drv_props = self.drv_info.GetDrvProperties(self.ws) self.ws_drvs = { 'WMS_1.1.1': { 'cmd': [ 'wms_version=1.1.1', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.1.1'), }, 'WMS_1.3.0': { 'cmd': [ 'wms_version=1.3.0', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.3.0'), }, 'WMTS': { 'cmd': ['driver=WMTS_GRASS'], 'cap_parser': WMTSCapabilities, }, 'OnEarth': { 'cmd': ['driver=OnEarth_GRASS'], 'cap_parser': OnEarthCapabilities, }} self.cmdStdErr = GStderr(self) self.cmd_thread = CmdThread(self) self.cap_file = grass.tempfile() reqDataBox = StaticBox( parent=self, label=_(" Requested data settings ")) self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL) self.notebook = GNotebook( parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG) self._requestPage() self._advancedSettsPage() self._layout() self.layerSelected = self.list.layerSelected self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.SetMinSize((-1, 300)) def __del__(self): self.cmd_thread.abort(abortall=True) grass.try_remove(self.cap_file) def _layout(self): self._nb_sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND) self.SetSizer(self._nb_sizer) def _requestPage(self): """Create request page""" self.req_page_panel = wx.Panel(parent=self, id=wx.ID_ANY) self.notebook.AddPage(page=self.req_page_panel, text=_('Request'), name='request') # list of layers self.layersBox = StaticBox(parent=self.req_page_panel, id=wx.ID_ANY, label=_("List of layers ")) style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT if self.drv_props['req_multiple_layers']: style = style | wx.TR_MULTIPLE if 'WMS' not in self.ws: style = style | wx.TR_HIDE_ROOT self.list = LayersList(parent=self.req_page_panel, web_service=self.ws, style=style) self.params['format'] = None self.params['srs'] = None if 'srs' not in self.drv_props['ignored_params']: projText = StaticText( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source projection:")) self.params['srs'] = wx.Choice( parent=self.req_page_panel, id=wx.ID_ANY) self.list.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnListSelChanged) # layout self.req_page_sizer = wx.BoxSizer(wx.VERTICAL) layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL) layersSizer.Add( self.list, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_sizer.Add( layersSizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.source_sizer = wx.BoxSizer(wx.HORIZONTAL) if self.params['format'] is not None: self.source_sizer.Add( self.params['format'], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) if self.params['srs'] is not None: self.source_sizer.Add( projText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5) self.source_sizer.Add( self.params['srs'], flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5) self.req_page_sizer.Add( self.source_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_panel.SetSizer(self.req_page_sizer) def enableButtons(self, enable=True): """Enable/disable up, down, buttons """ self.btnUp.Enable(enable) self.btnDown.Enable(enable) def _advancedSettsPage(self): """Create advanced settings page """ # TODO parse maxcol, maxrow, settings from d.wms module? # TODO OnEarth driver - add selection of time adv_setts_panel = ScrolledPanel(parent=self, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER) self.notebook.AddPage(page=adv_setts_panel, text=_('Advanced request settings'), name='adv_req_setts') labels = {} self.l_odrder_list = None if 'WMS' in self.ws: labels['l_order'] = StaticBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Order of layers in raster")) self.l_odrder_list = wx.ListBox( adv_setts_panel, id=wx.ID_ANY, choices=[], style=wx.LB_SINGLE | wx.LB_NEEDED_SB) self.btnUp = Button( adv_setts_panel, id=wx.ID_ANY, label=_("Up")) self.btnDown = Button( adv_setts_panel, id=wx.ID_ANY, label=_("Down")) self.btnUp.Bind(wx.EVT_BUTTON, self.OnUp) self.btnDown.Bind(wx.EVT_BUTTON, self.OnDown) labels['method'] = StaticText(parent=adv_setts_panel, id=wx.ID_ANY, label=_("Reprojection method:")) self.reproj_methods = ['nearest', 'linear', 'cubic', 'cubicspline'] self.params['method'] = wx.Choice( parent=adv_setts_panel, id=wx.ID_ANY, choices=[ _('Nearest neighbor'), _('Linear interpolation'), _('Cubic interpolation'), _('Cubic spline interpolation')]) labels['maxcols'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum columns to request from server at time:")) self.params['maxcols'] = SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) labels['maxrows'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum rows to request from server at time:")) self.params['maxrows'] = SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) min = 100 max = 10000 self.params['maxcols'].SetRange(min, max) self.params['maxrows'].SetRange(min, max) val = 500 self.params['maxcols'].SetValue(val) self.params['maxrows'].SetValue(val) self.flags['o'] = self.params['bgcolor'] = None if 'o' not in self.drv_props['ignored_flags']: self.flags['o'] = wx.CheckBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Do not request transparent data")) self.flags['o'].Bind(wx.EVT_CHECKBOX, self.OnTransparent) labels['bgcolor'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Background color:")) self.params['bgcolor'] = csel.ColourSelect( parent=adv_setts_panel, id=wx.ID_ANY, colour=( 255, 255, 255), size=globalvar.DIALOG_COLOR_SIZE) self.params['bgcolor'].Enable(False) self.params['urlparams'] = None if self.params['urlparams'] not in self.drv_props['ignored_params']: labels['urlparams'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Additional query parameters for server:")) self.params['urlparams'] = TextCtrl( parent=adv_setts_panel, id=wx.ID_ANY) # layout border = wx.BoxSizer(wx.VERTICAL) if 'WMS' in self.ws: boxSizer = wx.StaticBoxSizer(labels['l_order'], wx.VERTICAL) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) gridSizer.Add(self.l_odrder_list, pos=(0, 0), span=(4, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0) gridSizer.Add(self.btnUp, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.Add(self.btnDown, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.AddGrowableCol(0) boxSizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5) border.Add(boxSizer, flag=wx.LEFT | wx.RIGHT | wx.UP | wx.EXPAND, border=5) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 for k in ['method', 'maxcols', 'maxrows', 'o', 'bgcolor']: if k in self.params: param = self.params[k] elif k in self.flags: param = self.flags[k] if param is None: continue if k in labels or k == 'o': if k != 'o': label = labels[k] else: label = param gridSizer.Add(label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) if k != 'o': gridSizer.Add(param, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 1)) row += 1 gridSizer.AddGrowableCol(0) border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) if self.params['urlparams']: gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 gridSizer.Add(labels['urlparams'], flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) gridSizer.Add(self.params['urlparams'], flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos=(row, 1)) gridSizer.AddGrowableCol(1) border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) adv_setts_panel.SetSizer(border) adv_setts_panel.SetAutoLayout(True) adv_setts_panel.SetupScrolling() def OnUp(self, event): """Move selected layer up """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos: self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos)) if pos > 0: self._updateLayerOrderList(selected=(pos - 1)) else: self._updateLayerOrderList(selected=0) def OnDown(self, event): """Move selected to down """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos != len(self.sel_layers) - 1: self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos)) if pos < len(self.sel_layers) - 1: self._updateLayerOrderList(selected=(pos + 1)) else: self._updateLayerOrderList(selected=len(self.sel_layers) - 1) def _updateLayerOrderList(self, selected=None): """Update order in list. """ def getlayercaption(l): if l['title']: cap = (l['title']) else: cap = (l['name']) if l['style']: if l['style']['title']: cap += ' / ' + l['style']['title'] else: cap += ' / ' + l['style']['name'] return cap layer_capts = [getlayercaption(l) for l in self.sel_layers] self.l_odrder_list.Set(layer_capts) if self.l_odrder_list.IsEmpty(): self.enableButtons(False) else: self.enableButtons(True) if selected is not None: self.l_odrder_list.SetSelection(selected) self.l_odrder_list.EnsureVisible(selected) def OnTransparent(self, event): checked = event.IsChecked() if checked: self.params['bgcolor'].Enable(True) else: self.params['bgcolor'].Enable(False) def ConnectToServer(self, url, username, password): """Download and parse data from capabilities file. :param url: server url :type url: str :param username: username for connection :type username: str :param password: password for connection :type password: str """ self._prepareForNewConn(url, username, password) cap_cmd = [ 'r.in.wms', '-c', ('capfile_output=%s' % self.cap_file), '--overwrite'] + self.ws_cmdl self.currentPid = self.cmd_thread.GetId() self.cmd_thread.RunCmd(cap_cmd, stderr=self.cmdStdErr) 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 _prepareForNewConn(self, url, username, password): """Prepare panel for new connection """ self.is_connected = False self.sel_layers = [] self.formats_list = [] self.projs_list = [] self.conn = { 'url': url, 'password': password, 'username': username } conn_cmd = [] for k, v in six.iteritems(self.conn): if v: conn_cmd.append("%s=%s" % (k, v)) self.ws_cmdl = self.ws_drvs[self.ws]['cmd'] + conn_cmd def OnCapDownloadDone(self, event): """Process donwloaded capabilities file and emits capParsed signal (see class constructor). """ if event.pid != self.currentPid: return if event.returncode != 0: if self.cmd_err_str: self.cmd_err_str = _( "Unable to download %s capabilities file\nfrom <%s>:\n" % (self.ws.replace('_', ' '), self.conn['url'])) + self.cmd_err_str self._postCapParsedEvt(error_msg=self.cmd_err_str) self.cmd_err_str = '' return self._parseCapFile(self.cap_file) 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 ParseCapFile(self, url, username, password, cap_file=None,): """Parse capabilities data and emits capParsed signal (see class constructor). """ self._prepareForNewConn(url, username, password) if cap_file is None or not url: self._postCapParsedEvt(None) return shutil.copyfile(cap_file, self.cap_file) self._parseCapFile(self.cap_file) def UpdateWidgetsByCmd(self, cmd): """Update panel widgets accordnig to passed cmd tuple :param cmd: cmd in tuple """ dcmd = cmd[1] layers = [] if 'layers' in dcmd: layers = dcmd['layers'] styles = [] if 'styles' in dcmd: styles = dcmd['styles'] if 'WMS' in self.ws: layers = layers.split(',') styles = styles.split(',') else: layers = [layers] styles = [styles] if len(layers) != len(styles): styles = [''] * len(layers) l_st_list = [] for i in range(len(layers)): l_st_list.append({'style': styles[i], 'layer': layers[i]}) # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed l_st_list = [l for l in reversed(l_st_list)] self.list.SelectLayers(l_st_list) params = {} if 'format' in dcmd: params['format'] = dcmd['format'] if 'srs' in dcmd: params['srs'] = 'EPSG:' + dcmd['srs'] if 'method' in dcmd: params['method'] = dcmd['method'] for p, v in six.iteritems(params): if self.params[p]: self.params[p].SetStringSelection(v) for p, conv_f in [ ('urlparams', None), ('maxcols', int), ('maxrows', int)]: if p in dcmd: v = dcmd[p] if conv_f: v = conv_f(v) self.params[p].SetValue(v) if 'flags' in dcmd and \ 'o' in dcmd['flags']: self.flags['o'].SetValue(1) self.params['bgcolor'].Enable(True) if 'bgcolor' in dcmd and \ self.params['bgcolor']: bgcolor = dcmd['bgcolor'].strip().lower() if len(bgcolor) == 8 and \ '0x' == bgcolor[:2]: colour = '#' + bgcolor[2:] self.params['bgcolor'].SetColour(colour) def IsConnected(self): """Was successful in downloading and parsing capabilities data? """ return self.is_connected def _postCapParsedEvt(self, error_msg): """Helper function """ self.capParsed.emit(error_msg=error_msg) def CreateCmd(self): """Create d.wms cmd from values of panels widgets :return: cmd list :return: None if required widgets do not have selected/filled values. """ # check required widgets if not self._checkImportValues(): return None # create d.wms command lcmd = self.ws_cmdl lcmd = ['d.wms'] + lcmd layers = "layers=" styles = 'styles=' first = True # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed for layer in reversed(self.sel_layers): if not first: layers += ',' styles += ',' first = False layers += layer['name'] if layer['style'] is not None: styles += layer['style']['name'] lcmd.append(layers) lcmd.append(styles) if 'format' not in self.drv_props['ignored_params']: i_format = self.params['format'].GetSelection() lcmd.append("format=%s" % self.formats_list[i_format]) if 'srs' not in self.drv_props['ignored_params']: i_srs = self.params['srs'].GetSelection() srs = self.projs_list[i_srs].split(':')[-1] epsg_num = int(''.join(re.findall(r'\d+', srs))) lcmd.append("srs=%s" % epsg_num) for k in ['maxcols', 'maxrows', 'urlparams']: lcmd.append(k + '=' + str(self.params[k].GetValue())) i_method = self.params['method'].GetSelection() lcmd.append('method=' + self.reproj_methods[i_method]) if 'o' not in self.drv_props['ignored_flags'] and \ self.flags['o'].IsChecked(): lcmd.append('-o') c = self.params['bgcolor'].GetColour() hex_color = wx.Colour( c[0], c[1], c[2]).GetAsString( wx.C2S_HTML_SYNTAX) lcmd.append("bgcolor=" + '0x' + hex_color[1:]) lcmd.append("map=" + self.o_layer_name) return lcmd def OnListSelChanged(self, event): """Update widgets according to selected layer in list. """ curr_sel_ls = self.list.GetSelectedLayers() # update self.sel_layers (selected layer list) if 'WMS' in self.ws: for sel_l in self.sel_layers[:]: if sel_l not in curr_sel_ls: self.sel_layers.remove(sel_l) for l in curr_sel_ls: if l not in self.sel_layers: self.sel_layers.append(l) self._updateLayerOrderList() else: self.sel_layers = curr_sel_ls # update projection self.projs_list = [] projs_list = [] intersect_proj = [] first = True for l in curr_sel_ls: layer_projs = l['cap_intf_l'].GetLayerData('srs') if first: projs_list = layer_projs first = False continue projs_list = set(projs_list).intersection(layer_projs) if 'srs' not in self.drv_props['ignored_params']: for proj in projs_list: proj_code = Srs(proj.strip()).getcode() proj_spl = proj_code.split(':') if proj_spl[0].strip().lower() in self.drv_info.GetSrs(): # accept ogc:crs code self.projs_list.append(proj_code) cur_sel = self.params['srs'].GetStringSelection() self.projs_list = sorted(self.projs_list) self.params['srs'].SetItems(self.projs_list) if cur_sel: self.params['srs'].SetStringSelection(cur_sel) else: try: i = self.projs_list.index('EPSG:4326') self.params['srs'].SetSelection(i) except ValueError: if len(self.projs_list) > 0: self.params['srs'].SetSelection(0) # update format if 'WMS' not in self.ws and \ 'format' not in self.drv_props['ignored_params']: self.formats_list = [] cur_sel = None if self.params['format']: cur_sel = self.params['format'].GetStringSelection() if len(curr_sel_ls) > 0: self.formats_list = sorted( self._getFormats( curr_sel_ls[0]['cap_intf_l'])) self._updateFormatRadioBox(self.formats_list) if cur_sel: if self.params['format']: self.params['format'].SetStringSelection(cur_sel) else: self._setDefaultFormatVal() self.Layout() def _setDefaultFormatVal(self): """Set default format value. """ try: i = self.formats_list.index('png') self.params['format'].SetSelection(i) except ValueError: pass def _updateFormatRadioBox(self, formats_list): """Helper function """ if self.params['format']: self.req_page_sizer.Detach(self.params['format']) self.params['format'].Destroy() if len(self.formats_list) > 0: self.params['format'] = wx.RadioBox( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source image format"), pos=wx.DefaultPosition, choices=formats_list, majorDimension=4, style=wx.RA_SPECIFY_COLS) self.source_sizer.Insert(2, window=self.params['format'], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) def _getFormats(self, layer=None): """Get formats WMS has formats defined generally for whole cap. In WMTS and NASA OnEarh formats are defined for layer. """ formats_label = [] if layer is None: formats_list = self.cap.GetFormats() else: formats_list = layer.GetLayerData('format') for frmt in formats_list: frmt = frmt.strip() label = self.drv_info.GetFormatLabel(frmt) if label: formats_label.append(label) return formats_label def _checkImportValues(self,): """Check if required widgets are selected/filled """ warning_str = "" show_war = False if not self.list or not self.list.GetSelectedLayers(): warning_str += _("Select layer in layer list.\n") show_war = True if self.params['format'] is not None and \ self.params['format'].GetSelection() == -1: warning_str += _("Select source image format.\n") show_war = True if self.params['srs'] is not None and \ self.params['srs'].GetSelection() == -1: warning_str += _("Select source projection.\n") show_war = True if not self.o_layer_name: warning_str += _("Choose output layer name.\n") show_war = True if show_war: GMessage(parent=self.parent, message=warning_str) return False return True def SetOutputLayerName(self, name): """Set name of layer to be added to layer tree """ self.o_layer_name = name def GetOutputLayerName(self): return self.o_layer_name def GetCapFile(self): """Get path to file where capabilities are saved """ return self.cap_file def GetWebService(self): """Get web service """ return self.ws
def __init__(self, parent, web_service, **kwargs): """Show data from capabilities file. Signal: capParsed - this signal is emitted when capabilities file is downloaded (after ConnectToServer method was called) :param parent: parent widget :param web_service: web service to be panel generated for """ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.parent = parent self.ws = web_service self.capParsed = Signal('WSPanel.capParsed') # stores widgets, which represents parameters/flags of d.wms self.params = {} self.flags = {} self.o_layer_name = '' # stores err output from r.in.wms during getting capabilities self.cmd_err_str = '' # stores selected layer from layer list self.sel_layers = [] # downloaded and parsed data from server successfully? self.is_connected = False # common part of command for r.in.wms -c and d.wms self.ws_cmdl = None # provides information about driver parameters self.drv_info = WMSDriversInfo() self.drv_props = self.drv_info.GetDrvProperties(self.ws) self.ws_drvs = { 'WMS_1.1.1': { 'cmd': [ 'wms_version=1.1.1', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.1.1'), }, 'WMS_1.3.0': { 'cmd': [ 'wms_version=1.3.0', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.3.0'), }, 'WMTS': { 'cmd': ['driver=WMTS_GRASS'], 'cap_parser': WMTSCapabilities, }, 'OnEarth': { 'cmd': ['driver=OnEarth_GRASS'], 'cap_parser': OnEarthCapabilities, }} self.cmdStdErr = GStderr(self) self.cmd_thread = CmdThread(self) self.cap_file = grass.tempfile() reqDataBox = wx.StaticBox( parent=self, label=_(" Requested data settings ")) self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL) self.notebook = GNotebook(parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON) self._requestPage() self._advancedSettsPage() self._layout() self.layerSelected = self.list.layerSelected self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
class WSPanel(wx.Panel): def __init__(self, parent, web_service, **kwargs): """Show data from capabilities file. Signal: capParsed - this signal is emitted when capabilities file is downloaded (after ConnectToServer method was called) :param parent: parent widget :param web_service: web service to be panel generated for """ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.parent = parent self.ws = web_service self.capParsed = Signal('WSPanel.capParsed') # stores widgets, which represents parameters/flags of d.wms self.params = {} self.flags = {} self.o_layer_name = '' # stores err output from r.in.wms during getting capabilities self.cmd_err_str = '' # stores selected layer from layer list self.sel_layers = [] # downloaded and parsed data from server successfully? self.is_connected = False # common part of command for r.in.wms -c and d.wms self.ws_cmdl = None # provides information about driver parameters self.drv_info = WMSDriversInfo() self.drv_props = self.drv_info.GetDrvProperties(self.ws) self.ws_drvs = { 'WMS_1.1.1': { 'cmd': [ 'wms_version=1.1.1', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.1.1'), }, 'WMS_1.3.0': { 'cmd': [ 'wms_version=1.3.0', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.3.0'), }, 'WMTS': { 'cmd': ['driver=WMTS_GRASS'], 'cap_parser': WMTSCapabilities, }, 'OnEarth': { 'cmd': ['driver=OnEarth_GRASS'], 'cap_parser': OnEarthCapabilities, }} self.cmdStdErr = GStderr(self) self.cmd_thread = CmdThread(self) self.cap_file = grass.tempfile() reqDataBox = wx.StaticBox( parent=self, label=_(" Requested data settings ")) self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL) self.notebook = GNotebook(parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON) self._requestPage() self._advancedSettsPage() self._layout() self.layerSelected = self.list.layerSelected self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) def __del__(self): self.cmd_thread.abort(abortall=True) grass.try_remove(self.cap_file) def _layout(self): self._nb_sizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND) self.SetSizer(self._nb_sizer) def _requestPage(self): """Create request page""" self.req_page_panel = wx.Panel(parent=self, id=wx.ID_ANY) self.notebook.AddPage(page=self.req_page_panel, text=_('Request'), name='request') # list of layers self.layersBox = wx.StaticBox(parent=self.req_page_panel, id=wx.ID_ANY, label=_("List of layers ")) style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT if self.drv_props['req_multiple_layers']: style = style | wx.TR_MULTIPLE if 'WMS' not in self.ws: style = style | wx.TR_HIDE_ROOT self.list = LayersList(parent=self.req_page_panel, web_service=self.ws, style=style) self.params['format'] = None self.params['srs'] = None if 'srs' not in self.drv_props['ignored_params']: projText = wx.StaticText( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source projection:")) self.params['srs'] = wx.Choice( parent=self.req_page_panel, id=wx.ID_ANY) self.list.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnListSelChanged) # layout self.req_page_sizer = wx.BoxSizer(wx.VERTICAL) layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL) layersSizer.Add( item=self.list, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_sizer.Add( item=layersSizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.source_sizer = wx.BoxSizer(wx.HORIZONTAL) if self.params['format'] is not None: self.source_sizer.Add( item=self.params['format'], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) if self.params['srs'] is not None: self.source_sizer.Add( item=projText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5) self.source_sizer.Add( item=self.params['srs'], flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5) self.req_page_sizer.Add( item=self.source_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_panel.SetSizer(self.req_page_sizer) def enableButtons(self, enable=True): """Enable/disable up, down, buttons """ self.btnUp.Enable(enable) self.btnDown.Enable(enable) def _advancedSettsPage(self): """Create advanced settings page """ # TODO parse maxcol, maxrow, settings from d.wms module? # TODO OnEarth driver - add selection of time adv_setts_panel = wx.Panel(parent=self, id=wx.ID_ANY) self.notebook.AddPage(page=adv_setts_panel, text=_('Advanced request settings'), name='adv_req_setts') labels = {} self.l_odrder_list = None if 'WMS' in self.ws: labels['l_order'] = wx.StaticBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Order of layers in raster")) self.l_odrder_list = wx.ListBox( adv_setts_panel, id=wx.ID_ANY, choices=[], style=wx.LB_SINGLE | wx.LB_NEEDED_SB) self.btnUp = wx.Button( adv_setts_panel, id=wx.ID_ANY, label=_("Up")) self.btnDown = wx.Button( adv_setts_panel, id=wx.ID_ANY, label=_("Down")) self.btnUp.Bind(wx.EVT_BUTTON, self.OnUp) self.btnDown.Bind(wx.EVT_BUTTON, self.OnDown) labels['method'] = wx.StaticText(parent=adv_setts_panel, id=wx.ID_ANY, label=_("Reprojection method:")) self.reproj_methods = ['nearest', 'linear', 'cubic', 'cubicspline'] self.params['method'] = wx.Choice( parent=adv_setts_panel, id=wx.ID_ANY, choices=[ _('Nearest neighbor'), _('Linear interpolation'), _('Cubic interpolation'), _('Cubic spline interpolation')]) labels['maxcols'] = wx.StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum columns to request from server at time:")) self.params['maxcols'] = wx.SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) labels['maxrows'] = wx.StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum rows to request from server at time:")) self.params['maxrows'] = wx.SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) min = 100 max = 10000 self.params['maxcols'].SetRange(min, max) self.params['maxrows'].SetRange(min, max) val = 500 self.params['maxcols'].SetValue(val) self.params['maxrows'].SetValue(val) self.flags['o'] = self.params['bgcolor'] = None if not 'o' in self.drv_props['ignored_flags']: self.flags['o'] = wx.CheckBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Do not request transparent data")) self.flags['o'].Bind(wx.EVT_CHECKBOX, self.OnTransparent) labels['bgcolor'] = wx.StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Background color:")) self.params['bgcolor'] = csel.ColourSelect( parent=adv_setts_panel, id=wx.ID_ANY, colour=( 255, 255, 255), size=globalvar.DIALOG_COLOR_SIZE) self.params['bgcolor'].Enable(False) self.params['urlparams'] = None if self.params['urlparams'] not in self.drv_props['ignored_params']: labels['urlparams'] = wx.StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Additional query parameters for server:")) self.params['urlparams'] = wx.TextCtrl( parent=adv_setts_panel, id=wx.ID_ANY) # layout border = wx.BoxSizer(wx.VERTICAL) if 'WMS' in self.ws: boxSizer = wx.StaticBoxSizer(labels['l_order'], wx.VERTICAL) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) gridSizer.Add(self.l_odrder_list, pos=(0, 0), span=(4, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0) gridSizer.Add(self.btnUp, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.Add(self.btnDown, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.AddGrowableCol(0) boxSizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5) border.Add(item=boxSizer, flag=wx.LEFT | wx.RIGHT | wx.UP | wx.EXPAND, border=5) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 for k in ['method', 'maxcols', 'maxrows', 'o', 'bgcolor']: if k in self.params: param = self.params[k] elif k in self.flags: param = self.flags[k] if param is None: continue if k in labels or k == 'o': if k != 'o': label = labels[k] else: label = param gridSizer.Add(label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) if k != 'o': gridSizer.Add(item=param, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 1)) row += 1 gridSizer.AddGrowableCol(0) border.Add(item=gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) if self.params['urlparams']: gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 gridSizer.Add(labels['urlparams'], flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) gridSizer.Add(item=self.params['urlparams'], flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos=(row, 1)) gridSizer.AddGrowableCol(1) border.Add(item=gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) adv_setts_panel.SetSizer(border) def OnUp(self, event): """Move selected layer up """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos: self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos)) if pos > 0: self._updateLayerOrderList(selected=(pos - 1)) else: self._updateLayerOrderList(selected=0) def OnDown(self, event): """Move selected to down """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos != len(self.sel_layers) - 1: self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos)) if pos < len(self.sel_layers) - 1: self._updateLayerOrderList(selected=(pos + 1)) else: self._updateLayerOrderList(selected=len(self.sel_layers) - 1) def _updateLayerOrderList(self, selected=None): """Update order in list. """ def getlayercaption(layer): if l['title']: cap = (l['title']) else: cap = (l['name']) if l['style']: if l['style']['title']: cap += ' / ' + l['style']['title'] else: cap += ' / ' + l['style']['name'] return cap layer_capts = [getlayercaption(l) for l in self.sel_layers] self.l_odrder_list.Set(layer_capts) if self.l_odrder_list.IsEmpty(): self.enableButtons(False) else: self.enableButtons(True) if selected is not None: self.l_odrder_list.SetSelection(selected) self.l_odrder_list.EnsureVisible(selected) def OnTransparent(self, event): checked = event.IsChecked() if checked: self.params['bgcolor'].Enable(True) else: self.params['bgcolor'].Enable(False) def ConnectToServer(self, url, username, password): """Download and parse data from capabilities file. :param url: server url :type url: str :param username: username for connection :type username: str :param password: password for connection :type password: str """ self._prepareForNewConn(url, username, password) cap_cmd = [ 'r.in.wms', '-c', ('capfile_output=%s' % self.cap_file), '--overwrite'] + self.ws_cmdl self.currentPid = self.cmd_thread.GetId() self.cmd_thread.RunCmd(cap_cmd, stderr=self.cmdStdErr) 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 _prepareForNewConn(self, url, username, password): """Prepare panel for new connection """ self.is_connected = False self.sel_layers = [] self.formats_list = [] self.projs_list = [] self.conn = { 'url': url, 'password': password, 'username': username } conn_cmd = [] for k, v in self.conn.iteritems(): if v: conn_cmd.append("%s=%s" % (k, v)) self.ws_cmdl = self.ws_drvs[self.ws]['cmd'] + conn_cmd def OnCapDownloadDone(self, event): """Process donwloaded capabilities file and emits capParsed signal (see class constructor). """ if event.pid != self.currentPid: return if event.returncode != 0: if self.cmd_err_str: self.cmd_err_str = _( "Unable to download %s capabilities file\nfrom <%s>:\n" % (self.ws.replace('_', ' '), self.conn['url'])) + self.cmd_err_str self._postCapParsedEvt(error_msg=self.cmd_err_str) self.cmd_err_str = '' return self._parseCapFile(self.cap_file) 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 ParseCapFile(self, url, username, password, cap_file=None,): """Parse capabilities data and emits capParsed signal (see class constructor). """ self._prepareForNewConn(url, username, password) if cap_file is None or not url: self._postCapParsedEvt(None) return shutil.copyfile(cap_file, self.cap_file) self._parseCapFile(self.cap_file) def UpdateWidgetsByCmd(self, cmd): """Update panel widgets accordnig to passed cmd tuple :param cmd: cmd in tuple """ dcmd = cmd[1] layers = [] if 'layers' in dcmd: layers = dcmd['layers'] styles = [] if 'styles' in dcmd: styles = dcmd['styles'] if 'WMS' in self.ws: layers = layers.split(',') styles = styles.split(',') else: layers = [layers] styles = [styles] if len(layers) != len(styles): styles = [''] * len(layers) l_st_list = [] for i in range(len(layers)): l_st_list.append({'style': styles[i], 'layer': layers[i]}) # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed l_st_list = [l for l in reversed(l_st_list)] self.list.SelectLayers(l_st_list) params = {} if 'format' in dcmd: params['format'] = dcmd['format'] if 'srs' in dcmd: params['srs'] = 'EPSG:' + dcmd['srs'] if 'method' in dcmd: params['method'] = dcmd['method'] for p, v in params.iteritems(): if self.params[p]: self.params[p].SetStringSelection(v) for p, conv_f in [ ('urlparams', None), ('maxcols', int), ('maxrows', int)]: if p in dcmd: v = dcmd[p] if conv_f: v = conv_f(v) self.params[p].SetValue(v) if 'flags' in dcmd and \ 'o' in dcmd['flags']: self.flags['o'].SetValue(1) self.params['bgcolor'].Enable(True) if 'bgcolor' in dcmd and \ self.params['bgcolor']: bgcolor = dcmd['bgcolor'].strip().lower() if len(bgcolor) == 8 and \ '0x' == bgcolor[:2]: colour = '#' + bgcolor[2:] self.params['bgcolor'].SetColour(colour) def IsConnected(self): """Was successful in downloading and parsing capabilities data? """ return self.is_connected def _postCapParsedEvt(self, error_msg): """Helper function """ self.capParsed.emit(error_msg=error_msg) def CreateCmd(self): """Create d.wms cmd from values of panels widgets :return: cmd list :return: None if required widgets do not have selected/filled values. """ # check required widgets if not self._checkImportValues(): return None # create d.wms command lcmd = self.ws_cmdl lcmd = ['d.wms'] + lcmd layers = "layers=" styles = 'styles=' first = True # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed for layer in reversed(self.sel_layers): if not first: layers += ',' styles += ',' first = False layers += layer['name'] if layer['style'] is not None: styles += layer['style']['name'] lcmd.append(layers) lcmd.append(styles) if 'format' not in self.drv_props['ignored_params']: i_format = self.params['format'].GetSelection() lcmd.append("format=%s" % self.formats_list[i_format]) if 'srs' not in self.drv_props['ignored_params']: i_srs = self.params['srs'].GetSelection() epsg_num = int(self.projs_list[i_srs].split(':')[-1]) lcmd.append("srs=%s" % epsg_num) for k in ['maxcols', 'maxrows', 'urlparams']: lcmd.append(k + '=' + str(self.params[k].GetValue())) i_method = self.params['method'].GetSelection() lcmd.append('method=' + self.reproj_methods[i_method]) if not 'o' in self.drv_props['ignored_flags'] and \ self.flags['o'].IsChecked(): lcmd.append('-o') c = self.params['bgcolor'].GetColour() hex_color = wx.Colour( c[0], c[1], c[2]).GetAsString( wx.C2S_HTML_SYNTAX) lcmd.append("bgcolor=" + '0x' + hex_color[1:]) lcmd.append("map=" + self.o_layer_name) return lcmd def OnListSelChanged(self, event): """Update widgets according to selected layer in list. """ curr_sel_ls = self.list.GetSelectedLayers() # update self.sel_layers (selected layer list) if 'WMS' in self.ws: for sel_l in self.sel_layers[:]: if sel_l not in curr_sel_ls: self.sel_layers.remove(sel_l) for l in curr_sel_ls: if l not in self.sel_layers: self.sel_layers.append(l) self._updateLayerOrderList() else: self.sel_layers = curr_sel_ls # update projection self.projs_list = [] projs_list = [] intersect_proj = [] first = True for l in curr_sel_ls: layer_projs = l['cap_intf_l'].GetLayerData('srs') if first: projs_list = layer_projs first = False continue projs_list = set(projs_list).intersection(layer_projs) if 'srs' not in self.drv_props['ignored_params']: for proj in projs_list: proj_code = Srs(proj.strip()).getcode() proj_spl = proj_code.split(':') if proj_spl[0].strip().lower() in self.drv_info.GetSrs(): try: int(proj_spl[1]) self.projs_list.append(proj_code) except ValueError as IndexError: continue cur_sel = self.params['srs'].GetStringSelection() self.projs_list = sorted(self.projs_list) self.params['srs'].SetItems(self.projs_list) if cur_sel: self.params['srs'].SetStringSelection(cur_sel) else: try: i = self.projs_list.index('EPSG:4326') self.params['srs'].SetSelection(i) except ValueError: if len(self.projs_list) > 0: self.params['srs'].SetSelection(0) # update format if 'WMS' not in self.ws and \ 'format' not in self.drv_props['ignored_params']: self.formats_list = [] cur_sel = None if self.params['format'] is not None: cur_sel = self.params['format'].GetStringSelection() if len(curr_sel_ls) > 0: self.formats_list = sorted( self._getFormats( curr_sel_ls[0]['cap_intf_l'])) self._updateFormatRadioBox(self.formats_list) if cur_sel: self.params['format'].SetStringSelection(cur_sel) else: self._setDefaultFormatVal() self.Layout() def _setDefaultFormatVal(self): """Set default format value. """ try: i = self.formats_list.index('png') self.params['format'].SetSelection(i) except ValueError: pass def _updateFormatRadioBox(self, formats_list): """Helper function """ if self.params['format'] is not None: self.req_page_sizer.Detach(self.params['format']) self.params['format'].Destroy() if len(self.formats_list) > 0: self.params['format'] = wx.RadioBox( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source image format"), pos=wx.DefaultPosition, choices=formats_list, majorDimension=4, style=wx.RA_SPECIFY_COLS) self.source_sizer.Insert(item=self.params['format'], before=2, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) def _getFormats(self, layer=None): """Get formats WMS has formats defined generally for whole cap. In WMTS and NASA OnEarh formats are defined for layer. """ formats_label = [] if layer is None: formats_list = self.cap.GetFormats() else: formats_list = layer.GetLayerData('format') for frmt in formats_list: frmt = frmt.strip() label = self.drv_info.GetFormatLabel(frmt) if label: formats_label.append(label) return formats_label def _checkImportValues(self,): """Check if required widgets are selected/filled """ warning_str = "" show_war = False if not self.list or not self.list.GetSelectedLayers(): warning_str += _("Select layer in layer list.\n") show_war = True if self.params['format'] is not None and \ self.params['format'].GetSelection() == -1: warning_str += _("Select source image format.\n") show_war = True if self.params['srs'] is not None and \ self.params['srs'].GetSelection() == -1: warning_str += _("Select source projection.\n") show_war = True if not self.o_layer_name: warning_str += _("Choose output layer name.\n") show_war = True if show_war: GMessage(parent=self.parent, message=warning_str) return False return True def SetOutputLayerName(self, name): """Set name of layer to be added to layer tree """ self.o_layer_name = name def GetOutputLayerName(self): return self.o_layer_name def GetCapFile(self): """Get path to file where capabilities are saved """ return self.cap_file def GetWebService(self): """Get web service """ return self.ws
class RenderWMSMgr(wx.EvtHandler): """Fetch and prepare WMS data for rendering. """ def __init__(self, layer, mapfile, maskfile): if not haveGdal: sys.stderr.write(_("Unable to load GDAL Python bindings.\n"\ "WMS layers can not be displayed without the bindings.\n")) self.layer = layer wx.EvtHandler.__init__(self) # thread for d.wms commands self.thread = CmdThread(self) self.Bind(EVT_CMD_DONE, self.OnDataFetched) self.downloading = False self.renderedRegion = None self.updateMap = True self.fetched_data_cmd = None self.cmdStdErr = GStderr(self) self.mapfile = mapfile self.maskfile = maskfile self.tempMap = grass.tempfile() self.dstSize = {} self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.dataFetched = Signal('RenderWMSMgr.dataFetched') self.updateProgress = Signal('RenderWMSMgr.updateProgress') def __del__(self): try_remove(self.tempMap) 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 env = copy.copy(env) self.dstSize['cols'] = int(env["GRASS_WIDTH"]) self.dstSize['rows'] = int(env["GRASS_HEIGHT"]) region = self._getRegionDict(env) self._fitAspect(region, self.dstSize) self.updateMap = True fetchData = False 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.mapfile) try_remove(self.tempMap) self.currentPid = self.thread.GetId() self.thread.abort() self.downloading = True self.fetching_cmd = cmd cmdList = utils.CmdTupleToList(cmd) if Debug.GetLevel() < 3: cmdList.append('--quiet') env["GRASS_PNGFILE"] = self.tempMap env["GRASS_REGION"] = self._createRegionStr(region) self.thread.RunCmd(cmdList, env=env, stderr=self.cmdStdErr) def OnCmdOutput(self, event): """Print cmd output according to debug level. """ if Debug.GetLevel() == 0: if event.type == 'error': sys.stderr.write(event.text) sys.stderr.flush() else: Debug.msg(1, event.text) def OnDataFetched(self, event): """Fetch data """ if event.pid != self.currentPid: return self.downloading = False if not self.updateMap: self.updateProgress.emit(layer=self.layer) self.renderedRegion = None self.fetched_data_cmd = None return self.mapMerger = GDALRasterMerger(targetFile=self.mapfile, region=self.renderedRegion, bandsNum=3, gdalDriver='PNM', fillValue=0) self.mapMerger.AddRasterBands(self.tempMap, {1: 1, 2: 2, 3: 3}) del self.mapMerger self.maskMerger = GDALRasterMerger(targetFile=self.maskfile, region=self.renderedRegion, bandsNum=1, gdalDriver='PNM', fillValue=0) #{4 : 1} alpha channel (4) to first and only channel (1) in mask self.maskMerger.AddRasterBands(self.tempMap, {4: 1}) del self.maskMerger self.fetched_data_cmd = self.fetching_cmd self.dataFetched.emit() def _getRegionDict(self, env): """Parse string from GRASS_REGION env variable into dict. """ region = {} parsedRegion = env["GRASS_REGION"].split(';') for r in parsedRegion: r = r.split(':') r[0] = r[0].strip() if len(r) < 2: continue try: if r[0] in ['cols', 'rows']: region[r[0]] = int(r[1]) else: region[r[0]] = float(r[1]) except ValueError: region[r[0]] = r[1] return region def _createRegionStr(self, region): """Create string for GRASS_REGION env variable from dict created by _getRegionDict. """ regionStr = '' for k, v in region.iteritems(): item = k + ': ' + str(v) if regionStr: regionStr += '; ' regionStr += item return regionStr def IsDownloading(self): """Is it downloading any data from WMS server? """ return self.downloading def _fitAspect(self, region, size): """Compute region parameters to have direction independent resolution. """ if region['n-s resol'] > region['e-w resol']: delta = region['n-s resol'] * size['cols'] / 2 center = (region['east'] - region['west']) / 2 region['east'] = center + delta + region['west'] region['west'] = center - delta + region['west'] region['e-w resol'] = region['n-s resol'] else: delta = region['e-w resol'] * size['rows'] / 2 center = (region['north'] - region['south']) / 2 region['north'] = center + delta + region['south'] region['south'] = center - delta + region['south'] region['n-s resol'] = region['e-w resol'] def Abort(self): """Abort process""" self.updateMap = False self.thread.abort(abortall=True)