[GRASS-SVN] r54607 - in grass/trunk/gui/wxpython: . core gcp gui_core lmgr mapdisp ogc_services web_services xml
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Jan 12 08:41:52 PST 2013
Author: martinl
Date: 2013-01-12 08:41:52 -0800 (Sat, 12 Jan 2013)
New Revision: 54607
Added:
grass/trunk/gui/wxpython/web_services/
grass/trunk/gui/wxpython/web_services/cap_interface.py
grass/trunk/gui/wxpython/web_services/dialogs.py
grass/trunk/gui/wxpython/web_services/widgets.py
Modified:
grass/trunk/gui/wxpython/Makefile
grass/trunk/gui/wxpython/core/events.py
grass/trunk/gui/wxpython/core/gconsole.py
grass/trunk/gui/wxpython/core/render.py
grass/trunk/gui/wxpython/core/utils.py
grass/trunk/gui/wxpython/core/ws.py
grass/trunk/gui/wxpython/gcp/mapdisplay.py
grass/trunk/gui/wxpython/gui_core/gselect.py
grass/trunk/gui/wxpython/gui_core/mapwindow.py
grass/trunk/gui/wxpython/gui_core/widgets.py
grass/trunk/gui/wxpython/lmgr/frame.py
grass/trunk/gui/wxpython/lmgr/layertree.py
grass/trunk/gui/wxpython/lmgr/toolbars.py
grass/trunk/gui/wxpython/mapdisp/mapwindow.py
grass/trunk/gui/wxpython/ogc_services/wms.py
grass/trunk/gui/wxpython/xml/menudata.xml
Log:
wxGUI: fully-featured support for web services (work in progress)
patch provided by Stepan Turek
Modified: grass/trunk/gui/wxpython/Makefile
===================================================================
--- grass/trunk/gui/wxpython/Makefile 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/Makefile 2013-01-12 16:41:52 UTC (rev 54607)
@@ -11,12 +11,12 @@
SRCFILES := $(wildcard icons/*.* scripts/* xml/*) \
$(wildcard animation/* core/* dbmgr/* gcp/* gmodeler/* gui_core/* iclass/* lmgr/* location_wizard/* \
- mapdisp/* modules/* nviz/* psmap/* mapswipe/* vdigit/* wxplot/* ogc_services/* rlisetup/* vnet/*) \
+ mapdisp/* modules/* nviz/* psmap/* mapswipe/* vdigit/* wxplot/* web_services/* rlisetup/* vnet/*) \
gis_set.py gis_set_error.py wxgui.py README
DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler gui_core iclass lmgr location_wizard \
- mapdisp modules nviz psmap mapswipe vdigit wxplot ogc_services rlisetup vnet)
+ mapdisp modules nviz psmap mapswipe vdigit wxplot web_services rlisetup vnet)
DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
default: $(DSTFILES)
Modified: grass/trunk/gui/wxpython/core/events.py
===================================================================
--- grass/trunk/gui/wxpython/core/events.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/core/events.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -44,3 +44,14 @@
gMapCreated, EVT_MAP_CREATED = NewCommandEvent()
gZoomChanged, EVT_ZOOM_CHANGED = NewEvent()
+
+# Post it to BufferedWindow instance, which you want to update.
+# For relevant attributes for the event see
+# mapdisp.mapwindow.BufferedWindow UpdateMap method arguments.
+# If event does not contain attribute corresponding to argument with default
+# value, the default value will be used.
+# Arguments with no default value must be among event attributes
+# in order to be the event processed.
+# TODO implement to NVIZ GLWindow
+# TODO change direct calling of UpdateMap method to posting this event
+gUpdateMap, EVT_UPDATE_MAP = NewEvent()
Modified: grass/trunk/gui/wxpython/core/gconsole.py
===================================================================
--- grass/trunk/gui/wxpython/core/gconsole.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/core/gconsole.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -126,11 +126,15 @@
requestTime = time.time()
# prepare
+ if not self.receiver:
+ return
+
event = wxCmdPrepare(cmd=args[0],
time=requestTime,
pid=requestId,
onPrepare=vars()['onPrepare'],
userData=vars()['userData'])
+
wx.PostEvent(self.receiver, event)
# run command
@@ -188,6 +192,9 @@
self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
self.resultQ.put((requestId, self.requestCmdColor.run()))
+ if not self.receiver:
+ return
+
event = wxCmdDone(cmd=args[0],
aborted=aborted,
returncode=returncode,
Modified: grass/trunk/gui/wxpython/core/render.py
===================================================================
--- grass/trunk/gui/wxpython/core/render.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/core/render.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -6,6 +6,8 @@
@todo Implement RenderManager also for other layers (see WMS
implementation for details)
+ at todo Render classes should not care about updating statusbar (change emiting events).
+
Classes:
- render::Layer
- render::MapLayer
@@ -36,13 +38,14 @@
from grass.script import core as grass
from core import utils
-from core.ws import RenderWMSMgr
from core.gcmd import GException, GError, RunCommand
from core.debug import Debug
from core.settings import UserSettings
wxUpdateProgressBar, EVT_UPDATE_PRGBAR = NewEvent()
+from core.ws import RenderWMSMgr
+
USE_GPNMCOMP = True
class Layer(object):
@@ -51,10 +54,8 @@
- For map layer use MapLayer class.
- For overlays use Overlay class.
-
- @todo needs refactoring (avoid parent)
"""
- def __init__(self, ltype, cmd, parent, name = None,
+ def __init__(self, ltype, cmd, Map, name = None,
active = True, hidden = False, opacity = 1.0):
"""!Create new instance
@@ -63,12 +64,12 @@
@param ltype layer type ('raster', 'vector', 'overlay', 'command', etc.)
@param cmd GRASS command to render layer,
given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
+ @param Map render.Map instance
@param name layer name, e.g. 'elevation at PERMANENT' (for layer tree)
@param active layer is active, will be rendered only if True
@param hidden layer is hidden, won't be listed in Layer Manager if True
@param opacity layer opacity <0;1>
"""
- self.parent = parent
# generated file for each layer
if USE_GPNMCOMP or ltype == 'overlay':
@@ -84,6 +85,8 @@
# stores class which manages rendering instead of simple command - e. g. wms
self.renderMgr = None
+
+ self.Map = Map
self.type = None
self.SetType(ltype)
self.name = name
@@ -178,8 +181,6 @@
def _runCommand(self, cmd):
"""!Run command to render data
-
- @todo catch error for wms (?)
"""
if self.type == 'wms':
ret = 0
@@ -268,7 +269,11 @@
raise GException(_("Unsupported map layer type '%s'") % ltype)
if ltype == 'wms' and not isinstance(self.renderMgr, RenderWMSMgr):
- self.renderMgr = RenderWMSMgr(self, self.mapfile, self.maskfile)
+ self.renderMgr = RenderWMSMgr(receiver = self.Map.GetReceiver(),
+ layer = self,
+ Map = self.Map,
+ mapfile = self.mapfile,
+ maskfile = self.maskfile)
elif self.type == 'wms' and ltype != 'wms':
self.renderMgr = None
@@ -315,27 +320,32 @@
else:
return self.renderMgr.IsDownloading()
- def AbortDownload(self):
- """!Abort downloading data"""
+ def AbortThread(self):
+ """!Abort running thread e. g. downloading data"""
if self.renderMgr is None:
return
else:
self.renderMgr.Abort()
+ def GetRenderMgr(self):
+ """!Get render manager """
+ return self.renderMgr
+
class MapLayer(Layer):
- def __init__(self, ltype, cmd, parent, name = None,
+ def __init__(self, ltype, cmd, Map, name = None,
active = True, hidden = False, opacity = 1.0):
"""!Represents map layer in the map canvas
@param ltype layer type ('raster', 'vector', 'command', etc.)
@param cmd GRASS command to render layer,
given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
+ @param Map render.Map instance
@param name layer name, e.g. 'elevation at PERMANENT' (for layer tree) or None
@param active layer is active, will be rendered only if True
@param hidden layer is hidden, won't be listed in Layer Manager if True
@param opacity layer opacity <0;1>
"""
- Layer.__init__(self, ltype, cmd, parent, name,
+ Layer.__init__(self, ltype, cmd, Map, name,
active, hidden, opacity)
def GetMapset(self):
@@ -353,7 +363,7 @@
return self.name
class Overlay(Layer):
- def __init__(self, id, ltype, cmd, parent,
+ def __init__(self, id, ltype, cmd, Map,
active = True, hidden = True, opacity = 1.0):
"""!Represents overlay displayed in map canvas
@@ -361,11 +371,12 @@
@param type overlay type ('barscale', 'legend', etc.)
@param cmd GRASS command to render overlay,
given as list, e.g. ['d.legend', 'map=elevation at PERMANENT']
+ @param Map render.Map instance
@param active layer is active, will be rendered only if True
@param hidden layer is hidden, won't be listed in Layer Manager if True
@param opacity layer opacity <0;1>
"""
- Layer.__init__(self, 'overlay', cmd, parent, ltype,
+ Layer.__init__(self, 'overlay', cmd, Map, ltype,
active, hidden, opacity)
self.id = id
@@ -400,8 +411,8 @@
self._initGisEnv() # g.gisenv
self.GetWindow()
- # reference to mapWindow, which contains this Map instance
- self.mapWin = None
+ # receiver of events
+ self.receiver = None
# GRASS environment variable (for rendering)
self.env = {"GRASS_BACKGROUNDCOLOR" : "FFFFFF",
@@ -607,7 +618,7 @@
@param update if True update current display region settings
@param add3d add 3d region settings
- @return region settings as directory, e.g. {
+ @return region settings as dictionary, e.g. {
'n':'4928010', 's':'4913700', 'w':'589980',...}
@see GetCurrentRegion()
@@ -796,7 +807,7 @@
except:
return None
-
+
def GetListOfLayers(self, ltype = None, mapset = None, name = None,
active = None, hidden = None):
"""!Returns list of layers of selected properties or list of
@@ -865,11 +876,10 @@
return selected
- def _renderLayers(self, force = False, mapWindow = None, overlaysOnly = False):
+ def _renderLayers(self, force = False, overlaysOnly = False):
"""!Render all map layers into files
@param force True to force rendering
- @param mapWindow GUI window or None (statusbar/progress bar)
@param overlaysOnly True to render only overlays
@return list of maps, masks and opacities
@@ -884,13 +894,9 @@
layers = self.layers + self.overlays
self.downloading = False
- ### event = wxUpdateProgressBar(layer = None, map = self)
- # When using Event for progress update, the event is handled after
- # rendering. Maybe there exists some better solution than calling
- # the method directly.
- if mapWindow:
- mapWindow.GetProgressBar().UpdateProgress(None, self)
- ### wx.PostEvent(mapWindow, event)
+ if self.receiver:
+ event = wxUpdateProgressBar(layer = None, map = self)
+ self.receiver.GetEventHandler().ProcessEvent(event)
for layer in layers:
# skip non-active map layers
if not layer or not layer.active:
@@ -903,12 +909,9 @@
if layer.IsDownloading():
self.downloading = True
- if mapWindow:
- # update progress bar
- ### wx.SafeYield(mapWindow)
- mapWindow.GetProgressBar().UpdateProgress(layer, self)
- #event = wxUpdateProgressBar(layer = layer, map = self)
- #wx.PostEvent(mapWindow, event)
+ if self.receiver:
+ event = wxUpdateProgressBar(layer = layer, map = self)
+ self.receiver.GetEventHandler().ProcessEvent(event)
# skip map layers when rendering fails
if not os.path.exists(layer.mapfile):
@@ -924,22 +927,21 @@
return maps, masks, opacities
- def GetMapsMasksAndOpacities(self, force, guiFrame, windres):
+ def GetMapsMasksAndOpacities(self, force, windres):
"""!
Used by Render function.
@return maps, masks, opacities
"""
- return self._renderLayers(force, guiFrame)
+ return self._renderLayers(force)
- def Render(self, force = False, mapWindow = None, windres = False):
+ def Render(self, force = False, windres = False):
"""!Creates final image composite
This function can conditionaly use high-level tools, which
should be avaliable in wxPython library
@param force force rendering
- @param mapWindow reference for MapFrame or similar instance for progress bar
@param windres use region resolution (True) otherwise display resolution
@return name of file with rendered image or None
@@ -960,7 +962,7 @@
else:
os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
- maps, masks, opacities = self.GetMapsMasksAndOpacities(force, mapWindow, windres)
+ maps, masks, opacities = self.GetMapsMasksAndOpacities(force, windres)
# ugly hack for MSYS
if sys.platform != 'win32':
@@ -1038,7 +1040,7 @@
opacity = 0
elif opacity > 1:
opacity = 1
- layer = MapLayer(ltype = ltype, name = name, cmd = command, parent = self,
+ layer = MapLayer(ltype = ltype, name = name, cmd = command, Map = self,
active = active, hidden = hidden, opacity = opacity)
# add maplayer to the list of layers
@@ -1189,7 +1191,7 @@
Layer is defined by name at mapset or id.
@param name layer name (must be unique)
- @param id layer index in layer list
+ @param id layer index in layer list def __init__(self, targetFile, region, bandsNum, gdalDriver, fillValue = None):
@return removed layer on success
@return None on failure
@@ -1245,7 +1247,7 @@
@return None on failure
"""
Debug.msg (2, "Map.AddOverlay(): cmd=%s, render=%d" % (command, render))
- overlay = Overlay(id = id, ltype = ltype, cmd = command, parent = self,
+ overlay = Overlay(id = id, ltype = ltype, cmd = command, Map = self,
active = active, hidden = hidden, opacity = opacity)
# add maplayer to the list of layers
@@ -1356,14 +1358,22 @@
if force or layer.forceRender:
layer.Render()
- def SetParentMapWindow(self, mapWin):
- """!Set reference to parent MapWindow"""
- self.mapWin = mapWin
+ def GetReceiver(self):
+ """!Get event receiver"""
+ return self.receiver
- def GetParentMapWindow(self):
- """!Get reference to parent MapWindow"""
- return self.mapWin
+ def SetReceiver(self, receiver):
+ """!Set events receiver
- def IsDownloading(self):
- """!Is any layer downloading data from web server e. g. wms"""
- return self.downloading
+ @todo If it will be needed to change receiver, take care of running threads.
+ """
+ self.receiver = receiver
+ for l in self.overlays + self.layers:
+ if l.GetRenderMgr():
+ l.GetRenderMgr().SetReceiver(self.receiver)
+
+ def AbortAllThreads(self, old_receiver = None):
+ """!Abort all layers threads e. g. donwloading data"""
+ for l in self.layers + self.overlays:
+ l.AbortThread(old_receiver)
+
\ No newline at end of file
Modified: grass/trunk/gui/wxpython/core/utils.py
===================================================================
--- grass/trunk/gui/wxpython/core/utils.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/core/utils.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -19,6 +19,7 @@
import glob
import shlex
import re
+import inspect
from core.globalvar import ETCDIR
sys.path.append(os.path.join(ETCDIR, "python"))
@@ -907,3 +908,37 @@
rgb = (200, 200, 200)
label = _('Select Color')
return (rgb, label)
+
+def GetGEventAttribsForHandler(method, event):
+ """!Get attributes from event, which can be used by handler method.
+
+ Be aware of event class attributes.
+
+ @param method - handler method (including self arg)
+ @param event - event
+
+ @return (valid kwargs for method,
+ list of method's args without default value
+ which were not found among event attributes)
+ """
+ args_spec = inspect.getargspec(method)
+
+ args = args_spec[0]
+
+ defaults =[]
+ if args_spec[3]:
+ defaults = args_spec[3]
+
+ # number of arguments without def value
+ req_args = len(args) - 1 - len(defaults)
+
+ kwargs = {}
+ missing_args = []
+
+ for i, a in enumerate(args):
+ if hasattr(event, a):
+ kwargs[a] = getattr(event, a)
+ elif i < req_args:
+ missing_args.append(a)
+
+ return kwargs, missing_args
Modified: grass/trunk/gui/wxpython/core/ws.py
===================================================================
--- grass/trunk/gui/wxpython/core/ws.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/core/ws.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -7,7 +7,6 @@
Classes:
- ws::RenderWMSMgr
- - ws::StdErr
- ws::GDALRasterMerger
(C) 2012 by the GRASS Development Team
@@ -25,9 +24,11 @@
from grass.script import core as grass
from core import utils
+from core.events import gUpdateMap
+from core.render import wxUpdateProgressBar
from core.debug import Debug
-from core.gconsole import CmdThread, EVT_CMD_DONE
+from core.gconsole import CmdThread, GStderr, EVT_CMD_DONE, EVT_CMD_OUTPUT
from core.gcmd import GException
try:
@@ -39,31 +40,35 @@
class RenderWMSMgr(wx.EvtHandler):
"""!Fetch and prepare WMS data for rendering.
-
- @todo statusbar: updtade by event or call method ???
"""
- def __init__(self, parent, mapfile, maskfile):
+ def __init__(self, receiver, layer, Map, 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.parent = parent
+
+ self.Map = Map
+ self.receiver = receiver
+ self.layer = layer
+ wx.EvtHandler.__init__(self)
+
# thread for d.wms commands
self.thread = CmdThread(self)
- wx.EvtHandler.__init__(self)
self.Bind(EVT_CMD_DONE, self.OnDataFetched)
self.downloading = False
self.renderedRegion = None
self.updateMap = True
+ self.fetched_data_cmd = None
- self.cmdStdErr = StdErr()
+ self.cmdStdErr = GStderr(self)
self.mapfile = mapfile
self.maskfile = maskfile
self.tempMap = grass.tempfile()
self.dstSize = {}
+
+ self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
def __del__(self):
grass.try_remove(self.tempMap)
@@ -87,7 +92,8 @@
fetchData = False
zoomChanged = False
- if self.renderedRegion is None:
+ if self.renderedRegion is None or \
+ cmd != self.fetched_data_cmd:
fetchData = True
else:
for c in ['north', 'south', 'east', 'west']:
@@ -103,6 +109,7 @@
break
if fetchData:
+ self.fetched_data_cmd = None
self.renderedRegion = region
grass.try_remove(self.mapfile)
@@ -112,12 +119,15 @@
self.thread.abort()
self.downloading = True
+ self.fetching_cmd = cmd
cmdList = utils.CmdTupleToList(cmd)
if Debug.GetLevel() < 3:
cmdList.append('--quiet')
-
- tempPngfile = os.environ["GRASS_PNGFILE"]
+
+ tempPngfile = None
+ if "GRASS_PNGFILE" in os.environ:
+ tempPngfile = os.environ["GRASS_PNGFILE"]
os.environ["GRASS_PNGFILE"] = self.tempMap
tempRegion = os.environ["GRASS_REGION"]
@@ -125,22 +135,34 @@
self.thread.RunCmd(cmdList, env = os.environ.copy(), stderr = self.cmdStdErr)
- os.environ["GRASS_PNGFILE"] = tempPngfile
+ os.environ.pop("GRASS_PNGFILE")
+ if tempPngfile:
+ os.environ["GRASS_PNGFILE"] = tempPngfile
+
os.environ["GRASS_REGION"] = tempRegion
+ 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
-
- @todo ?
- @todo needs refactoring - self.parent.parent.mapWin.UpdateMap
"""
if event.pid != self.currentPid:
return
self.downloading = False
if not self.updateMap:
- # TODO
- self.parent.parent.GetParentMapWindow().frame.GetProgressBar().UpdateProgress(self.parent, self.parent.parent)
+ if self.receiver:
+ event = wxUpdateProgressBar(layer = self.layer, map = self.Map)
+ self.receiver.GetEventHandler().ProcessEvent(event)
self.renderedRegion = None
+ self.fetched_data_cmd = None
return
self.mapMerger = GDALRasterMerger(targetFile = self.mapfile, region = self.renderedRegion,
@@ -154,8 +176,12 @@
self.maskMerger.AddRasterBands(self.tempMap, {4 : 1})
del self.maskMerger
- self.parent.parent.GetParentMapWindow().UpdateMap(render = True)
+ self.fetched_data_cmd = self.fetching_cmd
+ if self.receiver:
+ event = gUpdateMap()
+ wx.PostEvent(self.receiver, event)
+
def _getRegionDict(self):
"""!Parse string from GRASS_REGION env variable into dict.
"""
@@ -219,37 +245,13 @@
self.updateMap = False
self.thread.abort(abortall = True)
-class StdErr:
- """!Redirect error output according to debug mode.
+ def SetReceiver(self, receiver):
+ """!Set events receiver
- @todo: replace or move to the other module (gconsole???)
- """
- def flush(self):
- pass
-
- def write(self, s):
- if "GtkPizza" in s:
- return
- if Debug.GetLevel() == 0:
- message = ''
- for line in s.splitlines():
- if len(line) == 0:
- continue
- if 'GRASS_INFO_ERROR' in line:
- message += line.split(':', 1)[1].strip() + '\n'
- elif 'ERROR:' in line:
- message = line
- if message:
- sys.stderr.write(message)
- message = ''
- sys.stderr.flush()
+ @todo If it will be needed to change receiver, take care of running threads.
+ """
+ self.receiver = receiver
- elif Debug.GetLevel() >= 1:
- for line in s.splitlines():
- if len(line) == 0:
- continue
- Debug.msg(3, line)
-
class GDALRasterMerger:
"""!Merge rasters.
@@ -341,7 +343,16 @@
lrx = geoTrans[0] + size['cols'] * geoTrans[1]
lry = geoTrans[3] + size['rows'] * geoTrans[5]
- return ulx, uly, lrx, lry
+ return ulx, uly, lrx, lry
+ def SetGeorefAndProj(self):
+ """!Set georeference and projection to target file
+ """
+ projection = grass.read_command('g.proj',
+ flags = 'wf')
+ self.tDataset.SetProjection(projection)
+
+ self.tDataset.SetGeoTransform(self.tGeotransform)
+
def __del__(self):
self.tDataset = None
Modified: grass/trunk/gui/wxpython/gcp/mapdisplay.py
===================================================================
--- grass/trunk/gui/wxpython/gcp/mapdisplay.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/gcp/mapdisplay.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -23,7 +23,6 @@
import wx
import wx.aui
-from core.render import EVT_UPDATE_PRGBAR
from mapdisp.toolbars import MapToolbar
from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
from mapdisp.gprint import PrintOptions
@@ -134,7 +133,6 @@
#
# Bind various events
#
- self.Bind(EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
#
Modified: grass/trunk/gui/wxpython/gui_core/gselect.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/gselect.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/gui_core/gselect.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -54,6 +54,8 @@
import grass.temporal as tgis
from grass.script import task as gtask
+from gui_core.widgets import ManageSettingsWidget, EVT_SETTINGS_CHANGED, EVT_SETTINGS_SAVING
+
from core.gcmd import RunCommand, GError, GMessage
from core.utils import GetListOfLocations, GetListOfMapsets, GetFormats
from core.utils import GetSettingsPath, GetValidLayerName, ListSortLower
@@ -1162,9 +1164,17 @@
self.dest = dest
wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
- self.settingsBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = " %s " % _("Settings"))
+ if self.ogr:
+ settingsFile = os.path.join(GetSettingsPath(), 'wxOGR')
+ else:
+ settingsFile = os.path.join(GetSettingsPath(), 'wxGDAL')
+ self.settsManager = ManageSettingsWidget(parent = self,
+ id = wx.ID_ANY,
+ settingsFile = settingsFile)
+ self.settsManager.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
+ self.settsManager.Bind(EVT_SETTINGS_SAVING, self.OnSettingsSaving)
+
self.inputBox = wx.StaticBox(parent = self, id = wx.ID_ANY)
if dest:
self.inputBox.SetLabel(" %s " % _("Output settings"))
@@ -1208,21 +1218,6 @@
sources.append(_("PostGIS (PG)"))
self.sourceMap['db-pg'] = idx
- if self.ogr:
- self.settingsFile = os.path.join(GetSettingsPath(), 'wxOGR')
- else:
- self.settingsFile = os.path.join(GetSettingsPath(), 'wxGDAL')
-
- self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
- self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsLoad)
- self._settings = self._loadSettings() # -> self.settingsChoice.SetItems()
- self.btnSettingsSave = wx.Button(parent = self, id = wx.ID_SAVE)
- self.btnSettingsSave.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
- self.btnSettingsSave.SetToolTipString(_("Save current settings"))
- self.btnSettingsDel = wx.Button(parent = self, id = wx.ID_REMOVE)
- self.btnSettingsDel.Bind(wx.EVT_BUTTON, self.OnSettingsDelete)
- self.btnSettingsSave.SetToolTipString(_("Delete currently selected settings"))
-
self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
style = wx.RA_SPECIFY_COLS,
choices = sources)
@@ -1360,23 +1355,7 @@
def _layout(self):
"""!Layout"""
mainSizer = wx.BoxSizer(wx.VERTICAL)
-
- settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
- settingsSizer.Add(item = wx.StaticText(parent = self,
- id = wx.ID_ANY,
- label = _("Load settings:")),
- flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
- border = 5)
- settingsSizer.Add(item = self.settingsChoice,
- proportion = 1,
- flag = wx.EXPAND)
- settingsSizer.Add(item = self.btnSettingsSave,
- flag = wx.LEFT | wx.RIGHT,
- border = 5)
- settingsSizer.Add(item = self.btnSettingsDel,
- flag = wx.RIGHT,
- border = 5)
-
+
inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
self.dsnSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
@@ -1417,7 +1396,7 @@
inputSizer.Add(item=self.dsnSizer, proportion = 1,
flag=wx.EXPAND | wx.BOTTOM, border = 10)
- mainSizer.Add(item=settingsSizer, proportion=0,
+ mainSizer.Add(item=self.settsManager, proportion=0,
flag=wx.ALL | wx.EXPAND, border=5)
mainSizer.Add(item=self.source, proportion=0,
flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
@@ -1427,6 +1406,33 @@
self.SetSizer(mainSizer)
mainSizer.Fit(self)
+ def OnSettingsChanged(self, event):
+ """!User changed setting"""
+ data = event.data
+
+ # data list: [type, dsn, format, options]
+ if len(data) == 3:
+ data.append('')
+ elif len < 3:
+ return
+
+ self.OnSetType(event = None, sel = self.sourceMap[data[0]])
+ self.OnSetFormat(event = None, format = data[2])
+ self.OnSetDsn(event = None, path = data[1])
+ self.creationOpt.SetValue(data[3])
+
+ def OnSettingsSaving(self, event):
+ """!Saving data"""
+ if not self.GetDsn():
+ GMessage(parent = self,
+ message = _("No data source defined, settings are not saved."))
+ return
+
+ self.settsManager.SetDataToSave((self.dsnType, self.GetDsn(),
+ self.format.GetStringSelection(),
+ self.creationOpt.GetValue()))
+ event.Skip()
+
def _getExtPatternGlob(self, ext):
"""!Get pattern for case-insensitive globing"""
pattern = '*.'
@@ -1438,123 +1444,7 @@
"""!Get pattern for case-insensitive file mask"""
return '*.%s;*.%s' % (ext.lower(), ext.upper())
- def OnSettingsLoad(self, event):
- """!Load named settings"""
- name = event.GetString()
- if name not in self._settings:
- GError(parent = self,
- message = _("Settings <%s> not found") % name)
- return
- data = self._settings[name]
- self.OnSetType(event = None, sel = self.sourceMap[data[0]])
- self.OnSetFormat(event = None, format = data[2])
- self.OnSetDsn(event = None, path = data[1])
- self.creationOpt.SetValue(data[3])
-
- def OnSettingsSave(self, event):
- """!Save settings"""
- dlg = wx.TextEntryDialog(parent = self,
- message = _("Name:"),
- caption = _("Save settings"))
- if dlg.ShowModal() != wx.ID_OK:
- return
-
- # check required params
- if not dlg.GetValue():
- GMessage(parent = self,
- message = _("Name not given, settings is not saved."))
- return
-
- if not self.GetDsn():
- GMessage(parent = self,
- message = _("No data source defined, settings is not saved."))
- return
-
- name = dlg.GetValue()
-
- # check if settings item already exists
- if name in self._settings:
- dlgOwt = wx.MessageDialog(self, message = _("Settings <%s> already exists. "
- "Do you want to overwrite the settings?") % name,
- caption = _("Save settings"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
- if dlgOwt.ShowModal() != wx.ID_YES:
- dlgOwt.Destroy()
- return
-
- self._settings[name] = (self.dsnType, self.GetDsn(),
- self.format.GetStringSelection(),
- self.creationOpt.GetValue())
-
- if self._saveSettings() == 0:
- self._settings = self._loadSettings()
- self.settingsChoice.SetStringSelection(name)
-
- dlg.Destroy()
-
- def OnSettingsDelete(self, event):
- """!Save settings"""
- name = self.settingsChoice.GetStringSelection()
- if not name:
- GMessage(parent = self,
- message = _("No settings is defined. Operation canceled."))
- return
-
- self._settings.pop(name)
- if self._saveSettings() == 0:
- self._settings = self._loadSettings()
-
- def _saveSettings(self):
- """!Save settings into the file
- @return 0 on success
- @return -1 on failure
- """
- try:
- fd = open(self.settingsFile, 'w')
- for key, value in self._settings.iteritems():
- fd.write('%s;%s;%s;%s\n' % (key, value[0], value[1], value[2]))
- except IOError:
- GError(parent = self,
- message = _("Unable to save settings"))
- return -1
- else:
- fd.close()
-
- return 0
-
- def _loadSettings(self):
- """!Load settings from the file
-
- The file is defined by self.SettingsFile.
-
- @return parsed dict
- @return empty dict on error
- """
- data = dict()
- if not os.path.exists(self.settingsFile):
- return data
-
- try:
- fd = open(self.settingsFile, 'r')
- for line in fd.readlines():
- try:
- lineData = line.rstrip('\n').split(';')
- if len(lineData) > 4:
- # type, dsn, format, options
- data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
- else:
- data[lineData[0]] = (lineData[1], lineData[2], lineData[3], '')
- except ValueError:
- pass
- except IOError:
- return data
- else:
- fd.close()
-
- self.settingsChoice.SetItems(sorted(data.keys()))
-
- return data
-
def OnSetType(self, event, sel = None):
"""!Datasource type changed"""
if event:
Modified: grass/trunk/gui/wxpython/gui_core/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/mapwindow.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/gui_core/mapwindow.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -39,9 +39,9 @@
def __init__(self, parent, giface, Map, frame, **kwargs):
self.parent = parent
self.Map = Map
- self.Map.SetParentMapWindow(self)
self.frame = frame
self._giface = giface
+ self.Map.SetReceiver(self)
# mouse attributes -- position on the screen, begin and end of
# dragging, and type of drawing
Modified: grass/trunk/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/widgets.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/gui_core/widgets.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -16,6 +16,7 @@
- widgets::ItemTree
- widgets::GListCtrl
- widgets::SearchModuleWidget
+ - widgets::ManageSettingsWidget
(C) 2008-2012 by the GRASS Development Team
@@ -25,6 +26,7 @@
@author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
@author Enhancements by Michael Barton <michael.barton asu.edu>
@author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
+ at author Stepan Turek <stepan.turek seznam.cz> (ManageSettingsWidget - created from GdalSelect)
"""
import os
@@ -48,12 +50,17 @@
import wx.lib.customtreectrl as CT
from core import globalvar
+from core.gcmd import GMessage
from core.debug import Debug
from core.events import gShowNotification
from wx.lib.newevent import NewEvent
wxSymbolSelectionChanged, EVT_SYMBOL_SELECTION_CHANGED = NewEvent()
+# ManageSettingsWidget
+wxOnSettingsLoaded, EVT_SETTINGS_LOADED = NewEvent()
+wxOnSettingsChanged, EVT_SETTINGS_CHANGED = NewEvent()
+wxOnSettingsSaving, EVT_SETTINGS_SAVING = NewEvent()
class NotebookController:
"""!Provides handling of notebook page names.
@@ -874,3 +881,299 @@
self.search.SetValue('')
if self.showTip:
self.searchTip.SetLabel('')
+
+class ManageSettingsWidget(wx.Panel):
+ """!Widget which allows loading and saving settings into file."""
+ def __init__(self, parent, settingsFile, id = wx.ID_ANY):
+ """
+ Events:
+ EVT_SETTINGS_CHANGED - called when users changes setting
+ - event object has attribute 'data', with chosen setting data
+ EVT_SETTINGS_SAVING - called when settings are saving
+ - If you bind instance of ManageSettingsWidget with this event,
+ you can use SetDataToSave method to set data for save and then call
+ Skip() to save the data.
+ If you do not call Skip(), the data will not be saved.
+ EVT_SETTINGS_LOADED - called when settings are loaded
+ - event object has attribute 'settings', which is dict with loaded settings
+ {nameofsetting : settingdata, ....}
+
+ @param settingsFile - path to file, where settings will be saved and loaded from
+ """
+ self.settingsFile = settingsFile
+
+ wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
+
+ self.settingsBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label = " %s " % _("Settings"))
+
+ self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
+ self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsChanged)
+ self.btnSettingsSave = wx.Button(parent = self, id = wx.ID_SAVE)
+ self.btnSettingsSave.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
+ self.btnSettingsSave.SetToolTipString(_("Save current settings"))
+ self.btnSettingsDel = wx.Button(parent = self, id = wx.ID_REMOVE)
+ self.btnSettingsDel.Bind(wx.EVT_BUTTON, self.OnSettingsDelete)
+ self.btnSettingsSave.SetToolTipString(_("Delete currently selected settings"))
+
+ self.Bind(EVT_SETTINGS_SAVING, self.OnSettingsSaving)
+
+ # escaping with '$' character - index in self.esc_chars
+ self.e_char_i = 0
+ self.esc_chars = ['$', ';']
+
+ self._settings = self._loadSettings() # -> self.settingsChoice.SetItems()
+ event = wxOnSettingsLoaded(settings = self._settings)
+ wx.PostEvent(self, event)
+
+ self.data_to_save = []
+
+ self._layout()
+
+ def _layout(self):
+
+ settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
+ settingsSizer.Add(item = wx.StaticText(parent = self,
+ id = wx.ID_ANY,
+ label = _("Load settings:")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
+ border = 5)
+ settingsSizer.Add(item = self.settingsChoice,
+ proportion = 1,
+ flag = wx.EXPAND)
+ settingsSizer.Add(item = self.btnSettingsSave,
+ flag = wx.LEFT | wx.RIGHT,
+ border = 5)
+ settingsSizer.Add(item = self.btnSettingsDel,
+ flag = wx.RIGHT,
+ border = 5)
+
+ self.SetSizer(settingsSizer)
+ settingsSizer.Fit(self)
+
+ def OnSettingsChanged(self, event):
+ """!Load named settings"""
+ name = event.GetString()
+ if name not in self._settings:
+ GError(parent = self,
+ message = _("Settings <%s> not found") % name)
+ return
+
+ data = self._settings[name]
+ event = wxOnSettingsChanged(data = data)
+ wx.PostEvent(self, event)
+
+ def OnSettingsSave(self, event):
+ """!Save settings"""
+ dlg = wx.TextEntryDialog(parent = self,
+ message = _("Name:"),
+ caption = _("Save settings"))
+ if dlg.ShowModal() != wx.ID_OK:
+ return
+
+ # check required params
+ if not dlg.GetValue():
+ GMessage(parent = self,
+ message = _("Name not given, settings is not saved."))
+ return
+
+ name = dlg.GetValue()
+
+ event = wxOnSettingsSaving(name = name, dlg = dlg)
+ wx.PostEvent(self, event)
+
+ def OnSettingsSaving(self, event):
+ # check if settings item already exists
+ if event.name in self._settings:
+ dlgOwt = wx.MessageDialog(self, message = _("Settings <%s> already exists. "
+ "Do you want to overwrite the settings?") % event.name,
+ caption = _("Save settings"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlgOwt.ShowModal() != wx.ID_YES:
+ dlgOwt.Destroy()
+ return
+
+ if self.data_to_save:
+ self._settings[event.name] = self.data_to_save
+
+ self.SaveSettings()
+ self.settingsChoice.SetStringSelection(event.name)
+
+ self.data_to_save = []
+ event.dlg.Destroy()
+
+ def SaveSettings(self):
+ """!Save settings"""
+ if self._saveSettings() == 0:
+ self._settings = self._loadSettings()
+
+ def SetDataToSave(self, data):
+ """!Set data for setting, which will be saved.
+
+ @param data - list of strings, which will be saved
+ """
+ self.data_to_save = data
+
+ def SetSettings(self, settings):
+ """!Set settings
+
+ @param settings - dict with all settigs {nameofsetting : settingdata, ....}
+ """
+ self._settings = settings
+ self.SaveSettings()
+
+ def OnSettingsDelete(self, event):
+ """!Save settings
+ """
+ name = self.settingsChoice.GetStringSelection()
+ if not name:
+ GMessage(parent = self,
+ message = _("No settings is defined. Operation canceled."))
+ return
+
+ self._settings.pop(name)
+ if self._saveSettings() == 0:
+ self._settings = self._loadSettings()
+
+ def _saveSettings(self):
+ """!Save settings into the file
+
+ @return 0 on success
+ @return -1 on failure
+ """
+ try:
+ fd = open(self.settingsFile, 'w')
+ fd.write('format_version=2.0\n')
+ for key, values in self._settings.iteritems():
+ first = True
+ for v in values:
+ # escaping characters
+ for e_ch in self.esc_chars:
+ v = v.replace(e_ch, self.esc_chars[self.e_char_i] + e_ch)
+ if first:
+ # escaping characters
+ for e_ch in self.esc_chars:
+ key = key.replace(e_ch, self.esc_chars[self.e_char_i] + e_ch)
+ fd.write('%s;%s;' % (key, v))
+ first = False
+ else:
+ fd.write('%s;' % (v))
+ fd.write('\n')
+
+ except IOError:
+ GError(parent = self,
+ message = _("Unable to save settings"))
+ return -1
+ fd.close()
+
+ return 0
+
+ def _loadSettings(self):
+ """!Load settings from the file
+
+ The file is defined by self.SettingsFile.
+
+ @return parsed dict
+ @return empty dict on error
+ """
+
+ data = dict()
+ if not os.path.exists(self.settingsFile):
+ return data
+
+ try:
+ fd = open(self.settingsFile, 'r')
+ except IOError:
+ return data
+
+ fd_lines = fd.readlines()
+
+ if not fd_lines:
+ fd.close()
+ return data
+
+ if fd_lines[0].strip() == 'format_version=2.0':
+ data = self._loadSettings_v2(fd_lines)
+ else:
+ data = self._loadSettings_v1(fd_lines)
+
+ self.settingsChoice.SetItems(sorted(data.keys()))
+ fd.close()
+
+ event = wxOnSettingsLoaded(settings = data)
+ wx.PostEvent(self, event)
+
+ return data
+
+ def _loadSettings_v2(self, fd_lines):
+ """Load settings from the file in format version 2.0
+
+ The file is defined by self.SettingsFile.
+
+ @return parsed dict
+ @return empty dict on error
+ """
+ data = dict()
+
+ for line in fd_lines[1:]:
+ try:
+ lineData = []
+ line = line.rstrip('\n')
+ i_last_found = i_last = 0
+ key = ''
+ while True:
+ idx = line.find(';', i_last)
+ if idx < 0:
+ break
+ elif idx != 0:
+
+ # find out whether it is separator
+ # $$$$; - it is separator
+ # $$$$$; - it is not separator
+ i_esc_chars = 0
+ while True:
+ if line[idx - (i_esc_chars + 1)] == self.esc_chars[self.e_char_i]:
+ i_esc_chars += 1
+ else:
+ break
+ if i_esc_chars%2 != 0:
+ i_last = idx + 1
+ continue
+
+ lineItem = line[i_last_found : idx]
+ # unescape characters
+ for e_ch in self.esc_chars:
+ lineItem = lineItem.replace(self.esc_chars[self.e_char_i] + e_ch, e_ch)
+ if i_last_found == 0:
+ key = lineItem
+ else:
+ lineData.append(lineItem)
+ i_last_found = i_last = idx + 1
+ if key and lineData:
+ data[key] = lineData
+ except ValueError:
+ pass
+
+ return data
+
+ def _loadSettings_v1(self, fd_lines):
+ """!Load settings from the file in format version 1.0 (backward compatibility)
+
+ The file is defined by self.SettingsFile.
+
+ @return parsed dict
+ @return empty dict on error
+ """
+ data = dict()
+
+ for line in fd_lines:
+ try:
+ lineData = line.rstrip('\n').split(';')
+ if len(lineData) > 4:
+ # type, dsn, format, options
+ data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
+ else:
+ data[lineData[0]] = (lineData[1], lineData[2], lineData[3], '')
+ except ValueError:
+ pass
+
+ return data
Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/lmgr/frame.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -992,9 +992,7 @@
(None, None),
('vectImport', self.OnImportOgrLayers),
('vectLink', self.OnLinkOgrLayers),
- ('vectOut', self.OnVectorOutputFormat),
- (None, None),
- ('wmsImport', self.OnImportWMS)))
+ ('vectOut', self.OnVectorOutputFormat)))
def OnWorkspaceNew(self, event = None):
"""!Create new workspace file
@@ -1509,37 +1507,13 @@
dlg.CentreOnScreen()
dlg.Show()
- def OnImportWMS(self, event, cmd = None):
- """!Import data from OGC WMS server"""
- from ogc_services.wms import WMSDialog
- dlg = WMSDialog(parent = self)
- dlg.CenterOnScreen()
- if dlg.ShowModal() == wx.ID_OK: # -> import layers
- layers = dlg.GetLayers()
-
- if len(layers.keys()) > 0:
- for layer in layers.keys():
- cmd = ['r.in.wms',
- 'mapserver=%s' % dlg.GetSettings()['server'],
- 'layers=%s' % layer,
- 'output=%s' % layer,
- 'format=png',
- '--overwrite']
- styles = ','.join(layers[layer])
- if styles:
- cmd.append('styles=%s' % styles)
- self._gconsole.RunCmd(cmd, switchPage = True)
+ def OnAddWS(self, event, cmd = None):
+ """!Add web services layer"""
+ from web_services.dialogs import AddWSDialog
+ dlg = AddWSDialog(parent = self, gmframe = self)
+ dlg.CentreOnScreen()
+ dlg.Show()
- self.GetLayerTree().AddLayer(ltype = 'raster',
- lname = layer,
- lcmd = ['d.rast', 'map=%s' % layer],
- multiple = False)
- else:
- self._gconsole.WriteWarning(_("Nothing to import. No WMS layer selected."))
-
-
- dlg.Destroy()
-
def OnShowAttributeTable(self, event, selection = None):
"""!Show attribute table of the given vector map layer
"""
Modified: grass/trunk/gui/wxpython/lmgr/layertree.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/layertree.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/lmgr/layertree.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -29,22 +29,24 @@
from grass.script import core as grass
-from core import globalvar
-from gui_core.dialogs import SqlQueryFrame, SetOpacityDialog, EVT_APPLY_OPACITY
-from gui_core.forms import GUI
-from mapdisp.frame import MapFrame
-from core.render import Map
-from modules.histogram import HistogramFrame
-from core.utils import GetLayerNameFromCmd
-from wxplot.profile import ProfileFrame
-from core.debug import Debug
-from core.settings import UserSettings, GetDisplayVectSettings
-from vdigit.main import haveVDigit
-from core.gcmd import GWarning, GError
-from gui_core.toolbars import BaseIcons
-from icons.icon import MetaIcon
-from modules.colorrules import RasterColorTable
+from core import globalvar
+from gui_core.dialogs import SqlQueryFrame, SetOpacityDialog, EVT_APPLY_OPACITY
+from gui_core.forms import GUI
+from mapdisp.frame import MapFrame
+from core.render import Map
+from modules.histogram import HistogramFrame
+from core.utils import GetLayerNameFromCmd
+from wxplot.profile import ProfileFrame
+from core.debug import Debug
+from core.settings import UserSettings, GetDisplayVectSettings
+from vdigit.main import haveVDigit
+from core.gcmd import GWarning, GError
+from gui_core.toolbars import BaseIcons
+from icons.icon import MetaIcon
+from modules.colorrules import RasterColorTable
+from web_services.dialogs import SaveWMSLayerDialog
+
TREE_ITEM_HEIGHT = 25
LMIcons = {
@@ -391,7 +393,7 @@
if not hasattr (self, "popupID"):
self.popupID = dict()
for key in ('remove', 'rename', 'opacity', 'nviz', 'zoom',
- 'region', 'export', 'attr', 'edit0', 'edit1',
+ 'region', 'export', 'attr', 'edit0', 'edit1', 'save_ws',
'bgmap', 'topo', 'meta', 'null', 'zoom1', 'region1',
'color', 'hist', 'univar', 'prof', 'properties', 'sql'):
self.popupID[key] = wx.NewId()
@@ -532,9 +534,21 @@
self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
+ # web service layers (specific item)
+ elif mltype and mltype == "wms":
+ self.popupMenu.Append(self.popupID['save_ws'], text = _("Save web service layer"))
+ self.Bind(wx.EVT_MENU, self.OnSaveWs, id = self.popupID['save_ws'])
+
self.PopupMenu(self.popupMenu)
self.popupMenu.Destroy()
+ def OnSaveWs(self, event):
+ """!Show dialog for saving web service layer into GRASS vector/raster layer"""
+ mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
+ dlg = SaveWMSLayerDialog(parent = self, layer = mapLayer, ltree = self)
+ dlg.CentreOnScreen()
+ dlg.Show()
+
def OnTopology(self, event):
"""!Rebuild topology of selected vector map"""
mapLayer = self.GetLayerInfo(self.layer_selected, key = 'maplayer')
@@ -1035,12 +1049,14 @@
def PropertiesDialog(self, layer, show = True):
"""!Launch the properties dialog"""
+ ltype = self.GetLayerInfo(layer, key = 'type')
if 'propwin' in self.GetLayerInfo(layer) and \
self.GetLayerInfo(layer, key = 'propwin') is not None:
# recycle GUI dialogs
win = self.GetLayerInfo(layer, key = 'propwin')
- # update properties (columns, layers)
- win.notebookpanel.OnUpdateSelection(None)
+ if ltype != 'wms':
+ # update properties (columns, layers)
+ win.notebookpanel.OnUpdateSelection(None)
if win.IsShown():
win.SetFocus()
else:
@@ -1049,13 +1065,13 @@
return
params = self.GetLayerParams(layer)
- ltype = self.GetLayerInfo(layer, key = 'type')
Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
ltype)
cmd = None
if self.GetLayerInfo(layer, key = 'cmd'):
+
module = GUI(parent = self, show = show, centreOnParent = False)
module.ParseCommand(self.GetLayerInfo(layer, key = 'cmd'),
completed = (self.GetOptData,layer,params))
Modified: grass/trunk/gui/wxpython/lmgr/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/toolbars.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/lmgr/toolbars.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -85,6 +85,8 @@
'addVect' : BaseIcons['addVect'].SetLabel(_("Add vector map layer (Ctrl+Shift+V)")),
'vectMisc' : MetaIcon(img = 'layer-vector-more',
label = _('Add various vector map layers (thematic, chart...)')),
+ 'addWS' : MetaIcon(img = 'layer-wms-add',
+ label = _('Add web service layer (WMS, WMTS, NASA OnEarth)')),
'addGroup' : MetaIcon(img = 'layer-group-add',
label = _('Add group')),
'addOverlay' : MetaIcon(img = 'layer-more',
@@ -107,6 +109,9 @@
self.parent.OnAddGroup),
('addovl', icons["addOverlay"],
self.parent.OnAddOverlay),
+ ('addWS', icons["addWS"],
+ self.parent.OnAddWS),
+ (None, ),
('delcmd', icons["delCmd"],
self.parent.OnDeleteLayer),
))
Modified: grass/trunk/gui/wxpython/mapdisp/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/mapwindow.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/mapdisp/mapwindow.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -34,8 +34,11 @@
from core.gcmd import RunCommand, GException, GError, GMessage
from core.debug import Debug
from core.settings import UserSettings
-from core.events import gZoomChanged
+from core.events import gZoomChanged, EVT_UPDATE_MAP
from gui_core.mapwindow import MapWindow
+from core.render import EVT_UPDATE_PRGBAR
+from core.utils import GetGEventAttribsForHandler
+
try:
import grass.lib.gis as gislib
haveCtypes = True
@@ -76,9 +79,13 @@
self.plineid = None
# event bindings
- self.Bind(wx.EVT_PAINT, self.OnPaint)
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_IDLE, self.OnIdle)
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+ self.Bind(EVT_UPDATE_MAP, self.OnUpdateMap)
+ if self.frame and hasattr(self.frame, 'OnUpdateProgress'):
+ self.Bind(EVT_UPDATE_PRGBAR, self.frame.OnUpdateProgress)
+
self._bindMouseEvents()
self.processMouse = True
@@ -571,10 +578,26 @@
def IsAlwaysRenderEnabled(self):
return self.alwaysRender
+ def OnUpdateMap(self, event):
+ """!Called when this class receives core.events.gUpdateMap event.
+ """
+ kwargs, missing_args = GetGEventAttribsForHandler(self.UpdateMap, event)
+
+ if missing_args:
+ Debug.msg (1, "Invalid call of EVT_UPDATE_MAP event.")
+ return
+
+ self.UpdateMap(self, **kwargs)
+
def UpdateMap(self, render = True, renderVector = True):
"""!Updates the canvas anytime there is a change to the
underlaying images or to the geometry of the canvas.
+ This method should not be called directly.
+ Post core.events.gUpdateMap event to instance of this class.
+
+ @todo change direct calling of UpdateMap method to posting core.events.gUpdateMap
+
@param render re-render map composition
@param renderVector re-render vector map layer enabled for editing (used for digitizer)
"""
@@ -606,10 +629,10 @@
else:
windres = False
- self.mapfile = self.Map.Render(force = True, mapWindow = self.frame,
+ self.mapfile = self.Map.Render(force = True,
windres = windres)
else:
- self.mapfile = self.Map.Render(force = False, mapWindow = self.frame)
+ self.mapfile = self.Map.Render(force = False)
except GException, e:
GError(message = e.value)
@@ -759,9 +782,8 @@
self.Draw(self.pdcDec, pdctype = 'clear')
self.Draw(self.pdcTmp, pdctype = 'clear')
- for layer in self.Map.GetListOfLayers(active = True):
- layer.AbortDownload()
-
+ self.Map.AbortAllThreads()
+
def DragMap(self, moveto):
"""!Drag the entire map image for panning.
Modified: grass/trunk/gui/wxpython/ogc_services/wms.py
===================================================================
--- grass/trunk/gui/wxpython/ogc_services/wms.py 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/ogc_services/wms.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -1,300 +0,0 @@
-"""!
- at package module.ogc_services
-
- at brief Dialogs for OGC services
-
-Currently only implemeted WMS.
-
-List of classes:
- - ogc_services::WMSDialog
- - ogc_services::LayersList
-
-(C) 2009-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import wx
-from wx.gizmos import TreeListCtrl
-import wx.lib.mixins.listctrl as listmix
-
-from core.gcmd import RunCommand
-from core.settings import UserSettings
-
-class WMSDialog(wx.Dialog):
- def __init__(self, parent, service = 'wms',
- id=wx.ID_ANY,
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
- """!Dialog to import data from WMS server"""
- self.parent = parent # GMFrame
- self.service = service # currently only WMS is implemented
-
- wx.Dialog.__init__(self, parent, id, style=style)
- if self.service == 'wms':
- self.SetTitle(_("Import data from WMS server"))
-
- self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
- self.__createWidgets()
-
- self.__doLayout()
-
- self.SetMinSize((550, 400))
-
- def __createWidgets(self):
- """!Create dialog widgets"""
- #
- # settings
- #
- self.settingsBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label = _(" Server settings "))
-
- self.serverText = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = _("Server:"))
- self.server = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
-
- #
- # list of layers
- #
- self.layersBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label=_(" List of layers "))
-
- self.list = LayersList(self.panel)
- self.list.LoadData()
-
- self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
- label=_("Add imported layers into layer tree"))
- self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
-
- #
- # buttons
- #
- # cancel
- self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
- self.btn_cancel.SetToolTipString(_("Close dialog"))
- # connect
- self.btn_connect = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Connect"))
- self.btn_connect.SetToolTipString(_("Connect to the server"))
- self.btn_connect.SetDefault()
- if not self.server.GetValue():
- self.btn_connect.Enable(False)
- # import
- self.btn_import = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
- self.btn_import.SetToolTipString(_("Import selected layers"))
- self.btn_import.Enable(False)
-
- #
- # bindings
- #
- self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
- self.btn_connect.Bind(wx.EVT_BUTTON, self.OnConnect)
- self.server.Bind(wx.EVT_TEXT, self.OnServer)
-
- def __doLayout(self):
- """!Do dialog layout"""
- dialogSizer = wx.BoxSizer(wx.VERTICAL)
-
- #
- # settings
- #
- settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
-
- gridSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
-
- gridSizer.Add(item=self.serverText,
- flag=wx.ALIGN_CENTER_VERTICAL)
- gridSizer.AddGrowableCol(1)
- gridSizer.Add(item=self.server,
- flag=wx.EXPAND | wx.ALL)
-
- settingsSizer.Add(item=gridSizer, proportion=1,
- flag=wx.EXPAND | wx.ALL)
-
- dialogSizer.Add(item=settingsSizer, proportion=0,
- flag=wx.ALL | wx.EXPAND, border=5)
-
- #
- # list of layers
- #
- layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)
-
- layersSizer.Add(item=self.list, proportion=1,
- flag=wx.ALL | wx.EXPAND, border=5)
-
- dialogSizer.Add(item=layersSizer, proportion=1,
- flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-
- dialogSizer.Add(item=self.add, proportion=0,
- flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-
- #
- # buttons
- #
- btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL)
-
- btnsizer.Add(item=self.btn_cancel, proportion=0,
- flag=wx.ALL | wx.ALIGN_CENTER,
- border=10)
-
- btnsizer.Add(item=self.btn_connect, proportion=0,
- flag=wx.ALL | wx.ALIGN_CENTER,
- border=10)
-
- btnsizer.Add(item=self.btn_import, proportion=0,
- flag=wx.ALL | wx.ALIGN_CENTER,
- border=10)
-
- dialogSizer.Add(item=btnsizer, proportion=0,
- flag=wx.ALIGN_CENTER)
-
- self.panel.SetAutoLayout(True)
- self.panel.SetSizer(dialogSizer)
- dialogSizer.Fit(self.panel)
- self.Layout()
-
- def OnCancel(self, event):
- """!Button 'Cancel' pressed -> close the dialog"""
- self.Close()
-
- def OnConnect(self, event):
- """!Button 'Connect' pressed"""
- server = self.server.GetValue()
- if not server:
- self.btn_import.Enable(False)
- return # not reachable
-
- layers = {}
- ret = RunCommand('r.in.wms',
- quiet = True,
- parent = self,
- read = True,
- flags = 'l',
- mapserver = server)
-
- if not ret:
- self.list.LoadData()
- self.btn_import.Enable(False)
- return # no layers found
-
- lastLayer = lastStyle = ''
- for line in ret.splitlines():
- try:
- key, value = line.split(':', 1)
- except ValueError:
- continue
- key = key.strip().lower()
- value = value.strip()
-
- if key == 'layer':
- layers[value] = {}
- lastLayer = value
- elif key == 'title':
- layers[lastLayer][key] = value
- elif key == 'style':
- if 'style' not in layers[lastLayer]:
- layers[lastLayer]['style'] = {}
- layers[lastLayer]['style'][value] = ''
- lastStyle = value
- elif key == 'style title':
- layers[lastLayer]['style'][lastStyle] = value
-
- # update list of layers
- self.list.LoadData(layers)
-
- if len(layers.keys()) > 0:
- self.btn_import.Enable(True)
- else:
- self.btn_import.Enable(False)
-
- def OnServer(self, event):
- """!Server settings changed"""
- value = event.GetString()
- if value:
- self.btn_connect.Enable(True)
- else:
- self.btn_connect.Enable(False)
-
- def GetLayers(self):
- """!Get list of selected layers/styles to be imported"""
- return self.list.GetSelectedLayers()
-
- def GetSettings(self):
- """!Get connection settings"""
- return { 'server' : self.server.GetValue() }
-
-class LayersList(TreeListCtrl, listmix.ListCtrlAutoWidthMixin):
- def __init__(self, parent, pos=wx.DefaultPosition):
- """!List of layers to be imported (dxf, shp...)"""
- self.parent = parent
-
- TreeListCtrl.__init__(self, parent, wx.ID_ANY,
- style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT |
- wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_MULTIPLE)
-
- # setup mixins
- listmix.ListCtrlAutoWidthMixin.__init__(self)
-
- self.AddColumn(_('Layer / Style'))
- self.AddColumn(_('Title'))
- self.SetMainColumn(0) # column with the tree
- self.SetColumnWidth(0, 175)
-
- self.root = None
-
- def LoadData(self, data = {}):
- """!Load data into list"""
- # detete first all items
- self.DeleteAllItems()
- self.root = self.AddRoot(_("Layers"))
-
- layers = data.keys()
- if not layers:
- return
-
- layers.sort()
-
- for layer in layers:
- title = data[layer]['title']
- lchild = self.AppendItem(self.root, layer)
- self.SetItemText(lchild, title, 1)
- if 'style' in data[layer]:
- styles = data[layer]['style'].keys()
- if not styles:
- continue
- styles.sort()
- for style in styles:
- title = data[layer]['style'][style]
- schild = self.AppendItem(lchild, style)
- self.SetItemText(schild, title, 1)
-
- self.Expand(self.root)
-
- def GetItemCount(self):
- """!Required for listmix.ListCtrlAutoWidthMixin"""
- return 0
-
- def GetCountPerPage(self):
- """!Required for listmix.ListCtrlAutoWidthMixin"""
- return 0
-
- def GetSelectedLayers(self):
- """!Get selected layers/styles"""
- layers = dict()
-
- for item in self.GetSelections():
- parent = self.GetItemParent(item)
- if parent == self.root: # -> layer
- layer = self.GetItemText(item, 0)
- layers[layer] = list()
- sitem, cookie = self.GetFirstChild(item)
- while sitem:
- layers[layer].append(self.GetItemText(sitem, 0))
- sitem, cookie = self.GetNextChild(item, cookie)
- else: # -> style
- layer = self.GetItemText(parent, 0)
- layers[layer] = list()
- layers[layer].append(self.GetItemText(item, 0))
-
- return layers
Added: grass/trunk/gui/wxpython/web_services/cap_interface.py
===================================================================
--- grass/trunk/gui/wxpython/web_services/cap_interface.py (rev 0)
+++ grass/trunk/gui/wxpython/web_services/cap_interface.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -0,0 +1,397 @@
+"""!
+ at package web_services.cap_interface
+
+ at brief Provides common interface for GUI web_services.widgets to capabilities data of web services.
+
+List of classes:
+ - cap_interface::CapabilitiesBase
+ - cap_interface::LayerBase
+ - cap_interface::WMSCapabilities
+ - cap_interface::WMSLayer
+ - cap_interface::WMTSCapabilities
+ - cap_interface::WMTSLayer
+ - cap_interface::OnEarthCapabilities
+ - cap_interface::OnEarthLayer
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
+"""
+
+import os
+import sys
+
+WMSLibPath = os.path.join(os.getenv("GISBASE"), "etc", "r.in.wms")
+sys.path.append(WMSLibPath)
+
+from wms_cap_parsers import WMSCapabilitiesTree, \
+ WMTSCapabilitiesTree, \
+ OnEarthCapabilitiesTree
+
+class CapabilitiesBase:
+ def GetLayerByName(self, name):
+ """!Find layer by name
+ """
+ for l in self.layers_by_id:
+ if name == l.GetLayerData('name'):
+ return l
+ return None
+
+ def GetRootLayer(self):
+ """!Get children layers
+ """
+ if self.layers_by_id:
+ return self.layers_by_id[0]
+ else:
+ return None
+
+class LayerBase:
+ def GetId(self):
+ """!Get layer id
+ """
+ return self.id
+
+ def GetChildren(self):
+ """!Get children layers
+ """
+ return self.child_layers
+
+ def GetLayerNode(self):
+ """!Get layer node
+ """
+ return self.layer_node
+
+ def AddChildLayer(self, layer):
+ """!Add child layer
+ """
+ self.child_layers.append(layer)
+
+class WMSCapabilities(CapabilitiesBase, WMSCapabilitiesTree):
+ def __init__(self, cap_file, force_version = None):
+ """!Create common interface for web_services.widgets to WMS capabilities data
+ """
+ # checks all elements needed for creation of GetMap requests
+ # by r.in.wms/d.wms modules, invalid elements are removed
+ WMSCapabilitiesTree.__init__(self, cap_file, force_version)
+
+ self.cap_node = self.getroot().find(self.xml_ns.Ns("Capability"))
+ self.root_layer = self.cap_node.find(self.xml_ns.Ns("Layer"))
+
+ self.layers_by_id = {}
+ self._initializeLayerTree(self.root_layer)
+
+ def _initializeLayerTree(self, parent_layer, id = 0):
+ """!Build tree, which represents layers
+ """
+ if id == 0:
+ parent_layer = WMSLayer(parent_layer, id, self)
+ self.layers_by_id[id] = parent_layer
+ id += 1
+
+ layer_nodes = parent_layer.GetLayerNode().findall((self.xml_ns.Ns("Layer")))
+
+ for l in layer_nodes:
+ layer = WMSLayer(l, id, self)
+ parent_layer.AddChildLayer(layer)
+ self.layers_by_id[id] = layer
+ id += 1
+ id = self._initializeLayerTree(layer, id)
+
+ return id
+
+ def GetFormats(self):
+ """!Get supported formats
+ """
+ request_node = self.cap_node.find(self.xml_ns.Ns("Request"))
+ get_map_node = request_node.find(self.xml_ns.Ns("GetMap"))
+ format_nodes = get_map_node.findall(self.xml_ns.Ns("Format"))
+
+ formats = []
+ for node in format_nodes:
+ formats.append(node.text)
+
+ return formats
+
+class WMSLayer(LayerBase):
+ def __init__(self, layer_node, id, cap):
+ """!Common interface for web_services.widgets to WMS capabilities <Layer> element
+ """
+ self.id = id
+ self.cap = cap
+ self.child_layers = []
+ self.layer_node = layer_node
+ self.xml_ns = self.cap.getxmlnshandler()
+
+ def GetLayerData(self, param):
+ """!Get layer data"""
+ title = self.xml_ns.Ns("Title")
+ name = self.xml_ns.Ns("Name")
+
+ if param == 'title':
+ title_node = self.layer_node.find(title)
+ if title_node is not None:
+ return title_node.text
+ else:
+ return None
+
+ if param == 'name':
+ name_node = self.layer_node.find(name)
+ if name_node is not None:
+ return name_node.text
+ else:
+ return None
+
+ if param == 'format':
+ return self.cap.GetFormats()
+
+ if param == 'styles':
+ styles = []
+ style = self.xml_ns.Ns("Style")
+ for style_node in self.layer_node.findall(style):
+ style_name = ''
+ style_title = ''
+
+ if style_node.find(title) is not None:
+ style_title = style_node.find(title).text
+ if style_node.find(name) is not None:
+ style_name = style_node.find(name).text
+
+ styles.append({'title' : style_title,
+ 'name' : style_name,
+ 'isDefault' : False})
+ return styles
+
+ if param == 'srs':
+ projs_nodes = self.layer_node.findall(self.xml_ns.Ns(self.cap.getprojtag()))
+
+ projs = []
+ if projs_nodes is None:
+ return projs
+ for p in projs_nodes:
+ projs.append(p.text.strip())
+ return projs
+
+ def IsRequestable(self):
+ """!Is it possible to use the layer for WMS GetMap request?
+ """
+ name = self.xml_ns.Ns("Name")
+ name_node = self.layer_node.find(name)
+
+ if name_node is not None:
+ return True
+ else:
+ return False
+
+class WMTSCapabilities(CapabilitiesBase, WMTSCapabilitiesTree):
+ def __init__(self, cap_file):
+ """!Create common interface for web_services.widgets to WMTS capabilities data
+ """
+ # checks all elements needed for creation of GetTile requests
+ # by r.in.wms/d.wms modules, invalid elements are removed
+ WMTSCapabilitiesTree.__init__(self, cap_file)
+
+ contents = self._find(self.getroot(), 'Contents', self.xml_ns.NsWmts)
+ layers = self._findall(contents, 'Layer', self.xml_ns.NsWmts)
+
+ self.layers_by_id = {}
+
+ id = 0
+ root_layer = WMTSLayer(None, id, self)
+ self.layers_by_id[id] = root_layer
+
+ for layer_node in layers:
+ id += 1
+ self.layers_by_id[id] = WMTSLayer(layer_node, id, self)
+ root_layer.child_layers.append(self.layers_by_id[id])
+
+class WMTSLayer(LayerBase):
+ def __init__(self, layer_node, id, cap):
+ """!Common interface for web_services.widgets to WMTS capabilities <Layer> element
+ """
+ self.id = id
+ self.cap = cap
+ self.child_layers = []
+ self.layer_node = layer_node
+ self.xml_ns = self.cap.getxmlnshandler()
+ self.projs = self._getProjs()
+
+ def GetLayerData(self, param):
+ """!Get layer data
+ """
+ title = self.xml_ns.NsOws("Title")
+ name = self.xml_ns.NsOws("Identifier")
+
+ if self.layer_node is None and param in ['title', 'name']:
+ return None
+ elif self.layer_node is None:
+ return []
+
+ if param == 'title':
+ title_node = self.layer_node.find(title)
+ if title_node is not None:
+ return title_node.text
+ else:
+ return None
+
+ if param == 'name':
+ name_node = self.layer_node.find(name)
+ if name_node is not None:
+ return name_node.text
+ else:
+ return None
+
+ if param == 'styles':
+ styles = []
+ for style_node in self.layer_node.findall(self.xml_ns.NsWmts("Style")):
+
+ style_name = ''
+ style_title = ''
+
+ if style_node.find(title) is not None:
+ style_title = style_node.find(title).text
+ if style_node.find(name) is not None:
+ style_name = style_node.find(name).text
+
+ is_def = False
+ if 'isDefault' in style_node.attrib and\
+ style_node.attrib['isDefault'] == 'true':
+ is_def = True
+
+ styles.append({'title' : style_title,
+ 'name' : style_name,
+ 'isDefault' : is_def})
+
+ return styles
+
+ if param == 'format':
+ formats = []
+ for frmt in self.layer_node.findall(self.xml_ns.NsWmts('Format')):
+ formats.append(frmt.text.strip())
+ return formats
+
+ if param == 'srs':
+ return self.projs
+
+ def _getProjs(self):
+ """!Get layer projections
+ """
+ layer_projs = []
+ if self.layer_node is None:
+ return layer_projs
+
+ mat_set_links = self.layer_node.findall(self.xml_ns.NsWmts('TileMatrixSetLink'))
+
+ contents = self.cap.getroot().find(self.xml_ns.NsWmts('Contents'))
+ tileMatrixSets = contents.findall(self.xml_ns.NsWmts('TileMatrixSet'))
+
+ for link in mat_set_links:
+ mat_set_link_id = link.find(self.xml_ns.NsWmts('TileMatrixSet')).text
+ if not mat_set_link_id:
+ continue
+
+ for mat_set in tileMatrixSets:
+ mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier')).text
+ if mat_set_id and mat_set_id != mat_set_link_id:
+ continue
+ mat_set_srs = mat_set.find(self.xml_ns.NsOws('SupportedCRS')).text.strip()
+ layer_projs.append(mat_set_srs)
+ return layer_projs
+
+ def IsRequestable(self):
+ """!Is it possible to use the layer for WMTS request?
+ """
+ if self.layer_node is None:
+ return False
+ else:
+ return True
+
+class OnEarthCapabilities(CapabilitiesBase, OnEarthCapabilitiesTree):
+ def __init__(self, cap_file):
+ """!Create Common interface for web_services.widgets to NASA OnEarth
+ tile service data (equivalent to WMS, WMTS capabilities data)
+ """
+ # checks all elements needed for creation of GetMap requests
+ # by r.in.wms/d.wms modules, invalid elements are removed
+ OnEarthCapabilitiesTree.__init__(self, cap_file)
+
+ self.layers_by_id = {}
+ self._initializeLayerTree(self.getroot())
+
+ def _initializeLayerTree(self, parent_layer, id = 0):
+ """!Build tree, which represents layers
+ """
+ if id == 0:
+ tiled_patterns = parent_layer.find('TiledPatterns')
+ layer_nodes = tiled_patterns.findall('TiledGroup')
+ layer_nodes += tiled_patterns.findall('TiledGroups')
+ parent_layer = OnEarthLayer(None, None, id, self)
+ self.layers_by_id[id] = parent_layer
+ id += 1
+ else:
+ layer_nodes = parent_layer.layer_node.findall('TiledGroup')
+ layer_nodes += parent_layer.layer_node.findall('TiledGroups')
+
+ for layer_node in layer_nodes:
+ layer = OnEarthLayer(layer_node, parent_layer, id, self)
+ self.layers_by_id[id] = layer
+ id += 1
+ parent_layer.child_layers.append(layer)
+ if layer_node.tag == 'TiledGroups':
+ id = self._initializeLayerTree(layer, id)
+
+ return id
+
+class OnEarthLayer(LayerBase):
+ def __init__(self, layer_node, parent_layer, id, cap):
+ """!Common interface for web_services.widgets to NASA Earth
+ capabilities <TiledGroup>\<TiledGroups> element
+ (equivalent to WMS, WMTS <Layer> element)
+ """
+ self.id = id
+ self.cap = cap
+ self.layer_node = layer_node
+ self.child_layers = []
+ self.parent_layer = parent_layer
+
+ def IsRequestable(self):
+ """!Is it possible to use the layer for NASA OnEarth GetMap request?
+ """
+ if self.layer_node is None or \
+ self.layer_node.tag == 'TiledGroups':
+ return False
+ else:
+ return True
+
+ def GetLayerData(self, param):
+ """!Get layer data
+ """
+ if self.layer_node is None and param in ['title', 'name']:
+ return None
+ elif self.layer_node is None:
+ return []
+
+ if param == 'title':
+ title_node = self.layer_node.find("Title")
+ if title_node is not None:
+ return title_node.text
+ else:
+ return None
+
+ if param == 'name':
+ name_node = self.layer_node.find("Name")
+ if name_node is not None:
+ return name_node.text
+ else:
+ return None
+
+ if param == 'styles':
+ return []
+
+ if param == 'format':
+ return []
+
+ if param == 'srs':
+ return []
Copied: grass/trunk/gui/wxpython/web_services/dialogs.py (from rev 54605, grass/trunk/gui/wxpython/ogc_services/wms.py)
===================================================================
--- grass/trunk/gui/wxpython/web_services/dialogs.py (rev 0)
+++ grass/trunk/gui/wxpython/web_services/dialogs.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -0,0 +1,972 @@
+"""!
+ at package web_services.dialogs
+
+ at brief Dialogs for web services.
+
+List of classes:
+ - dialogs::WSDialogBase
+ - dialogs::AddWSDialog
+ - dialogs::WSPropertiesDialog
+ - dialogs::SaveWMSLayerDialog
+
+(C) 2009-2013 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Stepan Turek <stepan.turek seznam.cz>
+"""
+
+import wx
+
+import os
+import sys
+import shutil
+
+from copy import deepcopy
+
+import grass.script as grass
+
+from core import globalvar
+from core.debug import Debug
+from core.ws import RenderWMSMgr
+from core.events import gUpdateMap
+from core.gcmd import GMessage, RunCommand, GWarning
+from core.utils import GetSettingsPath, CmdToTuple, CmdTupleToList
+from core.gconsole import CmdThread, GStderr, EVT_CMD_DONE, EVT_CMD_OUTPUT
+
+from gui_core.gselect import Select
+from gui_core.widgets import ManageSettingsWidget,\
+ EVT_SETTINGS_CHANGED, EVT_SETTINGS_SAVING, EVT_SETTINGS_LOADED
+
+from web_services.widgets import WSPanel, EVT_CAP_PARSED
+
+class WSDialogBase(wx.Dialog):
+ """!Base class for web service dialogs.
+ """
+ def __init__(self, parent, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+
+ wx.Dialog.__init__(self, parent, id, style = style, **kwargs)
+
+ self.parent = parent
+
+ # contains panel for every web service on server
+ self.ws_panels = {'WMS_1.1.1' : {'panel' : None,
+ 'label' : 'WMS 1.1.1'},
+ 'WMS_1.3.0' : {'panel' : None,
+ 'label' : 'WMS 1.3.0'},
+ 'WMTS' : {'panel' : None,
+ 'label' : 'WMTS'},
+ 'OnEarth' : {'panel' : None,
+ 'label' : 'OnEarth'},
+ }
+
+ #TODO: should be in file
+ self.default_servers = { 'OSM-WMS-EUROPE' : ['http://129.206.228.72/cached/osm', '', ''],
+ 'irs.gis-lab.info (OSM)' : ['http://irs.gis-lab.info', '', ''],
+ 'NASA OnEarth' : ['http://onearth.jpl.nasa.gov/wms.cgi', '', '']
+ }
+
+ # holds reference to web service panel which is showed
+ self.active_ws_panel = None
+
+ # buttons which are disabled when the dialog is not connected
+ self.run_btns = []
+
+ self._createWidgets()
+ self._doLayout()
+
+ def _createWidgets(self):
+
+ settingsFile = os.path.join(GetSettingsPath(), 'wxWS')
+
+ self.settsManager = ManageSettingsWidget(parent = self,
+ id = wx.ID_ANY,
+ settingsFile = settingsFile)
+
+ self.settingsBox = wx.StaticBox(parent = self,
+ id = wx.ID_ANY,
+ label = _(" Server settings "))
+
+ self.serverText = wx.StaticText(parent = self,
+ id = wx.ID_ANY, label = _("Server:"))
+ self.server = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+
+ self.btn_connect = wx.Button(parent = self,
+ id = wx.ID_ANY, label = _("&Connect"))
+ self.btn_connect.SetToolTipString(_("Connect to the server"))
+ self.btn_connect.SetDefault()
+ if not self.server.GetValue():
+ self.btn_connect.Enable(False)
+
+ self.infoCollapseLabelExp = _('Show advanced connection settings')
+ self.infoCollapseLabelCol = _('Hide advanced connection settings')
+
+ self.adv_conn = wx.CollapsiblePane(parent = self,
+ label = self.infoCollapseLabelExp,
+ style = wx.CP_DEFAULT_STYLE |
+ wx.CP_NO_TLW_RESIZE | wx.EXPAND)
+
+ self.MakeAdvConnPane(pane = self.adv_conn.GetPane())
+ self.adv_conn.Collapse(True)
+ self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnAdvConnPaneChanged, self.adv_conn)
+
+ self.reqDataPanel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.layerNameText = wx.StaticText(parent = self.reqDataPanel, id = wx.ID_ANY,
+ label = _("Output layer name:"))
+ self.layerName = wx.TextCtrl(parent = self.reqDataPanel, id = wx.ID_ANY)
+
+ for ws in self.ws_panels.iterkeys():
+ self.ws_panels[ws]['panel'] = WSPanel(parent = self.reqDataPanel,
+ web_service = ws,
+ receiver = self)
+
+ # buttons
+ self.btn_close = wx.Button(parent = self, id = wx.ID_CLOSE)
+ self.btn_close.SetToolTipString(_("Close dialog"))
+
+ # statusbar
+ self.statusbar = wx.StatusBar(parent = self, id = wx.ID_ANY)
+
+ # bindings
+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+ self.btn_connect.Bind(wx.EVT_BUTTON, self.OnConnect)
+
+ self.server.Bind(wx.EVT_TEXT, self.OnServer)
+ self.layerName.Bind(wx.EVT_TEXT, self.OnOutputLayerName)
+
+ self.settsManager.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
+ self.settsManager.Bind(EVT_SETTINGS_SAVING, self.OnSettingsSaving)
+ self.settsManager.Bind(EVT_SETTINGS_LOADED, self.OnSettingsLoaded)
+
+ self.Bind(EVT_CAP_PARSED, self.OnPanelCapParsed)
+
+ def _doLayout(self):
+
+ dialogSizer = wx.BoxSizer(wx.VERTICAL)
+
+ dialogSizer.Add(item = self.settsManager, proportion = 0,
+ flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+
+ # connectin settings
+ settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.VERTICAL)
+
+ serverSizer = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
+
+ serverSizer.Add(item = self.serverText,
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ serverSizer.AddGrowableCol(1)
+ serverSizer.Add(item = self.server,
+ flag = wx.EXPAND | wx.ALL)
+
+ serverSizer.Add(item = self.btn_connect)
+
+ settingsSizer.Add(item = serverSizer, proportion = 0,
+ flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+
+ settingsSizer.Add(item = self.adv_conn,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+
+ dialogSizer.Add(item = settingsSizer, proportion = 0,
+ flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+
+ # layer name, parsed capabilites
+
+ reqDataSizer = wx.BoxSizer(wx.VERTICAL)
+
+ layerNameSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ layerNameSizer.Add(item = self.layerNameText,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
+
+ layerNameSizer.Add(item = self.layerName,
+ flag = wx.EXPAND, proportion = 1)
+
+ reqDataSizer.Add(item = layerNameSizer,
+ flag = wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
+
+ self.ch_ws_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ reqDataSizer.Add(item = self.ch_ws_sizer, proportion = 0,
+ flag = wx.TOP | wx.EXPAND, border = 5)
+
+ for ws in self.ws_panels.iterkeys():
+ reqDataSizer.Add(item = self.ws_panels[ws]['panel'], proportion = 1,
+ flag = wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
+ self.ws_panels[ws]['panel'].Hide()
+
+ dialogSizer.Add(item = self.reqDataPanel, proportion = 1,
+ flag = wx.EXPAND)
+
+ self.reqDataPanel.SetSizer(reqDataSizer)
+ self.reqDataPanel.Hide()
+
+ # 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)
+
+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
+ flag = wx.ALIGN_CENTER)
+
+ dialogSizer.Add(item = self.statusbar, proportion = 0)
+
+ self.SetSizer(dialogSizer)
+ self.Layout()
+
+ self.SetMinSize((550, -1))
+ self.SetMaxSize((-1, self.GetBestSize()[1]))
+ self.Fit()
+
+ def MakeAdvConnPane(self, pane):
+ """!Create advanced connection settings pane
+ """
+ self.usernameText = wx.StaticText(parent = pane,
+ id = wx.ID_ANY, label = _("Username:"))
+ self.username = wx.TextCtrl(parent = pane, id = wx.ID_ANY)
+
+ self.passwText = wx.StaticText(parent = pane,
+ id = wx.ID_ANY, label = _("Password:"))
+ self.password = wx.TextCtrl(parent = pane, id = wx.ID_ANY,
+ style = wx.TE_PASSWORD)
+
+ # pane layout
+ adv_conn_sizer = wx.BoxSizer(wx.VERTICAL)
+
+ usernameSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ usernameSizer.Add(item = self.usernameText,
+ flag = wx.ALIGN_CENTER_VERTICAL, border = 5)
+
+ usernameSizer.Add(item = self.username, proportion = 1,
+ flag = wx.EXPAND, border = 5)
+
+ adv_conn_sizer.Add(item = usernameSizer,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+
+ passwSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ passwSizer.Add(item = self.passwText,
+ flag = wx.ALIGN_CENTER_VERTICAL, border = 5)
+
+ passwSizer.Add(item = self.password, proportion = 1,
+ flag = wx.EXPAND, border = 5)
+
+ adv_conn_sizer.Add(item = passwSizer,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+
+ pane.SetSizer(adv_conn_sizer)
+ adv_conn_sizer.Fit(pane)
+
+ pane.SetSizer(adv_conn_sizer)
+ adv_conn_sizer.Fit(pane)
+
+ def OnSettingsSaving(self, event):
+ """!Check if required data are filled before setting save is performed.
+ """
+ server = self.server.GetValue().strip()
+ if not server:
+ GMessage(parent = self,
+ message = _("No data source defined, settings are not saved."))
+ return
+
+ self.settsManager.SetDataToSave((server,
+ self.username.GetValue(),
+ self.password.GetValue()))
+ event.Skip()
+
+ def OnSettingsChanged(self, event):
+ """!Update widgets according to chosen settings"""
+ data = event.data
+
+ # data list: [server, username, password]
+ if len < 3:
+ return
+
+ self.server.SetValue(data[0])
+
+ self.username.SetValue(data[1])
+ self.password.SetValue(data[2])
+
+ if data[1] or data[2]:
+ self.adv_conn.Expand()
+ else:
+ self.adv_conn.Collapse(True)
+
+ def OnSettingsLoaded(self, event):
+ """!If settings are empty set default servers
+ """
+ if not event.settings:
+ self.settsManager.SetSettings(self.default_servers)
+
+ def OnClose(self, event):
+ """!Close the dialog
+ """
+ """!Close dialog"""
+ if not self.IsModal():
+ self.Destroy()
+ event.Skip()
+
+ def _getCapFiles(self):
+ ws_cap_files = {}
+ for v in self.ws_panels.itervalues():
+ ws_cap_files[v['panel'].GetWebService()] = v['panel'].GetCapFile()
+
+ return ws_cap_files
+
+ def OnServer(self, event):
+ """!Server settings edited
+ """
+ value = event.GetString()
+ if value:
+ self.btn_connect.Enable(True)
+ else:
+ self.btn_connect.Enable(False)
+
+ def OnOutputLayerName(self, event):
+ """!Update layer name to web service panel
+ """
+ lname = event.GetString()
+
+ for v in self.ws_panels.itervalues():
+ v['panel'].SetOutputLayerName(lname.strip())
+
+ def OnConnect(self, event):
+ """!Connect to the server
+ """
+ server = self.server.GetValue().strip()
+
+ self.ch_ws_sizer.Clear(deleteWindows = True)
+
+ if self.active_ws_panel is not None:
+ self.reqDataPanel.Hide()
+ for btn in self.run_btns:
+ btn.Enable(False)
+ self.active_ws_panel = None
+
+ self.Layout()
+ self.Fit()
+
+ self.statusbar.SetStatusText(_("Connectig to <%s>..." % self.server.GetValue().strip()))
+
+ # number of panels already connected
+ self.finished_panels_num = 0
+ for ws in self.ws_panels.iterkeys():
+ self.ws_panels[ws]['panel'].ConnectToServer(url = server,
+ username = self.username.GetValue(),
+ password = self.password.GetValue())
+ self.ws_panels[ws]['panel'].Hide()
+
+ def OnPanelCapParsed(self, event):
+ """!Called when panel has downloaded and parsed capabilities file.
+ """
+ # how many web service panels are finished
+ self.finished_panels_num += 1
+
+ # if all are finished, show panels, which succeeded in connection
+ if self.finished_panels_num == len(self.ws_panels):
+ self.UpdateDialogAfterConnection()
+ self.Layout()
+ self.Fit()
+
+ def UpdateDialogAfterConnection(self):
+ """!Update dialog after all web service panels downloaded and parsed capabilities data.
+ """
+ avail_ws = {}
+ for ws, data in self.ws_panels.iteritems():
+
+ if data['panel'].IsConnected():
+ avail_ws[ws] = data
+
+ self.web_service_sel = []
+ self.rb_choices = []
+
+ # at least one web service found on server
+ if len(avail_ws) > 0:
+ self.reqDataPanel.Show()
+ self.rb_order = ['WMS_1.1.1', 'WMS_1.3.0', 'WMTS', 'OnEarth']
+
+ for ws in self.rb_order:
+
+ if ws in avail_ws:
+ self.web_service_sel.append(ws)
+ self.rb_choices.append(avail_ws[ws]['label'])
+
+ self.choose_ws_rb = wx.RadioBox(parent = self.reqDataPanel, id = wx.ID_ANY,
+ label = _("Available web services"),
+ pos = wx.DefaultPosition, choices = self.rb_choices,
+ majorDimension = 1, style = wx.RA_SPECIFY_ROWS)
+
+ self.Bind(wx.EVT_RADIOBOX, self.OnChooseWs, self.choose_ws_rb)
+ self.ch_ws_sizer.Add(item = self.choose_ws_rb,
+ flag = wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+ self._showWsPanel(self.web_service_sel[self.choose_ws_rb.GetSelection()])
+ self.statusbar.SetStatusText(_("Connected to <%s>" % self.server.GetValue().strip()))
+ for btn in self.run_btns:
+ btn.Enable(True)
+ # no web service found on server
+ else:
+ self.statusbar.SetStatusText(_("Unable to connect to <%s>" % self.server.GetValue().strip()))
+ for btn in self.run_btns:
+ btn.Enable(False)
+ self.reqDataPanel.Hide()
+ self.active_ws_panel = None
+
+ def OnChooseWs(self, event):
+ """!Show panel corresponding to selected web service.
+ """
+ choosen_r = event.GetInt()
+ self._showWsPanel(self.web_service_sel[choosen_r])
+
+ def _showWsPanel(self, ws):
+ """!Helper function
+ """
+ if self.active_ws_panel is not None:
+ self.active_ws_panel.Hide()
+
+ self.active_ws_panel = self.ws_panels[ws]['panel']
+ self.active_ws_panel.Show()
+ self.SetMaxSize((-1, -1))
+ self.Layout()
+ self.Fit()
+
+ def OnAdvConnPaneChanged(self, event):
+ """!Collapse search module box
+ """
+ if self.adv_conn.IsExpanded():
+ self.adv_conn.SetLabel(self.infoCollapseLabelCol)
+ else:
+ self.adv_conn.SetLabel(self.infoCollapseLabelExp)
+
+ self.Layout()
+ self.SetMaxSize((-1, self.GetBestSize()[1]))
+ self.SendSizeEvent()
+ self.Fit()
+
+class AddWSDialog(WSDialogBase):
+ """!Show web service layer."""
+ def __init__(self, parent, gmframe, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+
+ WSDialogBase.__init__(self, parent, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs)
+
+ self.SetTitle(_("Add web service layer"))
+
+ self.gmframe = gmframe
+
+ def _createWidgets(self):
+
+ WSDialogBase._createWidgets(self)
+
+ self.btn_add = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Add layer"))
+ self.btn_add.SetToolTipString(_("Import selected layers"))
+ self.btn_add.Enable(False)
+
+ self.run_btns.append(self.btn_add)
+
+ def _doLayout(self):
+
+ WSDialogBase._doLayout(self)
+
+ self.btnsizer.Add(item = self.btn_add, proportion = 0,
+ flag = wx.ALL | wx.ALIGN_CENTER,
+ border = 10)
+
+ # bindings
+ self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddLayer)
+
+ def OnAddLayer(self, event):
+ """!Add web service layer.
+ """
+ # add layer
+ if self.active_ws_panel is None:
+ return
+
+ lcmd = self.active_ws_panel.CreateCmd()
+ if not lcmd:
+ return None
+
+ ltree = self.gmframe.GetLayerTree()
+
+ active_ws = self.active_ws_panel.GetWebService()
+ if 'WMS' not in active_ws:
+ cap_file = self.active_ws_panel.GetCapFile()
+ cmd_cap_file = grass.tempfile()
+ shutil.copyfile(cap_file, cmd_cap_file)
+ lcmd.append('capfile=' + cmd_cap_file)
+
+ layer = ltree.AddLayer(ltype = 'wms', lname = self.layerName.GetValue(),
+ lchecked = True, lcmd = lcmd)
+
+
+ ws_cap_files = self._getCapFiles()
+ # create properties dialog
+ cmd_list = ltree.GetLayerInfo(layer,'cmd')
+ cmd = CmdToTuple(cmd_list)
+
+ prop_win = WSPropertiesDialog(parent = self.gmframe,
+ id = wx.ID_ANY,
+ layer = layer,
+ ltree = ltree,
+ ws_cap_files = ws_cap_files,
+ cmd = cmd)
+
+ prop_win.Hide()
+ ltree.GetOptData(dcmd = None, layer = layer,
+ params = None, propwin = prop_win)
+
+class WSPropertiesDialog(WSDialogBase):
+ """!Show web service property."""
+ def __init__(self, parent, layer, ltree, ws_cap_files, cmd, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ """
+ @param layer - layer tree item
+ @param ltree - layer tree reference
+ @param ws_cap_files - dict web service('WMS_1.1.1', 'WMS_1.3.0', 'WMTS', 'OnEarth') : cap file path
+ - cap files, which will be parsed
+ @param cmd - cmd to which dialog widgets will be initialized if it is possible
+ (cmp parameters exists in parsed web service cap_file)
+ """
+
+ WSDialogBase.__init__(self, parent, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs)
+
+ self.SetTitle(_("Web service layer properties"))
+
+ self.ltree = ltree
+ self.layer = layer
+
+ # after web service panels are connected, set dialog widgets
+ # according to cmd in this variable (if it is not None)
+ self.cmd_to_set = None
+
+ # store data needed for reverting
+ self.revert_ws_cap_files = {}
+ self.revert_cmd = cmd
+
+ ws_cap = self._getWSfromCmd(cmd)
+ for ws in self.ws_panels.iterkeys():
+ # cap file used in cmd will be deleted, thnaks to the dialogs destructor
+ if ws == ws_cap and cmd[1].has_key('capfile'):
+ self.revert_ws_cap_files[ws] = cmd[1]['capfile']
+ del ws_cap_files[ws]
+ else:
+ self.revert_ws_cap_files[ws] = grass.tempfile()
+
+ self._setRevertCapFiles(ws_cap_files)
+
+ self.LoadCapFiles(ws_cap_files = self.revert_ws_cap_files, cmd = cmd)
+
+ def __del__(self):
+ for f in self.revert_ws_cap_files.itervalues():
+ grass.try_remove(f)
+
+ def _setRevertCapFiles(self, ws_cap_files):
+
+ for ws, f in ws_cap_files.iteritems():
+ if os.path.isfile(ws_cap_files[ws]):
+ shutil.copyfile(f, self.revert_ws_cap_files[ws])
+ else:
+ # delete file content
+ f_o = open(f, 'w')
+ f_o.close()
+
+ def _createWidgets(self):
+
+ WSDialogBase._createWidgets(self)
+
+ self.btn_apply = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Apply"))
+ self.btn_apply.SetToolTipString(_("Apply changes"))
+ self.btn_apply.Enable(False)
+ self.run_btns.append(self.btn_apply)
+
+ self.btn_save = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Save"))
+ self.btn_save.SetToolTipString(_("Revert changes"))
+ self.btn_save.Enable(False)
+ self.run_btns.append(self.btn_save)
+
+ def _doLayout(self):
+
+ WSDialogBase._doLayout(self)
+
+ self.btnsizer.Add(item = self.btn_apply, proportion = 0,
+ flag = wx.ALL | wx.ALIGN_CENTER,
+ border = 10)
+
+ self.btnsizer.Add(item = self.btn_save, proportion = 0,
+ flag = wx.ALL | wx.ALIGN_CENTER,
+ border = 10)
+
+ # bindings
+ self.btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
+ self.btn_save.Bind(wx.EVT_BUTTON, self.OnSave)
+
+ def LoadCapFiles(self, ws_cap_files, cmd):
+ """!Parse cap files and update dialog.
+
+ @params for description see constructor
+ """
+ self.ch_ws_sizer.Clear(deleteWindows = True)
+
+ self.cmd_to_set = cmd
+
+ self.finished_panels_num = 0
+
+ conn = self._getServerConnFromCmd(cmd)
+
+ self.server.SetValue(conn['url'])
+ self.password.SetValue(conn['password'])
+ self.username.SetValue(conn['username'])
+
+ self.layerName.SetValue(cmd[1]['map'])
+
+ for ws, data in self.ws_panels.iteritems():
+ cap_file = None
+
+ if ws_cap_files.has_key(ws):
+ cap_file = ws_cap_files[ws]
+
+ data['panel'].ParseCapFile(url = conn['url'],
+ username = conn['password'],
+ password = conn['username'],
+ cap_file = cap_file)
+
+ def _getServerConnFromCmd(self, cmd):
+ """!Get url/server/passwod from cmd tuple
+ """
+ conn = { 'url' : '', 'username' : '', 'password' : ''}
+
+ for k in conn.iterkeys():
+ if cmd[1].has_key(k):
+ conn[k] = cmd[1][k]
+ return conn
+
+ def _apply(self):
+ """!Apply chosen values from widgets to web service layer."""
+ lcmd = self.active_ws_panel.CreateCmd()
+ if not lcmd:
+ return
+
+ active_ws = self.active_ws_panel.GetWebService()
+ if 'WMS' not in active_ws:
+ lcmd.append('capfile=' + self.revert_ws_cap_files[active_ws])
+
+ self.ltree.GetOptData(dcmd = lcmd,
+ layer = self.layer,
+ params = None,
+ propwin = self)
+
+ #TODO use just list or tuple
+ cmd = CmdToTuple(lcmd)
+ self.revert_cmd = cmd
+ self._setRevertCapFiles(self._getCapFiles())
+
+ display = self.ltree.GetMapDisplay().GetMapWindow()
+ event = gUpdateMap()
+ wx.PostEvent(display, event)
+
+ def OnApply(self, event):
+ self._apply()
+
+ def OnSave(self, event):
+ self._apply()
+ self._close()
+
+ def OnClose(self, event):
+ """!Close dialog"""
+ self._close()
+
+ def _close(self):
+ """!Hide dialog"""
+ self.Hide()
+ self.LoadCapFiles(cmd = self.revert_cmd,
+ ws_cap_files = self.revert_ws_cap_files)
+
+ def OnPanelCapParsed(self, event):
+ """!Called when panel has downloaded and parsed capabilities file.
+ """
+ WSDialogBase.OnPanelCapParsed(self, event)
+
+ if self.finished_panels_num == len(self.ws_panels):
+ if self.cmd_to_set:
+ self._updateWsPanelWidgetsByCmd(self.cmd_to_set)
+ self.cmd_to_set = None
+
+ def _updateWsPanelWidgetsByCmd(self, cmd):
+ """!Set values of widgets according to parameters in cmd.
+ """
+
+ ws = self._getWSfromCmd(cmd)
+ if self.ws_panels[ws]['panel'].IsConnected():
+ self.ws_panels[ws]['panel'].UpdateWidgetsByCmd(cmd)
+ self.choose_ws_rb.SetStringSelection(self.ws_panels[ws]['label'])
+ self._showWsPanel(ws)
+
+ def _getWSfromCmd(self, cmd):
+ driver = cmd[1]['driver']
+ ws = driver.split('_')[0]
+
+ if ws == 'WMS':
+ ws += '_' + cmd[1]['wms_version']
+ return ws
+
+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, ltree):
+
+ wx.Dialog.__init__(self, parent = parent, title = ("Save web service layer"), id = wx.ID_ANY)
+
+ self.layer = layer
+ self.ltree = ltree
+
+ 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 layer:"))
+
+ self.params['output'] = Select(parent = self, type = 'rast', mapsets = [grass.gisenv()['MAPSET']],
+ size = globalvar.DIALOG_GSELECT_SIZE)
+
+ self.regionStBoxLabel = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label = _("Region"))
+
+ self.region_types_order = ['comp', 'named']
+ self.region_types = {}
+ #self.region_types['map_display'] = wx.RadioButton(parent = self, id = wx.ID_ANY, label = 'Map display', style = wx.RB_GROUP )
+ self.region_types['comp'] = wx.RadioButton(parent = self, id = wx.ID_ANY, label = 'Computational region')
+ self.region_types['named'] = wx.RadioButton(parent = self, id = wx.ID_ANY, label = 'Named region')
+
+ self.overwrite = wx.CheckBox(parent = self, id = wx.ID_ANY,
+ label = _("Overwrite existing layer"))
+
+ 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_save = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Save layer"))
+ self.btn_save.SetToolTipString(_("Add web service layer"))
+
+ # statusbar
+ self.statusbar = wx.StatusBar(parent = self, id = wx.ID_ANY)
+
+ self._layout()
+
+ def _layout(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']))
+
+ dialogSizer.Add(item = self.overwrite)
+
+ 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])
+
+ 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)
+
+ # 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_save, proportion = 0,
+ flag = wx.ALL | wx.ALIGN_CENTER,
+ border = 10)
+
+ dialogSizer.Add(item = self.btnsizer, proportion = 0,
+ flag = wx.ALIGN_CENTER)
+
+ border.Add(item = dialogSizer, proportion = 0,
+ flag = wx.ALL, border = 5)
+
+ border.Add(item = self.statusbar, proportion = 0)
+
+ self.SetSizer(border)
+ self.Layout()
+ self.Fit()
+
+ # bindings
+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
+ self.btn_save.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.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:
+ GWarning(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['comp'].GetValue() == 1:
+ pass
+ elif grass.find_file(reg_spl[0], 'region', reg_mapset)['fullname']:
+ msg = _('Region <%s> does not exists.' % 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
+
+ if self.region_types['named'].GetValue() == 1:
+ cmd[1]['region'] = region
+
+ cmdList = CmdTupleToList(cmd)
+ self.currentPid = self.thread.GetId()
+
+ self.thread.RunCmd(cmdList, 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.
+ """
+ if self.ltree.FindItemByData(key = 'name', value = self.output) is None:
+ cmd = ['d.rast', 'map=' + self.output]
+ self.ltree.AddLayer(ltype = 'raster',
+ lname = self.output,
+ lcmd = cmd,
+ lchecked = 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)
Added: grass/trunk/gui/wxpython/web_services/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/web_services/widgets.py (rev 0)
+++ grass/trunk/gui/wxpython/web_services/widgets.py 2013-01-12 16:41:52 UTC (rev 54607)
@@ -0,0 +1,1016 @@
+"""!
+ at package web_services.widgets
+
+ at brief Widgets for web services (WMS, WMTS, NasaOnEarh)
+
+List of classes:
+ - widgets::WSPanel
+ - widgets::LayersList
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Stepan Turek <stepan.turek seznam.cz>
+"""
+
+import os
+import sys
+import shutil
+
+from copy import deepcopy
+from xml.etree.ElementTree import ParseError
+
+import wx
+import wx.lib.flatnotebook as FN
+import wx.lib.colourselect as csel
+import wx.lib.mixins.listctrl as listmix
+from wx.lib.newevent import NewEvent
+from wx.gizmos import TreeListCtrl
+
+from core import globalvar
+from core.debug import Debug
+from core.gcmd import GWarning
+from core.gconsole import CmdThread, EVT_CMD_DONE
+
+from web_services.cap_interface import WMSCapabilities, \
+ WMTSCapabilities, \
+ OnEarthCapabilities
+
+from gui_core.widgets import GNotebook
+
+import grass.script as grass
+
+WMSLibPath = os.path.join(os.getenv("GISBASE"), "etc", "r.in.wms")
+sys.path.append(WMSLibPath)
+
+from wms_base import WMSDriversInfo
+
+wxOnCapParsed, EVT_CAP_PARSED = NewEvent()
+
+class WSPanel(wx.Panel):
+ def __init__(self, parent, receiver, web_service, **kwargs):
+ """!Show data from capabilities file.
+
+ Events: EVT_CAP_PARSED - this event is released when capabilities file is downloaded
+ (after ConnectToServer method was called)
+
+ @param parent - parent widget
+ @param receiver - receives EVT_CAP_PARSED event
+ @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.receiver = receiver
+
+ # stores widgets, which represents parameters/flags of d.wms
+ self.params = {}
+ self.flags = {}
+
+ self.o_layer_name = ''
+
+ # 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.cmd_thread = CmdThread(self)
+ self.cap_file = grass.tempfile()
+
+ self.notebook = GNotebook(parent = self,
+ style = FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON)
+
+ self._requestPage()
+ self._advancedSettsPage()
+
+ self._layout()
+
+ self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone)
+
+ def __del__(self):
+ self.cmd_thread.abort(abortall =True)
+ grass.try_remove(self.cap_file)
+
+ def _layout(self):
+ reqDataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label = _(" Requested data settings "))
+ sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL)
+ sizer.Add(item = self.notebook, proportion = 1,
+ flag = wx.EXPAND)
+ self.SetSizer(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, pos = wx.DefaultPosition,
+ choices = [], style = wx.RA_SPECIFY_COLS)
+
+ 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)
+
+ if self.params['format'] is not None:
+ self.req_page_sizer.Add(item = self.params['format'],
+ flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+
+ projSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ if self.params['srs'] is not None:
+ projSizer.Add(item = projText, flag = wx.ALIGN_CENTER_VERTICAL)
+ projSizer.Add(item = self.params['srs'])
+
+ self.req_page_sizer.Add(item = projSizer,
+ 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 = ['near', 'bilinear', 'cubic', 'cubicspline']
+ self.params['method'] = wx.Choice(parent = adv_setts_panel, id = wx.ID_ANY,
+ choices = [_('near'), _('bilinear'), _('cubic'), _('cubicspline')])
+
+ 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.AddGrowableCol(0)
+
+ 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)
+
+ 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)
+ gridSizer.AddGrowableCol(0)
+
+ row = 0
+ for k in ['method', 'maxcols', 'maxrows', 'o', 'bgcolor']:
+
+ if self.params.has_key(k):
+ param = self.params[k]
+ elif self.flags.has_key(k):
+ param = self.flags[k]
+
+ if param is None:
+ continue
+
+ if labels.has_key(k) 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
+
+ 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)
+ gridSizer.AddGrowableCol(1)
+
+ 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))
+
+ 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
+ @param username - username for connection
+ @param password - password for connection
+ """
+ self._prepareForNewConn(url, username, password)
+ cap_cmd = ['r.in.wms', '-c', ('capfile_output=%s' % self.cap_file)] + self.ws_cmdl
+
+ self.currentPid = self.cmd_thread.GetId()
+ self.cmd_thread.RunCmd(cap_cmd)
+
+ 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 EVT_CAP_PARSED (see class constructor).
+ """
+ if event.pid != self.currentPid:
+ return
+
+ if event.returncode != 0:
+ msg = "Downloading of capabilities file failed."
+ self._postCapParsedEvt(IOError(msg))
+ return
+
+ self._parseCapFile(self.cap_file)
+
+ def _parseCapFile(self, cap_file):
+ """!Parse capabilities data and emits EVT_CAP_PARSED (see class constructor).
+ """
+ try:
+ self.cap = self.ws_drvs[self.ws]['cap_parser'](cap_file)
+ except (IOError, ParseError) as error:
+ self._postCapParsedEvt(error)
+ return
+
+ if self.l_odrder_list:
+ self.l_odrder_list.Clear()
+
+ 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.OnListSelChanged(event = None)
+
+ self.list.LoadData(self.cap)
+ self._postCapParsedEvt(None)
+
+ def ParseCapFile(self, url, username, password, cap_file = None,):
+ """!Parse capabilities data and emits EVT_CAP_PARSED (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 self.l_odrder_list:
+ self.l_odrder_list.Clear()
+
+ if dcmd.has_key('layers'):
+ layers = dcmd['layers']
+
+ styles = []
+ if dcmd.has_key('styles'):
+ 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 dcmd.has_key('format'):
+ params['format'] = dcmd['format']
+ if dcmd.has_key('srs'):
+ params['srs'] = 'EPSG:' + dcmd['srs']
+ if dcmd.has_key('method'):
+ 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 dcmd.has_key(p):
+ v = dcmd[p]
+ if conv_f:
+ v = conv_f(v)
+ self.params[p].SetValue(v)
+
+ if dcmd.has_key('flags') and \
+ 'o' in dcmd['flags']:
+ self.flags['o'].SetValue(1)
+ self.params['bgcolor'].Enable(True)
+
+ if dcmd.has_key('bgcolor') 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):
+ """!Helper function
+ """
+ if error:
+ msg = "%s web service was not found in fetched capabilities from '%s'.\n%s\n" % \
+ (self.ws, self.conn['url'], str(error))
+ Debug.msg(3, msg)
+
+ cap_parsed_event = wxOnCapParsed()
+ cap_parsed_event.SetEventObject(self)
+ wx.PostEvent(self.receiver, cap_parsed_event)
+
+ 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.Color(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_spl = proj.strip().split(':')
+
+ if 'EPSG' in proj_spl[0]:
+ try:
+ int(proj_spl[1])
+ self.projs_list.append(proj)
+ except ValueError, 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.req_page_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 += _("Insert output layer name.\n")
+ show_war = True
+
+ if show_war:
+ GWarning(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 GetCapFile(self):
+ """!Get path to file where capabilities are saved
+ """
+ return self.cap_file
+
+ def GetWebService(self):
+ """!Get web service
+ """
+ return self.ws
+
+class LayersList(TreeListCtrl, listmix.ListCtrlAutoWidthMixin):
+ def __init__(self, parent, web_service, style, pos=wx.DefaultPosition):
+ """!List of layers and styles available in capabilities file
+ """
+ self.parent = parent
+ self.ws = web_service
+
+ TreeListCtrl.__init__(self, parent = parent, id = wx.ID_ANY, style = style)
+
+ # setup mixins
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+ if self.ws != 'OnEarth':
+ self.AddColumn(_('Name'))
+ self.AddColumn(_('Type'))
+ else:
+ self.AddColumn(_('Layer name'))
+
+ self.SetMainColumn(0) # column with the tree
+ self.setResizeColumn(0)
+
+ self.root = None
+ self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnListSelChanging)
+
+ def LoadData(self, cap = None):
+ """!Load data into list
+ """
+ # detete first all items
+ self.DeleteAllItems()
+
+ if not cap:
+ return
+
+ def AddLayerChildrenToTree(parent_layer, parent_item):
+ """!Recursive function which adds all capabilities layers/styles to the LayersList.
+ """
+ def gettitle(layer):
+ """!Helper function"""
+ if layer.GetLayerData('title') is not None:
+ layer_title = layer.GetLayerData('title')
+ elif layer.GetLayerData('name') is not None:
+ layer_title = layer.GetLayerData('name')
+ else:
+ layer_title = str(layer.GetId())
+
+ return layer_title
+
+ def addlayer(layer, item):
+
+ if self.ws != 'OnEarth':
+ self.SetItemText(item, _('layer'), 1)
+
+ styles = layer.GetLayerData('styles')
+
+ def_st = None
+ for st in styles:
+
+ if st['name']:
+ style_name = st['name']
+ else:
+ continue
+
+ if st['title']:
+ style_name = st['title']
+
+ if st['isDefault']:
+ def_st = st
+
+ style_item = self.AppendItem(item, style_name)
+ if self.ws != 'OnEarth':
+ self.SetItemText(style_item, _('style'), 1)
+
+ self.SetPyData(style_item, {'type' : 'style',
+ 'layer' : layer, # it is parent layer of style
+ 'style' : st})
+
+ self.SetPyData(item, {'type' : 'layer', # is it layer or style?
+ 'layer' : layer, # *Layer instance from web_services.cap_interface
+ 'style' : def_st}) # layer can have assigned default style
+
+ if parent_layer is None:
+ parent_layer = cap.GetRootLayer()
+ layer_title = gettitle(parent_layer)
+ parent_item = self.AddRoot(layer_title)
+ addlayer(parent_layer, parent_item)
+
+ for layer in parent_layer.GetChildren():
+ item = self.AppendItem(parent_item, gettitle(layer))
+ addlayer(layer, item)
+ AddLayerChildrenToTree(layer, item)
+
+ AddLayerChildrenToTree(None, None)
+ self.ExpandAll(self.GetRootItem())
+
+ def GetSelectedLayers(self):
+ """!Get selected layers/styles in LayersList
+
+ @return dict with these items:
+ 'name' : layer name used for request
+ if it is style, it is name of parent layer
+ 'title' : layer title
+ 'style' : {'name' : 'style name', title : 'style title'}
+ 'cap_intf_l' : *Layer instance from web_services.cap_interface
+ """
+ sel_layers = self.GetSelections()
+ sel_layers_dict = []
+ for s in sel_layers:
+
+ try:
+ layer = self.GetPyData(s)['layer']
+ except ValueError:
+ continue
+ sel_layers_dict.append({
+ 'name' : layer.GetLayerData('name'),
+ 'title' : layer.GetLayerData('title'),
+ 'style' : self.GetPyData(s)['style'],
+ 'cap_intf_l' : layer
+ })
+ return sel_layers_dict
+
+ def OnListSelChanging(self, event):
+ """!Do not allow to select items, which cannot be requested from server.
+ """
+ cur_item = event.GetItem ()
+
+ if not self.GetPyData(cur_item)['layer'].IsRequestable():
+ event.Veto()
+
+ def GetItemCount(self):
+ """!Required for listmix.ListCtrlAutoWidthMixin
+ """
+ return 0
+
+ def GetCountPerPage(self):
+ """!Required for listmix.ListCtrlAutoWidthMixin
+ """
+ return 0
+
+ def SelectLayers(self, l_st_list):
+ """!Select layers/styles in LayersList
+
+ @param l_st_list - [{style : 'style_name', layer : 'layer_name'}, ...]
+ @return items from l_st_list which were not found
+ """
+ def checknext(item, l_st_list, items_to_sel):
+ def compare(item, l_name, st_name):
+ it_l_name = self.GetPyData(item)['layer'].GetLayerData('name')
+ it_st = self.GetPyData(item)['style']
+ it_type = self.GetPyData(item)['type']
+
+ if it_l_name == l_name and \
+ ( (not it_st and not st_name) or \
+ (it_st and it_st['name'] == st_name and it_type == 'style')):
+
+ return True
+
+ return False
+
+ for i, l_st in enumerate(l_st_list):
+ l_name = l_st['layer']
+ st_name = l_st['style']
+
+ if compare(item, l_name, st_name):
+ items_to_sel[i] = [item, l_st]
+ break
+
+ if len(items_to_sel) == len(l_st_list):
+ item = self.GetNext(item)
+ if not item.IsOk():
+ return
+ checknext(item, l_st_list, items_to_sel)
+
+ self.UnselectAll()
+
+ l_st_list = deepcopy(l_st_list)
+ root_item = self.GetRootItem()
+
+ items_to_sel = [None] * len(l_st_list)
+ checknext(root_item, l_st_list, items_to_sel)
+
+ # items are selected according to position in l_st_list
+ # to be added to Layers order list in right order
+ for i in items_to_sel:
+ if not i:
+ continue
+
+ item, l_st = i
+ un_o = True
+ if self.HasFlag(wx.TR_MULTIPLE):
+ un_o = False
+
+ self.SelectItem(item, unselect_others = un_o)
+ l_st_list.remove(l_st)
+
+ return l_st_list
Modified: grass/trunk/gui/wxpython/xml/menudata.xml
===================================================================
--- grass/trunk/gui/wxpython/xml/menudata.xml 2013-01-12 16:13:46 UTC (rev 54606)
+++ grass/trunk/gui/wxpython/xml/menudata.xml 2013-01-12 16:41:52 UTC (rev 54607)
@@ -184,12 +184,6 @@
<handler>OnMenuCmd</handler>
<command>r.in.lidar</command>
</menuitem>
- <menuitem>
- <label>WMS import</label>
- <help>Download and import data from WMS servers.</help>
- <keywords>raster,import,wms</keywords><handler>OnImportWMS</handler>
- <command>r.in.wms</command>
- </menuitem>
<separator />
<menuitem>
<label>Unpack raster map</label>
More information about the grass-commit
mailing list