class AttributeManager(wx.Frame, DbMgrBase): def __init__(self, parent, id=wx.ID_ANY, title=None, vectorName=None, item=None, log=None, selection=None, **kwargs): """GRASS Attribute Table Manager window :param parent: parent window :param id: window id :param title: window title or None for default title :param vectorName: name of vector map :param item: item from Layer Tree :param log: log window :param selection: name of page to be selected :param kwagrs: other wx.Frame's arguments """ self.parent = parent try: mapdisplay = self.parent.GetMapDisplay() except: mapdisplay = None DbMgrBase.__init__(self, id=id, mapdisplay=mapdisplay, vectorName=vectorName, item=item, log=log, statusbar=self, **kwargs) wx.Frame.__init__(self, parent, id, *kwargs) # title if not title: title = "%s" % _("GRASS GIS Attribute Table Manager - ") if not self.dbMgrData['editable']: title += _("READONLY - ") title += "<%s>" % (self.dbMgrData['vectName']) self.SetTitle(title) # icon self.SetIcon( wx.Icon(os.path.join(globalvar.ICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO)) self.panel = wx.Panel(parent=self, id=wx.ID_ANY) if len(self.dbMgrData['mapDBInfo'].layers.keys()) == 0: GMessage(parent=self.parent, message=_("Database connection for vector map <%s> " "is not defined in DB file. " "You can define new connection in " "'Manage layers' tab.") % self.dbMgrData['vectName']) busy = wx.BusyInfo(_("Please wait, loading attribute data..."), parent=self.parent) wx.SafeYield() self.CreateStatusBar(number=1) self.notebook = GNotebook(self.panel, style=globalvar.FNPageDStyle) self.CreateDbMgrPage(parent=self, pageName='browse') self.notebook.AddPage(page=self.pages['browse'], text=_("Browse data"), name='browse') self.pages['browse'].SetTabAreaColour(globalvar.FNPageColor) self.CreateDbMgrPage(parent=self, pageName='manageTable') self.notebook.AddPage(page=self.pages['manageTable'], text=_("Manage tables"), name='table') self.pages['manageTable'].SetTabAreaColour(globalvar.FNPageColor) self.CreateDbMgrPage(parent=self, pageName='manageLayer') self.notebook.AddPage(page=self.pages['manageLayer'], text=_("Manage layers"), name='layers') del busy if selection: wx.CallAfter(self.notebook.SetSelectionByName, selection) else: wx.CallAfter(self.notebook.SetSelection, 0) # select browse tab # buttons self.btnClose = CloseButton(parent=self.panel) self.btnClose.SetToolTip(_("Close Attribute Table Manager")) self.btnReload = Button(parent=self.panel, id=wx.ID_REFRESH) self.btnReload.SetToolTip( _("Reload currently selected attribute data")) self.btnReset = ClearButton(parent=self.panel) self.btnReset.SetToolTip( _("Reload all attribute data (drop current selection)")) # bind closing to ESC self.Bind(wx.EVT_MENU, self.OnCloseWindow, id=wx.ID_CANCEL) accelTableList = [(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, wx.ID_CANCEL)] accelTable = wx.AcceleratorTable(accelTableList) self.SetAcceleratorTable(accelTable) # events self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow) self.btnReload.Bind(wx.EVT_BUTTON, self.OnReloadData) self.btnReset.Bind(wx.EVT_BUTTON, self.OnReloadDataAll) self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) # do layout self._layout() # self.SetMinSize(self.GetBestSize()) self.SetSize((700, 550)) # FIXME hard-coded size self.SetMinSize(self.GetSize()) def _layout(self): """Do layout""" # frame body mainSizer = wx.BoxSizer(wx.VERTICAL) # buttons btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.Add(self.btnReset, proportion=1, flag=wx.ALL, border=5) btnSizer.Add(self.btnReload, proportion=1, flag=wx.ALL, border=5) btnSizer.Add(self.btnClose, proportion=1, flag=wx.ALL, border=5) mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND) mainSizer.Add(btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) self.panel.SetAutoLayout(True) self.panel.SetSizer(mainSizer) mainSizer.Fit(self.panel) self.Layout() def OnCloseWindow(self, event): """Cancel button pressed""" if self.parent and self.parent.GetName() == 'LayerManager': # deregister ATM self.parent.dialogs['atm'].remove(self) if not isinstance(event, wx.CloseEvent): self.Destroy() event.Skip() def OnReloadData(self, event): """Reload data""" if self.pages['browse']: self.pages['browse'].OnDataReload(event) # TODO replace by signal def OnReloadDataAll(self, event): """Reload all data""" if self.pages['browse']: self.pages['browse'].ResetPage() def OnPageChanged(self, event): """On page in ATM is changed""" try: if self.pages["browse"]: selPage = self.pages["browse"].selLayer id = self.pages["browse"].layerPage[selPage]['data'] else: id = None except KeyError: id = None if event.GetSelection() == self.notebook.GetPageIndexByName( 'browse') and id: win = self.FindWindowById(id) if win: self.log.write( _("Number of loaded records: %d") % win.GetItemCount()) else: self.log.write("") self.btnReload.Enable() self.btnReset.Enable() else: self.log.write("") self.btnReload.Enable(False) self.btnReset.Enable(False) event.Skip() def OnTextEnter(self, event): pass def UpdateDialog(self, layer): """Updates dialog layout for given layer""" DbMgrBase.UpdateDialog(self, layer=layer) # set current page selection self.notebook.SetSelectionByName('layers')
class WSPanel(wx.Panel): def __init__(self, parent, web_service, **kwargs): """Show data from capabilities file. Signal: capParsed - this signal is emitted when capabilities file is downloaded (after ConnectToServer method was called) :param parent: parent widget :param web_service: web service to be panel generated for """ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.parent = parent self.ws = web_service self.capParsed = Signal('WSPanel.capParsed') # stores widgets, which represents parameters/flags of d.wms self.params = {} self.flags = {} self.o_layer_name = '' # stores err output from r.in.wms during getting capabilities self.cmd_err_str = '' # stores selected layer from layer list self.sel_layers = [] # downloaded and parsed data from server successfully? self.is_connected = False # common part of command for r.in.wms -c and d.wms self.ws_cmdl = None # provides information about driver parameters self.drv_info = WMSDriversInfo() self.drv_props = self.drv_info.GetDrvProperties(self.ws) self.ws_drvs = { 'WMS_1.1.1': { 'cmd': [ 'wms_version=1.1.1', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.1.1'), }, 'WMS_1.3.0': { 'cmd': [ 'wms_version=1.3.0', 'driver=WMS_GRASS'], 'cap_parser': lambda temp_file: WMSCapabilities( temp_file, '1.3.0'), }, 'WMTS': { 'cmd': ['driver=WMTS_GRASS'], 'cap_parser': WMTSCapabilities, }, 'OnEarth': { 'cmd': ['driver=OnEarth_GRASS'], 'cap_parser': OnEarthCapabilities, }} self.cmdStdErr = GStderr(self) self.cmd_thread = CmdThread(self) self.cap_file = grass.tempfile() reqDataBox = StaticBox( parent=self, label=_(" Requested data settings ")) self._nb_sizer = wx.StaticBoxSizer(reqDataBox, wx.VERTICAL) self.notebook = GNotebook( parent=self, style=FN.FNB_FANCY_TABS | FN.FNB_NO_X_BUTTON | FN.FNB_NODRAG) self._requestPage() self._advancedSettsPage() self._layout() self.layerSelected = self.list.layerSelected self.Bind(EVT_CMD_DONE, self.OnCapDownloadDone) self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput) self.SetMinSize((-1, 300)) def __del__(self): self.cmd_thread.abort(abortall=True) grass.try_remove(self.cap_file) def _layout(self): self._nb_sizer.Add(self.notebook, proportion=1, flag=wx.EXPAND) self.SetSizer(self._nb_sizer) def _requestPage(self): """Create request page""" self.req_page_panel = wx.Panel(parent=self, id=wx.ID_ANY) self.notebook.AddPage(page=self.req_page_panel, text=_('Request'), name='request') # list of layers self.layersBox = StaticBox(parent=self.req_page_panel, id=wx.ID_ANY, label=_("List of layers ")) style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT if self.drv_props['req_multiple_layers']: style = style | wx.TR_MULTIPLE if 'WMS' not in self.ws: style = style | wx.TR_HIDE_ROOT self.list = LayersList(parent=self.req_page_panel, web_service=self.ws, style=style) self.params['format'] = None self.params['srs'] = None if 'srs' not in self.drv_props['ignored_params']: projText = StaticText( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source projection:")) self.params['srs'] = wx.Choice( parent=self.req_page_panel, id=wx.ID_ANY) self.list.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnListSelChanged) # layout self.req_page_sizer = wx.BoxSizer(wx.VERTICAL) layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL) layersSizer.Add( self.list, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_sizer.Add( layersSizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.source_sizer = wx.BoxSizer(wx.HORIZONTAL) if self.params['format'] is not None: self.source_sizer.Add( self.params['format'], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) if self.params['srs'] is not None: self.source_sizer.Add( projText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5) self.source_sizer.Add( self.params['srs'], flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5) self.req_page_sizer.Add( self.source_sizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) self.req_page_panel.SetSizer(self.req_page_sizer) def enableButtons(self, enable=True): """Enable/disable up, down, buttons """ self.btnUp.Enable(enable) self.btnDown.Enable(enable) def _advancedSettsPage(self): """Create advanced settings page """ # TODO parse maxcol, maxrow, settings from d.wms module? # TODO OnEarth driver - add selection of time adv_setts_panel = ScrolledPanel(parent=self, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER) self.notebook.AddPage(page=adv_setts_panel, text=_('Advanced request settings'), name='adv_req_setts') labels = {} self.l_odrder_list = None if 'WMS' in self.ws: labels['l_order'] = StaticBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Order of layers in raster")) self.l_odrder_list = wx.ListBox( adv_setts_panel, id=wx.ID_ANY, choices=[], style=wx.LB_SINGLE | wx.LB_NEEDED_SB) self.btnUp = Button( adv_setts_panel, id=wx.ID_ANY, label=_("Up")) self.btnDown = Button( adv_setts_panel, id=wx.ID_ANY, label=_("Down")) self.btnUp.Bind(wx.EVT_BUTTON, self.OnUp) self.btnDown.Bind(wx.EVT_BUTTON, self.OnDown) labels['method'] = StaticText(parent=adv_setts_panel, id=wx.ID_ANY, label=_("Reprojection method:")) self.reproj_methods = ['nearest', 'linear', 'cubic', 'cubicspline'] self.params['method'] = wx.Choice( parent=adv_setts_panel, id=wx.ID_ANY, choices=[ _('Nearest neighbor'), _('Linear interpolation'), _('Cubic interpolation'), _('Cubic spline interpolation')]) labels['maxcols'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum columns to request from server at time:")) self.params['maxcols'] = SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) labels['maxrows'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Maximum rows to request from server at time:")) self.params['maxrows'] = SpinCtrl( parent=adv_setts_panel, id=wx.ID_ANY, size=(100, -1)) min = 100 max = 10000 self.params['maxcols'].SetRange(min, max) self.params['maxrows'].SetRange(min, max) val = 500 self.params['maxcols'].SetValue(val) self.params['maxrows'].SetValue(val) self.flags['o'] = self.params['bgcolor'] = None if 'o' not in self.drv_props['ignored_flags']: self.flags['o'] = wx.CheckBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Do not request transparent data")) self.flags['o'].Bind(wx.EVT_CHECKBOX, self.OnTransparent) labels['bgcolor'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Background color:")) self.params['bgcolor'] = csel.ColourSelect( parent=adv_setts_panel, id=wx.ID_ANY, colour=( 255, 255, 255), size=globalvar.DIALOG_COLOR_SIZE) self.params['bgcolor'].Enable(False) self.params['urlparams'] = None if self.params['urlparams'] not in self.drv_props['ignored_params']: labels['urlparams'] = StaticText( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Additional query parameters for server:")) self.params['urlparams'] = TextCtrl( parent=adv_setts_panel, id=wx.ID_ANY) # layout border = wx.BoxSizer(wx.VERTICAL) if 'WMS' in self.ws: boxSizer = wx.StaticBoxSizer(labels['l_order'], wx.VERTICAL) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) gridSizer.Add(self.l_odrder_list, pos=(0, 0), span=(4, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0) gridSizer.Add(self.btnUp, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.Add(self.btnDown, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL, border=0) gridSizer.AddGrowableCol(0) boxSizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5) border.Add(boxSizer, flag=wx.LEFT | wx.RIGHT | wx.UP | wx.EXPAND, border=5) gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 for k in ['method', 'maxcols', 'maxrows', 'o', 'bgcolor']: if k in self.params: param = self.params[k] elif k in self.flags: param = self.flags[k] if param is None: continue if k in labels or k == 'o': if k != 'o': label = labels[k] else: label = param gridSizer.Add(label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) if k != 'o': gridSizer.Add(param, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 1)) row += 1 gridSizer.AddGrowableCol(0) border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) if self.params['urlparams']: gridSizer = wx.GridBagSizer(hgap=3, vgap=3) row = 0 gridSizer.Add(labels['urlparams'], flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0)) gridSizer.Add(self.params['urlparams'], flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos=(row, 1)) gridSizer.AddGrowableCol(1) border.Add(gridSizer, flag=wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, border=5) adv_setts_panel.SetSizer(border) adv_setts_panel.SetAutoLayout(True) adv_setts_panel.SetupScrolling() def OnUp(self, event): """Move selected layer up """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos: self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos)) if pos > 0: self._updateLayerOrderList(selected=(pos - 1)) else: self._updateLayerOrderList(selected=0) def OnDown(self, event): """Move selected to down """ if self.l_odrder_list.GetSelections(): pos = self.l_odrder_list.GetSelection() if pos != len(self.sel_layers) - 1: self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos)) if pos < len(self.sel_layers) - 1: self._updateLayerOrderList(selected=(pos + 1)) else: self._updateLayerOrderList(selected=len(self.sel_layers) - 1) def _updateLayerOrderList(self, selected=None): """Update order in list. """ def getlayercaption(l): if l['title']: cap = (l['title']) else: cap = (l['name']) if l['style']: if l['style']['title']: cap += ' / ' + l['style']['title'] else: cap += ' / ' + l['style']['name'] return cap layer_capts = [getlayercaption(l) for l in self.sel_layers] self.l_odrder_list.Set(layer_capts) if self.l_odrder_list.IsEmpty(): self.enableButtons(False) else: self.enableButtons(True) if selected is not None: self.l_odrder_list.SetSelection(selected) self.l_odrder_list.EnsureVisible(selected) def OnTransparent(self, event): checked = event.IsChecked() if checked: self.params['bgcolor'].Enable(True) else: self.params['bgcolor'].Enable(False) def ConnectToServer(self, url, username, password): """Download and parse data from capabilities file. :param url: server url :type url: str :param username: username for connection :type username: str :param password: password for connection :type password: str """ self._prepareForNewConn(url, username, password) cap_cmd = [ 'r.in.wms', '-c', ('capfile_output=%s' % self.cap_file), '--overwrite'] + self.ws_cmdl self.currentPid = self.cmd_thread.GetId() self.cmd_thread.RunCmd(cap_cmd, stderr=self.cmdStdErr) def OnCmdOutput(self, event): """Manage cmd output. """ if Debug.GetLevel() != 0: Debug.msg(1, event.text) elif event.type != 'message' and event.type != 'warning': self.cmd_err_str += event.text + os.linesep def _prepareForNewConn(self, url, username, password): """Prepare panel for new connection """ self.is_connected = False self.sel_layers = [] self.formats_list = [] self.projs_list = [] self.conn = { 'url': url, 'password': password, 'username': username } conn_cmd = [] for k, v in six.iteritems(self.conn): if v: conn_cmd.append("%s=%s" % (k, v)) self.ws_cmdl = self.ws_drvs[self.ws]['cmd'] + conn_cmd def OnCapDownloadDone(self, event): """Process donwloaded capabilities file and emits capParsed signal (see class constructor). """ if event.pid != self.currentPid: return if event.returncode != 0: if self.cmd_err_str: self.cmd_err_str = _( "Unable to download %s capabilities file\nfrom <%s>:\n" % (self.ws.replace('_', ' '), self.conn['url'])) + self.cmd_err_str self._postCapParsedEvt(error_msg=self.cmd_err_str) self.cmd_err_str = '' return self._parseCapFile(self.cap_file) def _parseCapFile(self, cap_file): """Parse capabilities data and emits capParsed signal (see class constructor). """ try: self.cap = self.ws_drvs[self.ws]['cap_parser'](cap_file) except (IOError, ParseError) as error: error_msg = _( "%s web service was not found in fetched capabilities file from <%s>:\n%s\n" % (self.ws, self.conn['url'], str(error))) if Debug.GetLevel() != 0: Debug.msg(1, error_msg) self._postCapParsedEvt(None) else: self._postCapParsedEvt(error_msg=error_msg) return self.is_connected = True # WMS standard has formats defined for all layers if 'WMS' in self.ws: self.formats_list = sorted(self._getFormats()) self._updateFormatRadioBox(self.formats_list) self._setDefaultFormatVal() self.list.LoadData(self.cap) self.OnListSelChanged(event=None) self._postCapParsedEvt(None) def ParseCapFile(self, url, username, password, cap_file=None,): """Parse capabilities data and emits capParsed signal (see class constructor). """ self._prepareForNewConn(url, username, password) if cap_file is None or not url: self._postCapParsedEvt(None) return shutil.copyfile(cap_file, self.cap_file) self._parseCapFile(self.cap_file) def UpdateWidgetsByCmd(self, cmd): """Update panel widgets accordnig to passed cmd tuple :param cmd: cmd in tuple """ dcmd = cmd[1] layers = [] if 'layers' in dcmd: layers = dcmd['layers'] styles = [] if 'styles' in dcmd: styles = dcmd['styles'] if 'WMS' in self.ws: layers = layers.split(',') styles = styles.split(',') else: layers = [layers] styles = [styles] if len(layers) != len(styles): styles = [''] * len(layers) l_st_list = [] for i in range(len(layers)): l_st_list.append({'style': styles[i], 'layer': layers[i]}) # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed l_st_list = [l for l in reversed(l_st_list)] self.list.SelectLayers(l_st_list) params = {} if 'format' in dcmd: params['format'] = dcmd['format'] if 'srs' in dcmd: params['srs'] = 'EPSG:' + dcmd['srs'] if 'method' in dcmd: params['method'] = dcmd['method'] for p, v in six.iteritems(params): if self.params[p]: self.params[p].SetStringSelection(v) for p, conv_f in [ ('urlparams', None), ('maxcols', int), ('maxrows', int)]: if p in dcmd: v = dcmd[p] if conv_f: v = conv_f(v) self.params[p].SetValue(v) if 'flags' in dcmd and \ 'o' in dcmd['flags']: self.flags['o'].SetValue(1) self.params['bgcolor'].Enable(True) if 'bgcolor' in dcmd and \ self.params['bgcolor']: bgcolor = dcmd['bgcolor'].strip().lower() if len(bgcolor) == 8 and \ '0x' == bgcolor[:2]: colour = '#' + bgcolor[2:] self.params['bgcolor'].SetColour(colour) def IsConnected(self): """Was successful in downloading and parsing capabilities data? """ return self.is_connected def _postCapParsedEvt(self, error_msg): """Helper function """ self.capParsed.emit(error_msg=error_msg) def CreateCmd(self): """Create d.wms cmd from values of panels widgets :return: cmd list :return: None if required widgets do not have selected/filled values. """ # check required widgets if not self._checkImportValues(): return None # create d.wms command lcmd = self.ws_cmdl lcmd = ['d.wms'] + lcmd layers = "layers=" styles = 'styles=' first = True # WMS standard - first layer in params is most bottom... # therefore layers order need to be reversed for layer in reversed(self.sel_layers): if not first: layers += ',' styles += ',' first = False layers += layer['name'] if layer['style'] is not None: styles += layer['style']['name'] lcmd.append(layers) lcmd.append(styles) if 'format' not in self.drv_props['ignored_params']: i_format = self.params['format'].GetSelection() lcmd.append("format=%s" % self.formats_list[i_format]) if 'srs' not in self.drv_props['ignored_params']: i_srs = self.params['srs'].GetSelection() srs = self.projs_list[i_srs].split(':')[-1] epsg_num = int(''.join(re.findall(r'\d+', srs))) lcmd.append("srs=%s" % epsg_num) for k in ['maxcols', 'maxrows', 'urlparams']: lcmd.append(k + '=' + str(self.params[k].GetValue())) i_method = self.params['method'].GetSelection() lcmd.append('method=' + self.reproj_methods[i_method]) if 'o' not in self.drv_props['ignored_flags'] and \ self.flags['o'].IsChecked(): lcmd.append('-o') c = self.params['bgcolor'].GetColour() hex_color = wx.Colour( c[0], c[1], c[2]).GetAsString( wx.C2S_HTML_SYNTAX) lcmd.append("bgcolor=" + '0x' + hex_color[1:]) lcmd.append("map=" + self.o_layer_name) return lcmd def OnListSelChanged(self, event): """Update widgets according to selected layer in list. """ curr_sel_ls = self.list.GetSelectedLayers() # update self.sel_layers (selected layer list) if 'WMS' in self.ws: for sel_l in self.sel_layers[:]: if sel_l not in curr_sel_ls: self.sel_layers.remove(sel_l) for l in curr_sel_ls: if l not in self.sel_layers: self.sel_layers.append(l) self._updateLayerOrderList() else: self.sel_layers = curr_sel_ls # update projection self.projs_list = [] projs_list = [] intersect_proj = [] first = True for l in curr_sel_ls: layer_projs = l['cap_intf_l'].GetLayerData('srs') if first: projs_list = layer_projs first = False continue projs_list = set(projs_list).intersection(layer_projs) if 'srs' not in self.drv_props['ignored_params']: for proj in projs_list: proj_code = Srs(proj.strip()).getcode() proj_spl = proj_code.split(':') if proj_spl[0].strip().lower() in self.drv_info.GetSrs(): # accept ogc:crs code self.projs_list.append(proj_code) cur_sel = self.params['srs'].GetStringSelection() self.projs_list = sorted(self.projs_list) self.params['srs'].SetItems(self.projs_list) if cur_sel: self.params['srs'].SetStringSelection(cur_sel) else: try: i = self.projs_list.index('EPSG:4326') self.params['srs'].SetSelection(i) except ValueError: if len(self.projs_list) > 0: self.params['srs'].SetSelection(0) # update format if 'WMS' not in self.ws and \ 'format' not in self.drv_props['ignored_params']: self.formats_list = [] cur_sel = None if self.params['format']: cur_sel = self.params['format'].GetStringSelection() if len(curr_sel_ls) > 0: self.formats_list = sorted( self._getFormats( curr_sel_ls[0]['cap_intf_l'])) self._updateFormatRadioBox(self.formats_list) if cur_sel: if self.params['format']: self.params['format'].SetStringSelection(cur_sel) else: self._setDefaultFormatVal() self.Layout() def _setDefaultFormatVal(self): """Set default format value. """ try: i = self.formats_list.index('png') self.params['format'].SetSelection(i) except ValueError: pass def _updateFormatRadioBox(self, formats_list): """Helper function """ if self.params['format']: self.req_page_sizer.Detach(self.params['format']) self.params['format'].Destroy() if len(self.formats_list) > 0: self.params['format'] = wx.RadioBox( parent=self.req_page_panel, id=wx.ID_ANY, label=_("Source image format"), pos=wx.DefaultPosition, choices=formats_list, majorDimension=4, style=wx.RA_SPECIFY_COLS) self.source_sizer.Insert(2, window=self.params['format'], flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) def _getFormats(self, layer=None): """Get formats WMS has formats defined generally for whole cap. In WMTS and NASA OnEarh formats are defined for layer. """ formats_label = [] if layer is None: formats_list = self.cap.GetFormats() else: formats_list = layer.GetLayerData('format') for frmt in formats_list: frmt = frmt.strip() label = self.drv_info.GetFormatLabel(frmt) if label: formats_label.append(label) return formats_label def _checkImportValues(self,): """Check if required widgets are selected/filled """ warning_str = "" show_war = False if not self.list or not self.list.GetSelectedLayers(): warning_str += _("Select layer in layer list.\n") show_war = True if self.params['format'] is not None and \ self.params['format'].GetSelection() == -1: warning_str += _("Select source image format.\n") show_war = True if self.params['srs'] is not None and \ self.params['srs'].GetSelection() == -1: warning_str += _("Select source projection.\n") show_war = True if not self.o_layer_name: warning_str += _("Choose output layer name.\n") show_war = True if show_war: GMessage(parent=self.parent, message=warning_str) return False return True def SetOutputLayerName(self, name): """Set name of layer to be added to layer tree """ self.o_layer_name = name def GetOutputLayerName(self): return self.o_layer_name def GetCapFile(self): """Get path to file where capabilities are saved """ return self.cap_file def GetWebService(self): """Get web service """ return self.ws
class TplotFrame(wx.Frame): """The main frame of the application""" def __init__(self, parent, giface): wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=_("GRASS GIS Temporal Plot Tool")) tgis.init(True) self._giface = giface self.datasetsV = None self.datasetsR = None # self.vectorDraw=False # self.rasterDraw=False self.init() self._layout() # We create a database interface here to speedup the GUI self.dbif = tgis.SQLDatabaseInterfaceConnection() self.dbif.connect() self.Bind(wx.EVT_CLOSE, self.onClose) self.region = Region() def init(self): self.timeDataR = OrderedDict() self.timeDataV = OrderedDict() self.temporalType = None self.unit = None self.listWhereConditions = [] self.plotNameListR = [] self.plotNameListV = [] self.poi = None def __del__(self): """Close the database interface and stop the messenger and C-interface subprocesses. """ if self.dbif.connected is True: self.dbif.close() tgis.stop_subprocesses() def onClose(self, evt): if self._giface.GetMapDisplay(): self.coorval.OnClose() self.cats.OnClose() self.__del__() self.Destroy() def _layout(self): """Creates the main panel with all the controls on it: * mpl canvas * mpl navigation toolbar * Control panel for interaction """ self.mainPanel = wx.Panel(self) # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # # color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) # ------------CANVAS AND TOOLBAR------------ self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1)) self.canvas = FigCanvas(self.mainPanel, wx.ID_ANY, self.fig) # axes are initialized later self.axes2d = None self.axes3d = None # Create the navigation toolbar, tied to the canvas # self.toolbar = NavigationToolbar(self.canvas) # # Layout # # ------------MAIN VERTICAL SIZER------------ self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND) self.vbox.Add(self.toolbar, 0, wx.EXPAND) # self.vbox.AddSpacer(10) # ------------ADD NOTEBOOK------------ self.ntb = GNotebook(parent=self.mainPanel, style=FN.FNB_FANCY_TABS) # ------------ITEMS IN NOTEBOOK PAGE (RASTER)------------------------ self.controlPanelRaster = wx.Panel(parent=self.ntb, id=wx.ID_ANY) self.datasetSelectLabelR = wx.StaticText( parent=self.controlPanelRaster, id=wx.ID_ANY, label=_('Raster temporal ' 'dataset (strds)')) self.datasetSelectR = gselect.Select( parent=self.controlPanelRaster, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type='strds', multiple=True) self.coor = wx.StaticText(parent=self.controlPanelRaster, id=wx.ID_ANY, label=_('X and Y coordinates separated by ' 'comma:')) try: self._giface.GetMapWindow() self.coorval = gselect.CoordinatesSelect( parent=self.controlPanelRaster, giface=self._giface) except: self.coorval = wx.TextCtrl(parent=self.controlPanelRaster, id=wx.ID_ANY, size=globalvar.DIALOG_TEXTCTRL_SIZE, validator=CoordinatesValidator()) self.coorval.SetToolTipString( _("Coordinates can be obtained for example" " by right-clicking on Map Display.")) self.controlPanelSizerRaster = wx.BoxSizer(wx.VERTICAL) # self.controlPanelSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY, # label=_("Select space time raster dataset(s):")), # pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) self.controlPanelSizerRaster.Add(self.datasetSelectLabelR, flag=wx.EXPAND) self.controlPanelSizerRaster.Add(self.datasetSelectR, flag=wx.EXPAND) self.controlPanelSizerRaster.Add(self.coor, flag=wx.EXPAND) self.controlPanelSizerRaster.Add(self.coorval, flag=wx.EXPAND) self.controlPanelRaster.SetSizer(self.controlPanelSizerRaster) self.controlPanelSizerRaster.Fit(self) self.ntb.AddPage(page=self.controlPanelRaster, text=_('STRDS'), name='STRDS') # ------------ITEMS IN NOTEBOOK PAGE (VECTOR)------------------------ self.controlPanelVector = wx.Panel(parent=self.ntb, id=wx.ID_ANY) self.datasetSelectLabelV = wx.StaticText( parent=self.controlPanelVector, id=wx.ID_ANY, label=_('Vector temporal ' 'dataset (stvds)\n' 'Press ENTER if you' ' type the name of the' ' stvds instead of' ' selecting with the' ' combobox')) self.datasetSelectV = gselect.Select( parent=self.controlPanelVector, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type='stvds', multiple=True) self.datasetSelectV.Bind(wx.EVT_TEXT, self.OnVectorSelected) self.attribute = gselect.ColumnSelect(parent=self.controlPanelVector) self.attributeLabel = wx.StaticText(parent=self.controlPanelVector, id=wx.ID_ANY, label=_('Select attribute column')) # TODO fix the category selection as done for coordinates try: self._giface.GetMapWindow() self.cats = gselect.VectorCategorySelect( parent=self.controlPanelVector, giface=self._giface) except: self.cats = wx.TextCtrl(parent=self.controlPanelVector, id=wx.ID_ANY, size=globalvar.DIALOG_TEXTCTRL_SIZE) self.catsLabel = wx.StaticText(parent=self.controlPanelVector, id=wx.ID_ANY, label=_('Select category of vector(s)')) self.controlPanelSizerVector = wx.BoxSizer(wx.VERTICAL) # self.controlPanelSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY, # label=_("Select space time raster dataset(s):")), # pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) self.controlPanelSizerVector.Add(self.datasetSelectLabelV, flag=wx.EXPAND) self.controlPanelSizerVector.Add(self.datasetSelectV, flag=wx.EXPAND) self.controlPanelSizerVector.Add(self.attributeLabel, flag=wx.EXPAND) self.controlPanelSizerVector.Add(self.attribute, flag=wx.EXPAND) self.controlPanelSizerVector.Add(self.catsLabel, flag=wx.EXPAND) self.controlPanelSizerVector.Add(self.cats, flag=wx.EXPAND) self.controlPanelVector.SetSizer(self.controlPanelSizerVector) self.controlPanelSizerVector.Fit(self) self.ntb.AddPage(page=self.controlPanelVector, text=_('STVDS'), name='STVDS') # ------------Buttons on the bottom(draw,help)------------ self.vButtPanel = wx.Panel(self.mainPanel, id=wx.ID_ANY) self.vButtSizer = wx.BoxSizer(wx.HORIZONTAL) self.drawButton = wx.Button(self.vButtPanel, id=wx.ID_ANY, label=_("Draw")) self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw) self.helpButton = wx.Button(self.vButtPanel, id=wx.ID_ANY, label=_("Help")) self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp) self.vButtSizer.Add(self.drawButton) self.vButtSizer.Add(self.helpButton) self.vButtPanel.SetSizer(self.vButtSizer) self.mainPanel.SetSizer(self.vbox) self.vbox.Add(self.ntb, flag=wx.EXPAND) self.vbox.Add(self.vButtPanel, flag=wx.EXPAND) self.vbox.Fit(self) self.mainPanel.Fit() def _getSTRDdata(self, timeseries): """Load data and read properties :param list timeseries: a list of timeseries """ if not self.poi: GError(parent=self, message=_("Invalid input coordinates"), showTraceback=False) return mode = None unit = None columns = ','.join(['name', 'start_time', 'end_time']) for series in timeseries: name = series[0] fullname = name + '@' + series[1] etype = series[2] sp = tgis.dataset_factory(etype, fullname) if not sp.is_in_db(dbif=self.dbif): GError(message=_("Dataset <%s> not found in temporal " "database") % (fullname), parent=self) return sp.select(dbif=self.dbif) minmin = sp.metadata.get_min_min() self.plotNameListR.append(name) self.timeDataR[name] = OrderedDict() self.timeDataR[name]['temporalDataType'] = etype self.timeDataR[name]['temporalType'] = sp.get_temporal_type() self.timeDataR[name]['granularity'] = sp.get_granularity() if mode is None: mode = self.timeDataR[name]['temporalType'] elif self.timeDataR[name]['temporalType'] != mode: GError(parent=self, message=_("Datasets have different temporal" " type (absolute x relative), " "which is not allowed.")) return # check topology maps = sp.get_registered_maps_as_objects(dbif=self.dbif) self.timeDataR[name]['validTopology'] = sp.check_temporal_topology( maps=maps, dbif=self.dbif) self.timeDataR[name]['unit'] = None # only with relative if self.timeDataR[name]['temporalType'] == 'relative': start, end, self.timeDataR[name][ 'unit'] = sp.get_relative_time() if unit is None: unit = self.timeDataR[name]['unit'] elif self.timeDataR[name]['unit'] != unit: GError(parent=self, message=_("Datasets have different " "time unit which is not " "allowed.")) return rows = sp.get_registered_maps(columns=columns, where=None, order='start_time', dbif=self.dbif) for row in rows: self.timeDataR[name][row[0]] = {} self.timeDataR[name][row[0]]['start_datetime'] = row[1] self.timeDataR[name][row[0]]['end_datetime'] = row[2] r = RasterRow(row[0]) r.open() val = r.get_value(self.poi) r.close() if val == -2147483648 and val < minmin: self.timeDataR[name][row[0]]['value'] = None else: self.timeDataR[name][row[0]]['value'] = val self.unit = unit self.temporalType = mode return def _parseVDbConn(self, mapp, layerInp): '''find attribute key according to layer of input map''' vdb = Module('v.db.connect', map=mapp, flags='g', stdout_=PIPE) vdb = vdb.outputs.stdout for line in vdb.splitlines(): lsplit = line.split('|') layer = lsplit[0].split('/')[0] if str(layer) == str(layerInp): return lsplit[2] return None def _getExistingCategories(self, mapp, cats): """Get a list of categories for a vector map""" vdb = grass.read_command('v.category', input=mapp, option='print') categories = vdb.splitlines() for cat in cats: if str(cat) not in categories: GMessage(message=_("Category {ca} is not on vector map" " {ma} and it will be not used").format( ma=mapp, ca=cat), parent=self) cats.remove(cat) return cats def _getSTVDData(self, timeseries): """Load data and read properties :param list timeseries: a list of timeseries """ mode = None unit = None cats = None attribute = self.attribute.GetValue() if self.cats.GetValue() != '': cats = self.cats.GetValue().split(',') if cats and self.poi: GMessage(message=_("Both coordinates and categories are set, " "coordinates will be used. The use categories " "remove text from coordinate form")) if not attribute or attribute == '': GError(parent=self, showTraceback=False, message=_("With Vector temporal dataset you have to select" " an attribute column")) return columns = ','.join(['name', 'start_time', 'end_time', 'id', 'layer']) for series in timeseries: name = series[0] fullname = name + '@' + series[1] etype = series[2] sp = tgis.dataset_factory(etype, fullname) if not sp.is_in_db(dbif=self.dbif): GError(message=_("Dataset <%s> not found in temporal " "database") % (fullname), parent=self, showTraceback=False) return sp.select(dbif=self.dbif) rows = sp.get_registered_maps(dbif=self.dbif, order="start_time", columns=columns, where=None) self.timeDataV[name] = OrderedDict() self.timeDataV[name]['temporalDataType'] = etype self.timeDataV[name]['temporalType'] = sp.get_temporal_type() self.timeDataV[name]['granularity'] = sp.get_granularity() if mode is None: mode = self.timeDataV[name]['temporalType'] elif self.timeDataV[name]['temporalType'] != mode: GError(parent=self, showTraceback=False, message=_( "Datasets have different temporal type (" "absolute x relative), which is not allowed.")) return self.timeDataV[name]['unit'] = None # only with relative if self.timeDataV[name]['temporalType'] == 'relative': start, end, self.timeDataV[name][ 'unit'] = sp.get_relative_time() if unit is None: unit = self.timeDataV[name]['unit'] elif self.timeDataV[name]['unit'] != unit: GError(message=_("Datasets have different time unit which" " is not allowed."), parent=self, showTraceback=False) return if self.poi: self.plotNameListV.append(name) # TODO set an appropriate distance, right now a big one is set # to return the closer point to the selected one out = grass.vector_what(map='pois_srvds', coord=self.poi.coords(), distance=10000000000000000) if len(out) != len(rows): GError(parent=self, showTraceback=False, message=_("Difference number of vector layers and " "maps in the vector temporal dataset")) return for i in range(len(rows)): row = rows[i] values = out[i] if str(row['layer']) == str(values['Layer']): lay = "{map}_{layer}".format(map=row['name'], layer=values['Layer']) self.timeDataV[name][lay] = {} self.timeDataV[name][lay]['start_datetime'] = row[ 'start_time'] self.timeDataV[name][lay]['end_datetime'] = row[ 'start_time'] self.timeDataV[name][lay]['value'] = values[ 'Attributes'][attribute] else: wherequery = '' cats = self._getExistingCategories(rows[0]['name'], cats) totcat = len(cats) ncat = 1 for cat in cats: if ncat == 1 and totcat != 1: wherequery += '{k}={c} or'.format(c=cat, k="{key}") elif ncat == 1 and totcat == 1: wherequery += '{k}={c}'.format(c=cat, k="{key}") elif ncat == totcat: wherequery += ' {k}={c}'.format(c=cat, k="{key}") else: wherequery += ' {k}={c} or'.format(c=cat, k="{key}") catn = "cat{num}".format(num=cat) self.plotNameListV.append("{na}+{cat}".format(na=name, cat=catn)) self.timeDataV[name][catn] = OrderedDict() ncat += 1 for row in rows: lay = int(row['layer']) catkey = self._parseVDbConn(row['name'], lay) if not catkey: GError(parent=self, showTraceback=False, message=_( "No connection between vector map {vmap} " "and layer {la}".format(vmap=row['name'], la=lay))) return vals = grass.vector_db_select( map=row['name'], layer=lay, where=wherequery.format(key=catkey), columns=attribute) layn = "lay{num}".format(num=lay) for cat in cats: catn = "cat{num}".format(num=cat) if layn not in self.timeDataV[name][catn].keys(): self.timeDataV[name][catn][layn] = {} self.timeDataV[name][catn][layn][ 'start_datetime'] = row['start_time'] self.timeDataV[name][catn][layn]['end_datetime'] = row[ 'end_time'] self.timeDataV[name][catn][layn]['value'] = vals[ 'values'][int(cat)][0] self.unit = unit self.temporalType = mode return def _drawFigure(self): """Draws or print 2D plot (temporal extents)""" self.axes2d.clear() self.axes2d.grid(False) if self.temporalType == 'absolute': self.axes2d.xaxis_date() self.fig.autofmt_xdate() self.convert = mdates.date2num self.invconvert = mdates.num2date else: self.convert = lambda x: x self.invconvert = self.convert self.colors = cycle(COLORS) self.yticksNames = [] self.yticksPos = [] self.plots = [] if self.datasetsR: self.lookUp = LookUp(self.timeDataR, self.invconvert) else: self.lookUp = LookUp(self.timeDataV, self.invconvert) if self.datasetsR: self.drawR() if self.datasetsV: if self.poi: self.drawV() elif self.cats: self.drawVCats() self.canvas.draw() DataCursor(self.plots, self.lookUp, InfoFormat, self.convert) def drawR(self): for i, name in enumerate(self.datasetsR): name = name[0] # just name; with mapset it would be long self.yticksNames.append(name) self.yticksPos.append(1) # TODO xdata = [] ydata = [] for keys, values in self.timeDataR[name].iteritems(): if keys in [ 'temporalType', 'granularity', 'validTopology', 'unit', 'temporalDataType' ]: continue xdata.append(self.convert(values['start_datetime'])) ydata.append(values['value']) if len(ydata) == ydata.count(None): GError(parent=self, showTraceback=False, message=_("Problem getting data from raster temporal" " dataset. Empty list of values.")) return self.lookUp.AddDataset(yranges=ydata, xranges=xdata, datasetName=name) color = self.colors.next() self.plots.append( self.axes2d.plot(xdata, ydata, marker='o', color=color, label=self.plotNameListR[i])[0]) if self.temporalType == 'absolute': self.axes2d.set_xlabel( _("Temporal resolution: %s" % self.timeDataR[name]['granularity'])) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) self.axes2d.set_ylabel(', '.join(self.yticksNames)) # legend handles, labels = self.axes2d.get_legend_handles_labels() self.axes2d.legend(loc=0) def drawVCats(self): for i, name in enumerate(self.plotNameListV): # just name; with mapset it would be long labelname = name.replace('+', ' ') self.yticksNames.append(labelname) name_cat = name.split('+') name = name_cat[0] self.yticksPos.append(1) # TODO xdata = [] ydata = [] for keys, values in self.timeDataV[name_cat[0]][ name_cat[1]].iteritems(): if keys in [ 'temporalType', 'granularity', 'validTopology', 'unit', 'temporalDataType' ]: continue xdata.append(self.convert(values['start_datetime'])) ydata.append(values['value']) if len(ydata) == ydata.count(None): GError(parent=self, showTraceback=False, message=_("Problem getting data from raster temporal" " dataset. Empty list of values.")) return self.lookUp.AddDataset(yranges=ydata, xranges=xdata, datasetName=name) color = self.colors.next() self.plots.append( self.axes2d.plot(xdata, ydata, marker='o', color=color, label=labelname)[0]) # ============================ if self.temporalType == 'absolute': self.axes2d.set_xlabel( _("Temporal resolution: %s" % self.timeDataV[name]['granularity'])) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) self.axes2d.set_ylabel(', '.join(self.yticksNames)) # legend handles, labels = self.axes2d.get_legend_handles_labels() self.axes2d.legend(loc=0) self.listWhereConditions = [] def drawV(self): for i, name in enumerate(self.plotNameListV): # just name; with mapset it would be long self.yticksNames.append(self.attribute.GetValue()) self.yticksPos.append(0) # TODO xdata = [] ydata = [] for keys, values in self.timeDataV[name].iteritems(): if keys in [ 'temporalType', 'granularity', 'validTopology', 'unit', 'temporalDataType' ]: continue xdata.append(self.convert(values['start_datetime'])) ydata.append(values['value']) if len(ydata) == ydata.count(None): GError(parent=self, showTraceback=False, message=_("Problem getting data from raster temporal" " dataset. Empty list of values.")) return self.lookUp.AddDataset(yranges=ydata, xranges=xdata, datasetName=name) color = self.colors.next() self.plots.append( self.axes2d.plot(xdata, ydata, marker='o', color=color, label=name)[0]) # ============================ if self.temporalType == 'absolute': self.axes2d.set_xlabel( _("Temporal resolution: %s" % self.timeDataV[name]['granularity'])) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) self.axes2d.set_ylabel(', '.join(self.yticksNames)) # legend handles, labels = self.axes2d.get_legend_handles_labels() self.axes2d.legend(loc=0) self.listWhereConditions = [] def OnRedraw(self, event=None): """Required redrawing.""" self.init() datasetsR = self.datasetSelectR.GetValue().strip() datasetsV = self.datasetSelectV.GetValue().strip() if not datasetsR and not datasetsV: return try: getcoors = self.coorval.coordsField.GetValue() except: try: getcoors = self.coorval.GetValue() except: getcoors = None if getcoors and getcoors != '': try: coordx, coordy = getcoors.split(',') coordx, coordy = float(coordx), float(coordy) except (ValueError, AttributeError): try: coordx, coordy = self.coorval.GetValue().split(',') coordx, coordy = float(coordx), float(coordy) except (ValueError, AttributeError): GMessage(message=_("Incorrect coordinates format, should " "be: x,y"), parent=self) coors = [coordx, coordy] if coors: try: self.poi = Point(float(coors[0]), float(coors[1])) except GException: GError(parent=self, message=_("Invalid input coordinates"), showTraceback=False) return if not self.poi: GError(parent=self, message=_("Invalid input coordinates"), showTraceback=False) return bbox = self.region.get_bbox() if not bbox.contains(self.poi): GError(parent=self, message=_("Seed point outside the " "current region"), showTraceback=False) return # check raster dataset if datasetsR: datasetsR = datasetsR.split(',') try: datasetsR = self._checkDatasets(datasetsR, 'strds') if not datasetsR: return except GException: GError(parent=self, message=_("Invalid input raster dataset"), showTraceback=False) return if not self.poi: GError(parent=self, message=_("Invalid input coordinates"), showTraceback=False) return self.datasetsR = datasetsR # check vector dataset if datasetsV: datasetsV = datasetsV.split(',') try: datasetsV = self._checkDatasets(datasetsV, 'stvds') if not datasetsV: return except GException: GError(parent=self, message=_("Invalid input vector dataset"), showTraceback=False) return self.datasetsV = datasetsV self._redraw() def _redraw(self): """Readraw data. Decides if to draw also 3D and adjusts layout if needed. """ if self.datasetsR: self._getSTRDdata(self.datasetsR) if self.datasetsV: self._getSTVDData(self.datasetsV) # axes3d are physically removed if not self.axes2d: self.axes2d = self.fig.add_subplot(1, 1, 1) self._drawFigure() def _checkDatasets(self, datasets, typ): """Checks and validates datasets. Reports also type of dataset (e.g. 'strds'). :param list datasets: list of temporal dataset's name :return: (mapName, mapset, type) """ validated = [] tDict = tgis.tlist_grouped(type=typ, group_type=True, dbif=self.dbif) # nested list with '(map, mapset, etype)' items allDatasets = [[[(map, mapset, etype) for map in maps] for etype, maps in etypesDict.iteritems()] for mapset, etypesDict in tDict.iteritems()] # flatten this list if allDatasets: allDatasets = reduce(lambda x, y: x + y, reduce(lambda x, y: x + y, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() allDatasets = [ i for i in sorted(allDatasets, key=lambda l: mapsets.index(l[1])) ] for dataset in datasets: errorMsg = _("Space time dataset <%s> not found.") % dataset if dataset.find("@") >= 0: nameShort, mapset = dataset.split('@', 1) indices = [ n for n, (mapName, mapsetName, etype) in enumerate(allDatasets) if nameShort == mapName and mapsetName == mapset ] else: indices = [ n for n, (mapName, mapset, etype) in enumerate(allDatasets) if dataset == mapName ] if len(indices) == 0: raise GException(errorMsg) elif len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the " "space time dataset " "<%s>." % dataset), caption=_("Ambiguous dataset name"), choices=[("%(map)s@%(mapset)s:" " %(etype)s" % { 'map': allDatasets[i][0], 'mapset': allDatasets[i][1], 'etype': allDatasets[i][2] }) for i in indices], style=wx.CHOICEDLG_STYLE | wx.OK) if dlg.ShowModal() == wx.ID_OK: index = dlg.GetSelection() validated.append(allDatasets[indices[index]]) else: continue else: validated.append(allDatasets[indices[0]]) return validated def OnHelp(self, event): """Function to show help""" RunCommand(prog='g.manual', quiet=True, entry='g.gui.tplot') def SetDatasets(self, rasters, vectors, coors, cats, attr): """Set the data #TODO :param list rasters: a list of temporal raster dataset's name :param list vectors: a list of temporal vector dataset's name :param list coors: a list with x/y coordinates :param list cats: a list with incld. categories of vector :param str attr: name of atribute of vectror data """ if not (rasters or vectors) or not (coors or cats): return try: if rasters: self.datasetsR = self._checkDatasets(rasters, 'strds') if vectors: self.datasetsV = self._checkDatasets(vectors, 'stvds') if not (self.datasetsR or self.datasetsV): return except GException: GError(parent=self, message=_("Invalid input temporal dataset"), showTraceback=False) return if coors: try: self.poi = Point(float(coors[0]), float(coors[1])) except GException: GError(parent=self, message=_("Invalid input coordinates"), showTraceback=False) return try: self.coorval.coordsField.SetValue(','.join(coors)) except: self.coorval.SetValue(','.join(coors)) if self.datasetsV: vdatas = ','.join(map(lambda x: x[0] + '@' + x[1], self.datasetsV)) self.datasetSelectV.SetValue(vdatas) if attr: self.attribute.SetValue(attr) if cats: self.cats.SetValue(cats) if self.datasetsR: self.datasetSelectR.SetValue(','.join( map(lambda x: x[0] + '@' + x[1], self.datasetsR))) self._redraw() def OnVectorSelected(self, event): """Update the controlbox related to stvds""" dataset = self.datasetSelectV.GetValue().strip() name = dataset.split('@')[0] mapset = dataset.split('@')[1] if len(dataset.split('@')) > 1 else '' found = False for each in tgis.tlist(type='stvds', dbif=self.dbif): each_name, each_mapset = each.split('@') if name == each_name: if mapset and mapset != each_mapset: continue dataset = name + '@' + each_mapset found = True break if found: try: vect_list = grass.read_command('t.vect.list', flags='u', input=dataset, column='name') except Exception: self.attribute.Clear() GError(parent=self, message=_("Invalid input temporal dataset"), showTraceback=False) return vect_list = list(set(sorted(vect_list.split()))) for vec in vect_list: self.attribute.InsertColumns(vec, 1) else: self.attribute.Clear()
class ImportDialog(wx.Dialog): """Dialog for bulk import of various data (base class)""" def __init__(self, parent, giface, itype, id=wx.ID_ANY, title=_("Multiple import"), style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER): self.parent = parent # GMFrame self._giface = giface # used to add layers self.importType = itype self.options = dict() # list of options self.options_par = dict() self.commandId = -1 # id of running command wx.Dialog.__init__(self, parent, id, title, style=style, name="MultiImportDialog") self.panel = wx.Panel(parent=self, id=wx.ID_ANY) self.layerBox = StaticBox(parent=self.panel, id=wx.ID_ANY) if self.importType == 'gdal': label = _("List of raster layers") elif self.importType == 'ogr': label = _("List of vector layers") else: label = _("List of %s layers") % self.importType.upper() self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all"))) # list of layers columns = [ _('Layer id'), _('Layer name'), _('Name for output GRASS map (editable)') ] if itype == 'ogr': columns.insert(2, _('Feature type')) columns.insert(3, _('Projection match')) elif itype == 'gdal': columns.insert(2, _('Projection match')) self.list = LayersList(parent=self.panel, columns=columns) self.list.LoadData() self.override = wx.CheckBox( parent=self.panel, id=wx.ID_ANY, label=_( "Override projection check (use current location's projection)" )) self.overwrite = wx.CheckBox( parent=self.panel, id=wx.ID_ANY, label=_("Allow output files to overwrite existing files")) self.overwrite.SetValue( UserSettings.Get(group='cmd', key='overwrite', subkey='enabled')) self.overwrite.Bind(wx.EVT_CHECKBOX, self.OnCheckOverwrite) if UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'): self.list.validate = False self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY) self.closeOnFinish = wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("Close dialog on finish")) self.closeOnFinish.SetValue( UserSettings.Get(group='cmd', key='closeDlg', subkey='enabled')) # # buttons # # cancel self.btn_close = CloseButton(parent=self.panel) self.btn_close.SetToolTip(_("Close dialog")) self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) # run self.btn_run = Button(parent=self.panel, id=wx.ID_OK, label=_("&Import")) self.btn_run.SetToolTip(_("Import selected layers")) self.btn_run.SetDefault() self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun) self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy()) self.notebook = GNotebook(parent=self, style=globalvar.FNPageDStyle) self.notebook.AddPage(page=self.panel, text=_('Source settings'), name='source') self.createSettingsPage() def createSettingsPage(self): self._blackList = { 'enabled': True, 'items': { self._getCommand(): { 'params': self._getBlackListedParameters(), 'flags': self._getBlackListedFlags() } } } grass_task = gtask.parse_interface(self._getCommand(), blackList=self._blackList) self.advancedPagePanel = CmdPanel(parent=self, giface=None, task=grass_task, frame=None) self.notebook.AddPage(page=self.advancedPagePanel, text=_('Import settings'), name='settings') def doLayout(self): """Do layout""" dialogSizer = wx.BoxSizer(wx.VERTICAL) # dsn input dialogSizer.Add(self.dsnInput, proportion=0, flag=wx.EXPAND) # # list of DXF layers # layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL) layerSizer.Add(self.list, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) dialogSizer.Add(layerSizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) dialogSizer.Add(self.override, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.overwrite, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.add, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.closeOnFinish, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) # # buttons # btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL) btnsizer.Add(self.btn_close, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER, border=10) btnsizer.Add(self.btn_run, proportion=0, flag=wx.RIGHT | wx.ALIGN_CENTER, border=10) dialogSizer.Add(btnsizer, proportion=0, flag=wx.BOTTOM | wx.ALIGN_RIGHT, border=10) # dialogSizer.SetSizeHints(self.panel) self.panel.SetAutoLayout(True) self.panel.SetSizer(dialogSizer) dialogSizer.Fit(self.panel) # auto-layout seems not work here - FIXME size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 322, 550) self.SetMinSize(size) self.SetSize((size.width, size.height + 100)) # width = self.GetSize()[0] # self.list.SetColumnWidth(col = 1, width = width / 2 - 50) self.Layout() def _getCommand(self): """Get command""" raise NotImplementedError() def _getBlackListedParameters(self): """Get parameters which will not be showed in Settings page""" raise NotImplementedError() def _getBlackListedFlags(self): """Get flags which will not be showed in Settings page""" raise NotImplementedError() def _nameValidationFailed(self, layers_list): """Output map name validation callback :param layers_list: LayersList class instance """ if isinstance(layers_list.output_map, list): maps = ['<{}>'.format(m) for m in layers_list.output_map] message = _("Output map names %(names)s exist. ") % { 'names': ', '.join(maps) } else: message = _("Output map name <%(name)s> exist. ") % { 'name': layers_list.output_map } GError(parent=self, message=message, caption=_("Invalid name")) def _validateOutputMapName(self): """Enable/disable output map name validation according the overwrite state""" if not self.overwrite.IsChecked(): if not self.list.GetValidator().\ Validate(win=self.list, validate_all=True): return False return True def OnClose(self, event=None): """Close dialog""" self.Close() def OnRun(self, event): """Import/Link data (each layes as separate vector map)""" pass def OnCheckOverwrite(self, event): """Check/uncheck overwrite checkbox widget""" if self.overwrite.IsChecked(): self.list.validate = False else: self.list.validate = True def AddLayers(self, returncode, cmd=None, userData=None): """Add imported/linked layers into layer tree""" if not self.add.IsChecked() or returncode != 0: return # TODO: if importing map creates more map the following does not work # * do nothing if map does not exist or # * try to determine names using regexp or # * persuade import tools to report map names self.commandId += 1 layer, output = self.list.GetLayers()[self.commandId][:2] if '@' not in output: name = output + '@' + grass.gisenv()['MAPSET'] else: name = output # add imported layers into layer tree # an alternative would be emit signal (mapCreated) and (optionally) # connect to this signal llist = self._giface.GetLayerList() if self.importType == 'gdal': if userData: nBands = int(userData.get('nbands', 1)) else: nBands = 1 if UserSettings.Get(group='rasterLayer', key='opaque', subkey='enabled'): nFlag = True else: nFlag = False for i in range(1, nBands + 1): nameOrig = name if nBands > 1: mapName, mapsetName = name.split('@') mapName += '.%d' % i name = mapName + '@' + mapsetName cmd = ['d.rast', 'map=%s' % name] if nFlag: cmd.append('-n') llist.AddLayer(ltype='raster', name=name, checked=True, cmd=cmd) name = nameOrig else: llist.AddLayer(ltype='vector', name=name, checked=True, cmd=['d.vect', 'map=%s' % name] + GetDisplayVectSettings()) self._giface.GetMapWindow().ZoomToMap() def OnAbort(self, event): """Abort running import .. todo:: not yet implemented """ pass def OnCmdDone(self, event): """Do what has to be done after importing""" pass def _getLayersToReprojetion(self, projMatch_idx, grassName_idx): """If there are layers with different projection from loation projection, show dialog to user to explicitly select layers which will be reprojected...""" differentProjLayers = [] data = self.list.GetData(checked=True) for itm in data: layerId = itm[-1] # select only layers with different projetion if self.layersData[layerId][projMatch_idx] == 0: dt = [itm[0], itm[grassName_idx]] differentProjLayers.append(tuple(dt)) layers = self.list.GetLayers() if not self.link and \ differentProjLayers and \ not self.override.IsChecked(): # '-o' not in self.getSettingsPageCmd(): dlg = ReprojectionDialog(parent=self, giface=self._giface, data=differentProjLayers) ret = dlg.ShowModal() if ret == wx.ID_OK: # do not import unchecked layers for itm in reversed(list(dlg.GetData(checked=False))): idx = itm[-1] layers.pop(idx) else: return None return layers def getSettingsPageCmd(self): return self.advancedPagePanel.createCmd(ignoreErrors=True, ignoreRequired=True)
class KrigingPanel(wx.Panel): """Main panel. Contains all widgets except Menus and Statusbar.""" def __init__(self, parent, Rinstance, controller, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) self.parent = parent self.border = 4 # 1. Input data InputBoxSizer = wx.StaticBoxSizer( wx.StaticBox(self, id=wx.ID_ANY, label=_("Input Data")), orient=wx.HORIZONTAL, ) flexSizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) flexSizer.AddGrowableCol(1) flexSizer.Add( wx.StaticText(self, id=wx.ID_ANY, label=_("Point dataset:")), flag=wx.ALIGN_CENTER_VERTICAL, ) self.InputDataMap = gselect.VectorSelect(parent=self, ftype="points", updateOnPopup=False) self.InputDataMap.SetFocus() flexSizer.Add(self.InputDataMap, flag=wx.ALIGN_CENTER_VERTICAL) RefreshButton = wx.Button(self, id=wx.ID_REFRESH) RefreshButton.Bind(wx.EVT_BUTTON, self.OnButtonRefresh) flexSizer.Add(RefreshButton, flag=wx.ALIGN_CENTER_VERTICAL) flexSizer.Add( wx.StaticText(self, id=wx.ID_ANY, label=_("Numeric column:")), flag=wx.ALIGN_CENTER_VERTICAL, ) self.InputDataColumn = gselect.ColumnSelect(self, id=wx.ID_ANY) flexSizer.Add(self.InputDataColumn) self.InputDataMap.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnInputMapChanged) self.InputDataColumn.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnInputColumnChanged) InputBoxSizer.Add(flexSizer) # 2. Kriging. In book pages one for each R package. Includes variogram # fit. KrigingSizer = wx.StaticBoxSizer( wx.StaticBox(self, id=wx.ID_ANY, label=_("Kriging")), wx.HORIZONTAL) self.RPackagesBook = GNotebook(parent=self, style=globalvar.FNPageDStyle) # , "geoR"]: #@TODO: enable it if/when it'll be implemented. for Rpackage in ["gstat"]: self.CreatePage(package=Rpackage, Rinstance=Rinstance, controller=controller) # Command output. From menuform module, cmdPanel class self._gconsole = gconsole.GConsole(guiparent=self) self.goutput = goutput.GConsoleWindow(parent=self, gconsole=self._gconsole, margin=False) self.goutputId = self.RPackagesBook.GetPageCount() self.outpage = self.RPackagesBook.AddPage(page=self.goutput, text=_("Command output"), name="output") self._gconsole.Bind( gconsole.EVT_CMD_RUN, lambda event: self._switchPageHandler( event=event, notification=Notification.MAKE_VISIBLE), ) self._gconsole.Bind( gconsole.EVT_CMD_DONE, lambda event: self._switchPageHandler( event=event, notification=Notification.RAISE_WINDOW), ) self.RPackagesBook.SetSelection(0) KrigingSizer.Add(self.RPackagesBook, proportion=1, flag=wx.EXPAND) # 3. Output Parameters. OutputSizer = wx.StaticBoxSizer( wx.StaticBox(self, id=wx.ID_ANY, label=_("Output")), wx.HORIZONTAL) OutputParameters = wx.GridBagSizer(hgap=5, vgap=5) OutputParameters.Add( wx.StaticText(self, id=wx.ID_ANY, label=_("Name for the output raster map:")), flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0), ) self.OutputMapName = gselect.Select(parent=self, id=wx.ID_ANY, type="raster", mapsets=[grass.gisenv()["MAPSET"]]) OutputParameters.Add(self.OutputMapName, flag=wx.EXPAND | wx.ALL, pos=(0, 1)) self.VarianceRasterCheckbox = wx.CheckBox( self, id=wx.ID_ANY, label=_("Export variance map as well: ")) self.VarianceRasterCheckbox.SetValue(state=True) OutputParameters.Add(self.VarianceRasterCheckbox, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0)) self.OutputVarianceMapName = gselect.Select( parent=self, id=wx.ID_ANY, type="raster", mapsets=[grass.gisenv()["MAPSET"]]) self.VarianceRasterCheckbox.Bind(wx.EVT_CHECKBOX, self.OnVarianceCBChecked) OutputParameters.Add(self.OutputVarianceMapName, flag=wx.EXPAND | wx.ALL, pos=(1, 1)) self.OverwriteCheckBox = wx.CheckBox( self, id=wx.ID_ANY, label=_("Allow output files to overwrite existing files"), ) self.OverwriteCheckBox.SetValue( UserSettings.Get(group="cmd", key="overwrite", subkey="enabled")) OutputParameters.Add(self.OverwriteCheckBox, pos=(2, 0), span=(1, 2)) OutputParameters.AddGrowableCol(1) OutputSizer.Add(OutputParameters, proportion=0, flag=wx.EXPAND | wx.ALL, border=self.border) # 4. Run Button and Quit Button ButtonSizer = wx.BoxSizer(wx.HORIZONTAL) HelpButton = wx.Button(self, id=wx.ID_HELP) HelpButton.Bind(wx.EVT_BUTTON, self.OnHelpButton) QuitButton = wx.Button(self, id=wx.ID_EXIT) QuitButton.Bind(wx.EVT_BUTTON, self.OnCloseWindow) # no stock ID for Run button.. self.RunButton = wx.Button(self, id=wx.ID_ANY, label=_("&Run")) self.RunButton.Bind(wx.EVT_BUTTON, self.OnRunButton) # disable it on loading the interface, as input map is not set self.RunButton.Enable(False) ButtonSizer.Add(HelpButton, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=self.border) ButtonSizer.Add(QuitButton, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=self.border) ButtonSizer.Add( self.RunButton, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=self.border, ) # Main Sizer. Add each child sizer as soon as it is ready. Sizer = wx.BoxSizer(wx.VERTICAL) Sizer.Add(InputBoxSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=self.border) Sizer.Add(KrigingSizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=self.border) Sizer.Add(OutputSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=self.border) Sizer.Add(ButtonSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=self.border) self.SetSizerAndFit(Sizer) # last action of __init__: update imput data list. # it's performed in the few seconds gap while user examines interface before clicking anything. # @TODO: implement a splashcreen IF the maps cause a noticeable lag [markus' suggestion] self.InputDataMap.GetElementList() def CreatePage(self, package, Rinstance, controller): """Creates the three notebook pages, one for each R package""" for package in [ "gstat" ]: # @TODO add here other packages when they will be implemented classobj = eval("RBook" + package + "Panel") setattr( self, "RBook" + package + "Panel", (classobj(self, id=wx.ID_ANY, Rinstance=Rinstance, controller=controller)), ) self.RPackagesBook.AddPage(page=getattr( self, "RBook" + package + "Panel"), text=package) def OnButtonRefresh(self, event): """Forces refresh of list of available layers.""" self.InputDataMap.GetElementList() def OnCloseWindow(self, event): """Cancel button pressed""" self.parent.Close() event.Skip() def OnHelpButton(self, event): grass.run_command("g.manual", entry="v.krige") event.Skip() def OnInputMapChanged(self, event): """Refreshes list of columns.""" MapName = event.GetString() self.InputDataColumn.InsertColumns( vector=MapName, layer=1, excludeKey=False, type=["integer", "double precision"], ) def OnInputColumnChanged(self, event): """Fills output map name TextCtrl""" MapName = self.InputDataMap.GetValue() enable = bool(self.InputDataColumn.GetValue()) self.RunButton.Enable(enable) self.RBookgstatPanel.PlotButton.Enable(enable) if enable: self.OutputMapName.SetValue(MapName.split("@")[0] + "_kriging") self.OutputVarianceMapName.SetValue( MapName.split("@")[0] + "_kriging.var") else: self.OutputMapName.SetValue("") self.OutputVarianceMapName.SetValue("") def OnRunButton(self, event): """Execute R analysis.""" # @FIXME: send data to main method instead of running it here. # -1: get the selected notebook page. The user shall know that [s]he can modify settings in all # pages, but only the selected one will be executed when Run is # pressed. SelectedPanel = self.RPackagesBook.GetCurrentPage() if (self.RPackagesBook.GetPageText( self.RPackagesBook.GetSelection()) == "Command output"): self._gconsole.WriteError( 'No parameters for running. Please select "gstat" tab, check parameters and re-run.' ) return False # no break invoked by above function # mount command string as it would have been written on CLI command = [ "v.krige", "input=" + self.InputDataMap.GetValue(), "column=" + self.InputDataColumn.GetValue(), "output=" + self.OutputMapName.GetValue(), "package=" + "%s" % self.RPackagesBook.GetPageText(self.RPackagesBook.GetSelection()), ] if (not hasattr(SelectedPanel, "VariogramCheckBox") or not SelectedPanel.VariogramCheckBox.IsChecked()): command.append("model=" + "%s" % SelectedPanel.ModelChoicebox. GetStringSelection().split(" ")[0]) for i in ["Psill", "Nugget", "Range", "Kappa"]: if getattr(SelectedPanel, i + "ChextBox").IsChecked(): command.append(i.lower() + "=" + "%s" % getattr(SelectedPanel, i + "Ctrl").GetValue()) if SelectedPanel.KrigingRadioBox.GetStringSelection( ) == "Block kriging": command.append("block=" + "%s" % SelectedPanel.BlockSpinBox.GetValue()) if self.OverwriteCheckBox.IsChecked(): command.append("--overwrite") if self.VarianceRasterCheckbox.IsChecked(): command.append("output_var=" + self.OutputVarianceMapName.GetValue()) # give it to the output console # @FIXME: it runs the command as a NEW instance. Reimports data, recalculates variogram fit.. # otherwise I can use Controller() and mimic RunCmd behaviour. self._gconsole.RunCmd(command) def OnVarianceCBChecked(self, event): self.OutputVarianceMapName.Enable(event.IsChecked()) def _switchPageHandler(self, event, notification): self._switchPage(notification=notification) event.Skip() def _switchPage(self, notification): """Manages @c 'output' notebook page according to event notification.""" if notification == Notification.HIGHLIGHT: self.RPackagesBook.HighlightPageByName("output") if notification == Notification.MAKE_VISIBLE: self.RPackagesBook.SetSelectionByName("output") if notification == Notification.RAISE_WINDOW: self.RPackagesBook.SetSelectionByName("output") self.SetFocus() self.Raise()
def __init__(self, parent, size=(650, 460), title=_('About GRASS GIS'), **kwargs): wx.Frame.__init__(self, parent=parent, id=wx.ID_ANY, title=title, size=size, **kwargs) panel = wx.Panel(parent=self, id=wx.ID_ANY) # icon self.SetIcon( wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO)) # get version and web site vInfo = grass.version() infoTxt = ScrolledPanel(parent=panel) infoTxt.SetupScrolling() infoSizer = wx.BoxSizer(wx.VERTICAL) infoGridSizer = wx.GridBagSizer(vgap=5, hgap=5) logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass-64x64.png") logoBitmap = wx.StaticBitmap(parent=infoTxt, id=wx.ID_ANY, bitmap=wx.Bitmap(name=logo, type=wx.BITMAP_TYPE_PNG)) infoSizer.Add(item=logoBitmap, proportion=0, flag=wx.ALL | wx.ALIGN_CENTER, border=20) info = wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label='GRASS GIS ' + vInfo['version'] + '\n\n') info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) info.SetForegroundColour(wx.Colour(35, 142, 35)) infoSizer.Add(item=info, proportion=0, flag=wx.BOTTOM | wx.ALIGN_CENTER, border=1) row = 0 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=_('Official GRASS site:')), pos=(row, 0), flag=wx.ALIGN_RIGHT) infoGridSizer.Add(item=HyperLinkCtrl(parent=infoTxt, id=wx.ID_ANY, label='http://grass.osgeo.org'), pos=(row, 1), flag=wx.ALIGN_LEFT) row += 2 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label='%s:' % _('SVN Revision')), pos=(row, 0), flag=wx.ALIGN_RIGHT) infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=vInfo['revision']), pos=(row, 1), flag=wx.ALIGN_LEFT) row += 1 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label='%s:' % _('GIS Library Revision')), pos=(row, 0), flag=wx.ALIGN_RIGHT) infoGridSizer.Add( item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=vInfo['libgis_revision'] + ' (' + vInfo['libgis_date'].split(' ')[0] + ')'), pos=(row, 1), flag=wx.ALIGN_LEFT) row += 2 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label='Python:'), pos=(row, 0), flag=wx.ALIGN_RIGHT) infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=platform.python_version()), pos=(row, 1), flag=wx.ALIGN_LEFT) row += 1 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label='wxPython:'), pos=(row, 0), flag=wx.ALIGN_RIGHT) infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=wx.__version__), pos=(row, 1), flag=wx.ALIGN_LEFT) infoGridSizer.AddGrowableCol(0) infoGridSizer.AddGrowableCol(1) infoSizer.Add(item=infoGridSizer, proportion=1, flag=wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL) row += 2 infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label="%s:" % _('Language')), pos=(row, 0), flag=wx.ALIGN_RIGHT) lang = grass.gisenv().get('LANG', None) if not lang: import locale loc = locale.getdefaultlocale() if loc == (None, None): lang = _('unknown') else: lang = u'%s.%s' % (loc[0], loc[1]) infoGridSizer.Add(item=wx.StaticText(parent=infoTxt, id=wx.ID_ANY, label=lang), pos=(row, 1), flag=wx.ALIGN_LEFT) # create a flat notebook for displaying information about GRASS aboutNotebook = GNotebook(panel, style=globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON) aboutNotebook.SetTabAreaColour(globalvar.FNPageColor) for title, win in ((_("Info"), infoTxt), (_("Copyright"), self._pageCopyright()), (_("License"), self._pageLicense()), (_("Authors"), self._pageCredit()), (_("Contributors"), self._pageContributors()), (_("Extra contributors"), self._pageContributors(extra=True)), (_("Translators"), self._pageTranslators())): aboutNotebook.AddPage(page=win, text=title) wx.CallAfter(aboutNotebook.SetSelection, 0) # buttons btnClose = wx.Button(parent=panel, id=wx.ID_CLOSE) btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.Add(item=btnClose, proportion=0, flag=wx.ALL | wx.ALIGN_RIGHT, border=5) # bindings btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow) infoTxt.SetSizer(infoSizer) infoSizer.Fit(infoTxt) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(item=aboutNotebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=1) sizer.Add(item=btnSizer, proportion=0, flag=wx.ALL | wx.ALIGN_RIGHT, border=1) panel.SetSizer(sizer) self.Layout() self.SetMinSize((400, 400))