12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193 |
- """
- @package web_services.widgets
- @brief Widgets for web services (WMS, WMTS, NasaOnEarh)
- List of classes:
- - widgets::WSPanel
- - widgets::LayersList
- (C) 2012-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.
- @author Martin Landa <landa.martin gmail.com>
- @author Stepan Turek <stepan.turek seznam.cz>
- """
- import re
- import os
- import sys
- import six
- import shutil
- from copy import deepcopy
- from core import globalvar
- try:
- from xml.etree.ElementTree import ParseError
- except ImportError: # < Python 2.7
- from xml.parsers.expat import ExpatError as ParseError
- import wx
- if globalvar.wxPythonPhoenix:
- try:
- import agw.flatnotebook as FN
- except ImportError: # if it's not there locally, try the wxPython lib.
- import wx.lib.agw.flatnotebook as FN
- else:
- import wx.lib.flatnotebook as FN
- import wx.lib.colourselect as csel
- from core.debug import Debug
- from core.gcmd import GMessage
- from core.gconsole import CmdThread, GStderr, EVT_CMD_DONE, EVT_CMD_OUTPUT
- from web_services.cap_interface import (
- WMSCapabilities,
- WMTSCapabilities,
- OnEarthCapabilities,
- )
- from gui_core.widgets import GNotebook
- from gui_core.widgets import ManageSettingsWidget
- from gui_core.wrap import (
- Button,
- ScrolledPanel,
- SpinCtrl,
- StaticBox,
- StaticText,
- TextCtrl,
- TreeCtrl,
- )
- import grass.script as grass
- rinwms_path = os.path.join(os.getenv("GISBASE"), "etc", "r.in.wms")
- if rinwms_path not in sys.path:
- sys.path.append(rinwms_path)
- from wms_base import WMSDriversInfo
- from srs import Srs
- from grass.pydispatch.signal import Signal
- class WSPanel(wx.Panel):
- def __init__(self, parent, web_service, **kwargs):
- """Show data from capabilities file.
- Signal: capParsed - this signal is emitted when capabilities file is downloaded
- (after ConnectToServer method was called)
- :param parent: parent widget
- :param web_service: web service to be panel generated for
- """
- wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
- self.parent = parent
- self.ws = web_service
- self.capParsed = Signal("WSPanel.capParsed")
- # stores widgets, which represents parameters/flags of d.wms
- self.params = {}
- self.flags = {}
- self.o_layer_name = ""
- # stores err output from r.in.wms during getting capabilities
- self.cmd_err_str = ""
- # stores selected layer from layer list
- self.sel_layers = []
- # downloaded and parsed data from server successfully?
- self.is_connected = False
- # common part of command for r.in.wms -c and d.wms
- self.ws_cmdl = None
- # provides information about driver parameters
- self.drv_info = WMSDriversInfo()
- self.drv_props = self.drv_info.GetDrvProperties(self.ws)
- self.ws_drvs = {
- "WMS_1.1.1": {
- "cmd": ["wms_version=1.1.1", "driver=WMS_GRASS"],
- "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.1.1"),
- },
- "WMS_1.3.0": {
- "cmd": ["wms_version=1.3.0", "driver=WMS_GRASS"],
- "cap_parser": lambda temp_file: WMSCapabilities(temp_file, "1.3.0"),
- },
- "WMTS": {
- "cmd": ["driver=WMTS_GRASS"],
- "cap_parser": WMTSCapabilities,
- },
- "OnEarth": {
- "cmd": ["driver=OnEarth_GRASS"],
- "cap_parser": OnEarthCapabilities,
- },
- }
- self.cmdStdErr = GStderr(self)
- self.cmd_thread = CmdThread(self)
- self.cap_file = grass.tempfile()
- reqDataBox = StaticBox(parent=self, label=_(" Requested data settings "))
- self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL)
- self.notebook = GNotebook(parent=self, style=FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG)
- self._requestPage()
- self._advancedSettsPage()
- self._layout()
- self.layerSelected = self.list.layerSelected
- self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone)
- self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
- self.SetMinSize((-1, 300))
- def __del__(self):
- self.cmd_thread.abort(abortall=True)
- grass.try_remove(self.cap_file)
- def _layout(self):
- self._nb_sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND)
- self.SetSizer(self._nb_sizer)
- def _requestPage(self):
- """Create request page"""
- self.req_page_panel = wx.Panel(parent=self, id=wx.ID_ANY)
- self.notebook.AddPage(
- page=self.req_page_panel, text=_("Request"), name="request"
- )
- # list of layers
- self.layersBox = StaticBox(
- parent=self.req_page_panel, id=wx.ID_ANY, label=_("List of layers ")
- )
- style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT
- if self.drv_props["req_multiple_layers"]:
- style = style | wx.TR_MULTIPLE
- if "WMS" not in self.ws:
- style = style | wx.TR_HIDE_ROOT
- self.list = LayersList(
- parent=self.req_page_panel, web_service=self.ws, style=style
- )
- self.params["format"] = None
- self.params["srs"] = None
- if "srs" not in self.drv_props["ignored_params"]:
- projText = StaticText(
- parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source projection:")
- )
- self.params["srs"] = wx.Choice(parent=self.req_page_panel, id=wx.ID_ANY)
- self.list.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnListSelChanged)
- # layout
- self.req_page_sizer = wx.BoxSizer(wx.VERTICAL)
- layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)
- layersSizer.Add(
- self.list,
- proportion=1,
- flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
- border=5,
- )
- self.req_page_sizer.Add(
- layersSizer,
- proportion=1,
- flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
- border=5,
- )
- self.source_sizer = wx.BoxSizer(wx.HORIZONTAL)
- if self.params["format"] is not None:
- self.source_sizer.Add(
- self.params["format"], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5
- )
- if self.params["srs"] is not None:
- self.source_sizer.Add(
- projText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5
- )
- self.source_sizer.Add(
- self.params["srs"],
- flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP | wx.BOTTOM,
- border=5,
- )
- self.req_page_sizer.Add(
- self.source_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5
- )
- self.req_page_panel.SetSizer(self.req_page_sizer)
- def enableButtons(self, enable=True):
- """Enable/disable up, down, buttons"""
- self.btnUp.Enable(enable)
- self.btnDown.Enable(enable)
- def _advancedSettsPage(self):
- """Create advanced settings page"""
- # TODO parse maxcol, maxrow, settings from d.wms module?
- # TODO OnEarth driver - add selection of time
- adv_setts_panel = ScrolledPanel(
- parent=self, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER
- )
- self.notebook.AddPage(
- page=adv_setts_panel,
- text=_("Advanced request settings"),
- name="adv_req_setts",
- )
- labels = {}
- self.l_odrder_list = None
- if "WMS" in self.ws:
- labels["l_order"] = StaticBox(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- label=_("Order of layers in raster"),
- )
- self.l_odrder_list = wx.ListBox(
- adv_setts_panel,
- id=wx.ID_ANY,
- choices=[],
- style=wx.LB_SINGLE | wx.LB_NEEDED_SB,
- )
- self.btnUp = Button(adv_setts_panel, id=wx.ID_ANY, label=_("Up"))
- self.btnDown = Button(adv_setts_panel, id=wx.ID_ANY, label=_("Down"))
- self.btnUp.Bind(wx.EVT_BUTTON, self.OnUp)
- self.btnDown.Bind(wx.EVT_BUTTON, self.OnDown)
- labels["method"] = StaticText(
- parent=adv_setts_panel, id=wx.ID_ANY, label=_("Reprojection method:")
- )
- self.reproj_methods = ["nearest", "linear", "cubic", "cubicspline"]
- self.params["method"] = wx.Choice(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- choices=[
- _("Nearest neighbor"),
- _("Linear interpolation"),
- _("Cubic interpolation"),
- _("Cubic spline interpolation"),
- ],
- )
- labels["maxcols"] = StaticText(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- label=_("Maximum columns to request from server at time:"),
- )
- self.params["maxcols"] = SpinCtrl(
- parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)
- )
- labels["maxrows"] = StaticText(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- label=_("Maximum rows to request from server at time:"),
- )
- self.params["maxrows"] = SpinCtrl(
- parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)
- )
- min = 100
- max = 10000
- self.params["maxcols"].SetRange(min, max)
- self.params["maxrows"].SetRange(min, max)
- val = 500
- self.params["maxcols"].SetValue(val)
- self.params["maxrows"].SetValue(val)
- self.flags["o"] = self.params["bgcolor"] = None
- if "o" not in self.drv_props["ignored_flags"]:
- self.flags["o"] = wx.CheckBox(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- label=_("Do not request transparent data"),
- )
- self.flags["o"].Bind(wx.EVT_CHECKBOX, self.OnTransparent)
- labels["bgcolor"] = StaticText(
- parent=adv_setts_panel, id=wx.ID_ANY, label=_("Background color:")
- )
- self.params["bgcolor"] = csel.ColourSelect(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- colour=(255, 255, 255),
- size=globalvar.DIALOG_COLOR_SIZE,
- )
- self.params["bgcolor"].Enable(False)
- self.params["urlparams"] = None
- if self.params["urlparams"] not in self.drv_props["ignored_params"]:
- labels["urlparams"] = StaticText(
- parent=adv_setts_panel,
- id=wx.ID_ANY,
- label=_("Additional query parameters for server:"),
- )
- self.params["urlparams"] = TextCtrl(parent=adv_setts_panel, id=wx.ID_ANY)
- # layout
- border = wx.BoxSizer(wx.VERTICAL)
- if "WMS" in self.ws:
- boxSizer = wx.StaticBoxSizer(labels["l_order"], wx.VERTICAL)
- gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
- gridSizer.Add(
- self.l_odrder_list,
- pos=(0, 0),
- span=(4, 1),
- flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
- border=0,
- )
- gridSizer.Add(
- self.btnUp, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0
- )
- gridSizer.Add(
- self.btnDown, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0
- )
- gridSizer.AddGrowableCol(0)
- boxSizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
- border.Add(boxSizer, flag=wx.LEFT | wx.RIGHT | wx.UP | wx.EXPAND, border=5)
- gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
- row = 0
- for k in ["method", "maxcols", "maxrows", "o", "bgcolor"]:
- if k in self.params:
- param = self.params[k]
- elif k in self.flags:
- param = self.flags[k]
- if param is None:
- continue
- if k in labels or k == "o":
- if k != "o":
- label = labels[k]
- else:
- label = param
- gridSizer.Add(
- label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)
- )
- if k != "o":
- gridSizer.Add(
- param, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 1)
- )
- row += 1
- gridSizer.AddGrowableCol(0)
- border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5)
- if self.params["urlparams"]:
- gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
- row = 0
- gridSizer.Add(
- labels["urlparams"],
- flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL,
- pos=(row, 0),
- )
- gridSizer.Add(
- self.params["urlparams"],
- flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
- pos=(row, 1),
- )
- gridSizer.AddGrowableCol(1)
- border.Add(
- gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5
- )
- adv_setts_panel.SetSizer(border)
- adv_setts_panel.SetAutoLayout(True)
- adv_setts_panel.SetupScrolling()
- def OnUp(self, event):
- """Move selected layer up"""
- if self.l_odrder_list.GetSelections():
- pos = self.l_odrder_list.GetSelection()
- if pos:
- self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos))
- if pos > 0:
- self._updateLayerOrderList(selected=(pos - 1))
- else:
- self._updateLayerOrderList(selected=0)
- def OnDown(self, event):
- """Move selected to down"""
- if self.l_odrder_list.GetSelections():
- pos = self.l_odrder_list.GetSelection()
- if pos != len(self.sel_layers) - 1:
- self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos))
- if pos < len(self.sel_layers) - 1:
- self._updateLayerOrderList(selected=(pos + 1))
- else:
- self._updateLayerOrderList(selected=len(self.sel_layers) - 1)
- def _updateLayerOrderList(self, selected=None):
- """Update order in list."""
- def getlayercaption(l):
- if l["title"]:
- cap = l["title"]
- else:
- cap = l["name"]
- if l["style"]:
- if l["style"]["title"]:
- cap += " / " + l["style"]["title"]
- else:
- cap += " / " + l["style"]["name"]
- return cap
- layer_capts = [getlayercaption(l) for l in self.sel_layers]
- self.l_odrder_list.Set(layer_capts)
- if self.l_odrder_list.IsEmpty():
- self.enableButtons(False)
- else:
- self.enableButtons(True)
- if selected is not None:
- self.l_odrder_list.SetSelection(selected)
- self.l_odrder_list.EnsureVisible(selected)
- def OnTransparent(self, event):
- checked = event.IsChecked()
- if checked:
- self.params["bgcolor"].Enable(True)
- else:
- self.params["bgcolor"].Enable(False)
- def ConnectToServer(self, url, username, password):
- """Download and parse data from capabilities file.
- :param url: server url
- :type url: str
- :param username: username for connection
- :type username: str
- :param password: password for connection
- :type password: str
- """
- self._prepareForNewConn(url, username, password)
- cap_cmd = [
- "r.in.wms",
- "-c",
- ("capfile_output=%s" % self.cap_file),
- "--overwrite",
- ] + self.ws_cmdl
- self.currentPid = self.cmd_thread.GetId()
- self.cmd_thread.RunCmd(cap_cmd, stderr=self.cmdStdErr)
- def OnCmdOutput(self, event):
- """Manage cmd output."""
- if Debug.GetLevel() != 0:
- Debug.msg(1, event.text)
- elif event.type != "message" and event.type != "warning":
- self.cmd_err_str += event.text + os.linesep
- def _prepareForNewConn(self, url, username, password):
- """Prepare panel for new connection"""
- self.is_connected = False
- self.sel_layers = []
- self.formats_list = []
- self.projs_list = []
- self.conn = {"url": url, "password": password, "username": username}
- conn_cmd = []
- for k, v in six.iteritems(self.conn):
- if v:
- conn_cmd.append("%s=%s" % (k, v))
- self.ws_cmdl = self.ws_drvs[self.ws]["cmd"] + conn_cmd
- def OnCapDownloadDone(self, event):
- """Process downloaded capabilities file and emits capParsed
- signal (see class constructor).
- """
- if event.pid != self.currentPid:
- return
- if event.returncode != 0:
- if self.cmd_err_str:
- self.cmd_err_str = (
- _(
- "Unable to download %s capabilities file\nfrom <%s>:\n"
- % (self.ws.replace("_", " "), self.conn["url"])
- )
- + self.cmd_err_str
- )
- self._postCapParsedEvt(error_msg=self.cmd_err_str)
- self.cmd_err_str = ""
- return
- self._parseCapFile(self.cap_file)
- def _parseCapFile(self, cap_file):
- """Parse capabilities data and emits capParsed signal
- (see class constructor).
- """
- try:
- self.cap = self.ws_drvs[self.ws]["cap_parser"](cap_file)
- except (IOError, ParseError) as error:
- error_msg = _(
- "%s web service was not found in fetched capabilities file from <%s>:\n%s\n"
- % (self.ws, self.conn["url"], str(error))
- )
- if Debug.GetLevel() != 0:
- Debug.msg(1, error_msg)
- self._postCapParsedEvt(None)
- else:
- self._postCapParsedEvt(error_msg=error_msg)
- return
- self.is_connected = True
- # WMS standard has formats defined for all layers
- if "WMS" in self.ws:
- self.formats_list = sorted(self._getFormats())
- self._updateFormatRadioBox(self.formats_list)
- self._setDefaultFormatVal()
- self.list.LoadData(self.cap)
- self.OnListSelChanged(event=None)
- self._postCapParsedEvt(None)
- def ParseCapFile(
- self,
- url,
- username,
- password,
- cap_file=None,
- ):
- """Parse capabilities data and emits capParsed signal
- (see class constructor).
- """
- self._prepareForNewConn(url, username, password)
- if cap_file is None or not url:
- self._postCapParsedEvt(None)
- return
- shutil.copyfile(cap_file, self.cap_file)
- self._parseCapFile(self.cap_file)
- def UpdateWidgetsByCmd(self, cmd):
- """Update panel widgets accordnig to passed cmd tuple
- :param cmd: cmd in tuple
- """
- dcmd = cmd[1]
- layers = []
- if "layers" in dcmd:
- layers = dcmd["layers"]
- styles = []
- if "styles" in dcmd:
- styles = dcmd["styles"]
- if "WMS" in self.ws:
- layers = layers.split(",")
- styles = styles.split(",")
- else:
- layers = [layers]
- styles = [styles]
- if len(layers) != len(styles):
- styles = [""] * len(layers)
- l_st_list = []
- for i in range(len(layers)):
- l_st_list.append({"style": styles[i], "layer": layers[i]})
- # WMS standard - first layer in params is most bottom...
- # therefore layers order need to be reversed
- l_st_list = [l for l in reversed(l_st_list)]
- self.list.SelectLayers(l_st_list)
- params = {}
- if "format" in dcmd:
- params["format"] = dcmd["format"]
- if "srs" in dcmd:
- params["srs"] = "EPSG:" + dcmd["srs"]
- if "method" in dcmd:
- params["method"] = dcmd["method"]
- for p, v in six.iteritems(params):
- if self.params[p]:
- self.params[p].SetStringSelection(v)
- for p, conv_f in [("urlparams", None), ("maxcols", int), ("maxrows", int)]:
- if p in dcmd:
- v = dcmd[p]
- if conv_f:
- v = conv_f(v)
- self.params[p].SetValue(v)
- if "flags" in dcmd and "o" in dcmd["flags"]:
- self.flags["o"].SetValue(1)
- self.params["bgcolor"].Enable(True)
- if "bgcolor" in dcmd and self.params["bgcolor"]:
- bgcolor = dcmd["bgcolor"].strip().lower()
- if len(bgcolor) == 8 and "0x" == bgcolor[:2]:
- colour = "#" + bgcolor[2:]
- self.params["bgcolor"].SetColour(colour)
- def IsConnected(self):
- """Was successful in downloading and parsing capabilities data?"""
- return self.is_connected
- def _postCapParsedEvt(self, error_msg):
- """Helper function"""
- self.capParsed.emit(error_msg=error_msg)
- def CreateCmd(self):
- """Create d.wms cmd from values of panels widgets
- :return: cmd list
- :return: None if required widgets do not have selected/filled values.
- """
- # check required widgets
- if not self._checkImportValues():
- return None
- # create d.wms command
- lcmd = self.ws_cmdl
- lcmd = ["d.wms"] + lcmd
- layers = "layers="
- styles = "styles="
- first = True
- # WMS standard - first layer in params is most bottom...
- # therefore layers order need to be reversed
- for layer in reversed(self.sel_layers):
- if not first:
- layers += ","
- styles += ","
- first = False
- layers += layer["name"]
- if layer["style"] is not None:
- styles += layer["style"]["name"]
- lcmd.append(layers)
- lcmd.append(styles)
- if "format" not in self.drv_props["ignored_params"]:
- i_format = self.params["format"].GetSelection()
- lcmd.append("format=%s" % self.formats_list[i_format])
- if "srs" not in self.drv_props["ignored_params"]:
- i_srs = self.params["srs"].GetSelection()
- srs = self.projs_list[i_srs].split(":")[-1]
- epsg_num = int("".join(re.findall(r"\d+", srs)))
- lcmd.append("srs=%s" % epsg_num)
- for k in ["maxcols", "maxrows", "urlparams"]:
- lcmd.append(k + "=" + str(self.params[k].GetValue()))
- i_method = self.params["method"].GetSelection()
- lcmd.append("method=" + self.reproj_methods[i_method])
- if "o" not in self.drv_props["ignored_flags"] and self.flags["o"].IsChecked():
- lcmd.append("-o")
- c = self.params["bgcolor"].GetColour()
- hex_color = wx.Colour(c[0], c[1], c[2]).GetAsString(wx.C2S_HTML_SYNTAX)
- lcmd.append("bgcolor=" + "0x" + hex_color[1:])
- lcmd.append("map=" + self.o_layer_name)
- return lcmd
- def OnListSelChanged(self, event):
- """Update widgets according to selected layer in list."""
- curr_sel_ls = self.list.GetSelectedLayers()
- # update self.sel_layers (selected layer list)
- if "WMS" in self.ws:
- for sel_l in self.sel_layers[:]:
- if sel_l not in curr_sel_ls:
- self.sel_layers.remove(sel_l)
- for l in curr_sel_ls:
- if l not in self.sel_layers:
- self.sel_layers.append(l)
- self._updateLayerOrderList()
- else:
- self.sel_layers = curr_sel_ls
- # update projection
- self.projs_list = []
- projs_list = []
- intersect_proj = []
- first = True
- for l in curr_sel_ls:
- layer_projs = l["cap_intf_l"].GetLayerData("srs")
- if first:
- projs_list = layer_projs
- first = False
- continue
- projs_list = set(projs_list).intersection(layer_projs)
- if "srs" not in self.drv_props["ignored_params"]:
- for proj in projs_list:
- proj_code = Srs(proj.strip()).getcode()
- proj_spl = proj_code.split(":")
- if proj_spl[0].strip().lower() in self.drv_info.GetSrs():
- # accept ogc:crs code
- self.projs_list.append(proj_code)
- cur_sel = self.params["srs"].GetStringSelection()
- self.projs_list = sorted(self.projs_list)
- self.params["srs"].SetItems(self.projs_list)
- if cur_sel:
- self.params["srs"].SetStringSelection(cur_sel)
- else:
- try:
- i = self.projs_list.index("EPSG:4326")
- self.params["srs"].SetSelection(i)
- except ValueError:
- if len(self.projs_list) > 0:
- self.params["srs"].SetSelection(0)
- # update format
- if "WMS" not in self.ws and "format" not in self.drv_props["ignored_params"]:
- self.formats_list = []
- cur_sel = None
- if self.params["format"]:
- cur_sel = self.params["format"].GetStringSelection()
- if len(curr_sel_ls) > 0:
- self.formats_list = sorted(
- self._getFormats(curr_sel_ls[0]["cap_intf_l"])
- )
- self._updateFormatRadioBox(self.formats_list)
- if cur_sel:
- if self.params["format"]:
- self.params["format"].SetStringSelection(cur_sel)
- else:
- self._setDefaultFormatVal()
- self.Layout()
- def _setDefaultFormatVal(self):
- """Set default format value."""
- try:
- i = self.formats_list.index("png")
- self.params["format"].SetSelection(i)
- except ValueError:
- pass
- def _updateFormatRadioBox(self, formats_list):
- """Helper function"""
- if self.params["format"]:
- self.req_page_sizer.Detach(self.params["format"])
- self.params["format"].Destroy()
- if len(self.formats_list) > 0:
- self.params["format"] = wx.RadioBox(
- parent=self.req_page_panel,
- id=wx.ID_ANY,
- label=_("Source image format"),
- pos=wx.DefaultPosition,
- choices=formats_list,
- majorDimension=4,
- style=wx.RA_SPECIFY_COLS,
- )
- self.source_sizer.Insert(
- 2,
- window=self.params["format"],
- flag=wx.LEFT | wx.RIGHT | wx.BOTTOM,
- border=5,
- )
- def _getFormats(self, layer=None):
- """Get formats
- WMS has formats defined generally for whole cap.
- In WMTS and NASA OnEarh formats are defined for layer.
- """
- formats_label = []
- if layer is None:
- formats_list = self.cap.GetFormats()
- else:
- formats_list = layer.GetLayerData("format")
- for frmt in formats_list:
- frmt = frmt.strip()
- label = self.drv_info.GetFormatLabel(frmt)
- if label:
- formats_label.append(label)
- return formats_label
- def _checkImportValues(
- self,
- ):
- """Check if required widgets are selected/filled"""
- warning_str = ""
- show_war = False
- if not self.list or not self.list.GetSelectedLayers():
- warning_str += _("Select layer in layer list.\n")
- show_war = True
- if (
- self.params["format"] is not None
- and self.params["format"].GetSelection() == -1
- ):
- warning_str += _("Select source image format.\n")
- show_war = True
- if self.params["srs"] is not None and self.params["srs"].GetSelection() == -1:
- warning_str += _("Select source projection.\n")
- show_war = True
- if not self.o_layer_name:
- warning_str += _("Choose output layer name.\n")
- show_war = True
- if show_war:
- GMessage(parent=self.parent, message=warning_str)
- return False
- return True
- def SetOutputLayerName(self, name):
- """Set name of layer to be added to layer tree"""
- self.o_layer_name = name
- def GetOutputLayerName(self):
- return self.o_layer_name
- def GetCapFile(self):
- """Get path to file where capabilities are saved"""
- return self.cap_file
- def GetWebService(self):
- """Get web service"""
- return self.ws
- class LayersList(TreeCtrl):
- 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
- TreeCtrl.__init__(self, parent=parent, id=wx.ID_ANY, style=style)
- self.root = None
- self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnListSelChanging)
- self.layerSelected = Signal("LayersList.layerSelected")
- 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):
- 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)
- self.SetItemData(
- style_item,
- {
- "type": "style",
- "layer": layer, # it is parent layer of style
- "style": st,
- },
- )
- self.SetItemData(
- 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.GetItemData(s)["layer"]
- except ValueError:
- continue
- sel_layers_dict.append(
- {
- "name": layer.GetLayerData("name"),
- "title": layer.GetLayerData("title"),
- "style": self.GetItemData(s)["style"],
- "cap_intf_l": layer,
- }
- )
- return sel_layers_dict
- def OnListSelChanging(self, event):
- """Do not allow selecting items, which cannot be requested from server."""
- def _emitSelected(layer):
- title = layer.GetLayerData("title")
- self.layerSelected.emit(title=title)
- def _selectRequestableChildren(item, list_to_check, items_to_sel):
- self.Expand(item)
- child_item, cookie = self.GetFirstChild(item)
- while child_item and child_item.IsOk():
- if self.GetItemData(child_item)[
- "layer"
- ].IsRequestable() and not self.IsSelected(child_item):
- items_to_sel.append(child_item)
- elif not self.GetItemData(child_item)["layer"].IsRequestable():
- list_to_check.append(child_item)
- child_item, cookie = self.GetNextChild(item, cookie)
- cur_item = event.GetItem()
- if not self.GetItemData(cur_item)["layer"].IsRequestable():
- event.Veto()
- if not self.HasFlag(wx.TR_MULTIPLE):
- return
- _emitSelected(self.GetItemData(cur_item)["layer"])
- items_to_chck = []
- items_to_sel = []
- chck_item = cur_item
- while True:
- _selectRequestableChildren(chck_item, items_to_chck, items_to_sel)
- if items_to_chck:
- chck_item = items_to_chck.pop()
- else:
- break
- while items_to_sel:
- self.SelectItem(items_to_sel.pop(), select=True)
- else:
- _emitSelected(self.GetItemData(cur_item)["layer"])
- 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(root_item, l_st_list, items_to_sel):
- def compare(item, l_name, st_name):
- it_l_name = self.GetItemData(item)["layer"].GetLayerData("name")
- it_st = self.GetItemData(item)["style"]
- it_type = self.GetItemData(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
- (child, cookie) = self.GetFirstChild(root_item)
- while child.IsOk():
- for i, l_st in enumerate(l_st_list):
- l_name = l_st["layer"]
- st_name = l_st["style"]
- if compare(child, l_name, st_name):
- items_to_sel[i] = [child, l_st]
- break
- if len(items_to_sel) == len(l_st_list):
- if self.ItemHasChildren(child):
- checknext(child, l_st_list, items_to_sel)
- child = self.GetNextSibling(child)
- 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)
- self.CollapseAll()
- # 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
- keep = False
- if self.HasFlag(wx.TR_MULTIPLE):
- keep = True
- self.SelectItem(item, select=keep)
- self.SetFocusedItem(item)
- self.Expand(item)
- l_st_list.remove(l_st)
- return l_st_list
- class WSManageSettingsWidget(ManageSettingsWidget):
- def __init__(self, parent, settingsFile, default_servers):
- ManageSettingsWidget.__init__(self, parent, settingsFile)
- self.default_servers = default_servers
- def _layout(self):
- self.btnAddDefaultServers = Button(
- parent=self, id=wx.ID_ANY, label=_("Add default")
- )
- self.btnAddDefaultServers.Bind(wx.EVT_BUTTON, self.OnAddDefaultServers)
- ManageSettingsWidget._layout(self)
- self.settingsSizer.Add(self.btnAddDefaultServers, flag=wx.RIGHT, border=5)
- def OnAddDefaultServers(self, event):
- setts = self.GetSettings()
- self.servers_to_add = {}
- for k, v in six.iteritems(self.default_servers):
- if k not in six.iterkeys(setts):
- self.servers_to_add[k] = v
- elif v != setts[k]:
- GMessage(
- parent=self,
- message=_(
- "User defined server with same name "
- "as default server <%s> already exists.\n"
- "Keeping user defined server"
- )
- % (k),
- )
- if self.servers_to_add:
- self.AddSettings(self.servers_to_add)
|