|
@@ -0,0 +1,972 @@
|
|
|
+"""!
|
|
|
+@package web_services.dialogs
|
|
|
+
|
|
|
+@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.
|
|
|
+
|
|
|
+@author Martin Landa <landa.martin gmail.com>
|
|
|
+@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)
|