""" MODULE: r_li_setup_GUI.py AUTHOR(S): Anne Ghisla PURPOSE: Dedicated GUI for r.li.setup, translated and reshaped from original TclTk. DEPENDS: [] COPYRIGHT: (C) 2010 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. """ # bulk import from location_wizard.py. import os import shutil import re import string import sys import locale import platform GUIModulesPath = os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython", "gui_modules") sys.path.append(GUIModulesPath) from core import globalvar import wx import wx.lib.mixins.listctrl as listmix import wx.wizard as wiz import wx.lib.scrolledpanel as scrolled import time from core import cmd as gcmd from core import utils from grass.script import core as grass #@TODO create wizard instead of progressively increasing window print >> sys.stderr, "TODO: implement r.li.setup wizard..." #@NOTE: r.li.setup writes in the settings file with ## r.li.windows.tcl: #exec echo "SAMPLINGFRAME $per_x|$per_y|$per_rl|$per_cl" >> $env(TMP).set class BaseClass(wx.Object): """!Base class providing basic methods""" def __init__(self): pass def MakeLabel(self, text="", style=wx.ALIGN_LEFT, parent=None): """!Make aligned label""" if not parent: parent = self return wx.StaticText(parent=parent, id=wx.ID_ANY, label=text, style=style) def MakeTextCtrl(self, text='', size=(100,-1), style=0, parent=None): """!Generic text control""" if not parent: parent = self return wx.TextCtrl(parent=parent, id=wx.ID_ANY, value=text, size=size, style=style) def MakeButton(self, text, id=wx.ID_ANY, size=(-1,-1), parent=None): """!Generic button""" if not parent: parent = self return wx.Button(parent=parent, id=id, label=text, size=size) class TitledPage(BaseClass, wiz.WizardPageSimple): """ Class to make wizard pages. Generic methods to make labels, text entries, and buttons. """ def __init__(self, parent, title): self.page = wiz.WizardPageSimple.__init__(self, parent) # page title self.title = wx.StaticText(parent=self, id=wx.ID_ANY, label=title) self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD)) # main sizers self.pagesizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.GridBagSizer(vgap=0, hgap=0) def DoLayout(self): """!Do page layout""" self.pagesizer.Add(item=self.title, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5) self.pagesizer.Add(item=wx.StaticLine(self, -1), proportion=0, flag=wx.EXPAND | wx.ALL, border=0) self.pagesizer.Add(item=self.sizer) self.SetAutoLayout(True) self.SetSizer(self.pagesizer) # tmpsizer.Fit(self) self.Layout() class LocationWizard(wx.Object): """ Start wizard here and finish wizard here """ def __init__(self, parent): # global coordsys self.parent = parent # # define wizard image # # file = "loc_wizard.png" file = "loc_wizard_qgis.png" imagePath = os.path.join(globalvar.ETCIMGDIR, file) wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG) # wizbmp.Rescale(250,600) wizbmp = wizbmp.ConvertToBitmap() # # get georeferencing information from tables in $GISBASE/etc # # self.__readData() # # # # # datum transform number and list of datum transforms # # # self.datumtrans = 0 # self.proj4string = '' # # # # # define wizard pages # # self.wizard = wiz.Wizard(parent, id=wx.ID_ANY, title=_("I m!"), bitmap=wizbmp) self.startpage = SummaryPage(self.wizard, self) # self.csystemspage = CoordinateSystemPage(self.wizard, self) # self.projpage = ProjectionsPage(self.wizard, self) # self.datumpage = DatumPage(self.wizard, self) # self.paramspage = ProjParamsPage(self.wizard,self) # self.epsgpage = EPSGPage(self.wizard, self) # self.filepage = GeoreferencedFilePage(self.wizard, self) # self.wktpage = WKTPage(self.wizard, self) # self.ellipsepage = EllipsePage(self.wizard, self) # self.custompage = CustomPage(self.wizard, self) # self.sumpage = SummaryPage(self.wizard, self) # # # # # set the initial order of the pages # # (should follow the epsg line) # # # self.startpage.SetNext(self.csystemspage) # # self.csystemspage.SetPrev(self.startpage) # self.csystemspage.SetNext(self.sumpage) # # self.projpage.SetPrev(self.csystemspage) # self.projpage.SetNext(self.paramspage) # # self.paramspage.SetPrev(self.projpage) # self.paramspage.SetNext(self.datumpage) # # self.datumpage.SetPrev(self.paramspage) # self.datumpage.SetNext(self.sumpage) # # self.ellipsepage.SetPrev(self.paramspage) # self.ellipsepage.SetNext(self.sumpage) # # self.epsgpage.SetPrev(self.csystemspage) # self.epsgpage.SetNext(self.sumpage) # # self.filepage.SetPrev(self.csystemspage) # self.filepage.SetNext(self.sumpage) # # self.wktpage.SetPrev(self.csystemspage) # self.wktpage.SetNext(self.sumpage) # # self.custompage.SetPrev(self.csystemspage) # self.custompage.SetNext(self.sumpage) # # self.sumpage.SetPrev(self.csystemspage) # # # # # do pages layout # # # self.startpage.DoLayout() # self.csystemspage.DoLayout() # self.projpage.DoLayout() # self.datumpage.DoLayout() # self.paramspage.DoLayout() # self.epsgpage.DoLayout() # self.filepage.DoLayout() # self.wktpage.DoLayout() # self.ellipsepage.DoLayout() # self.custompage.DoLayout() # self.sumpage.DoLayout() # self.wizard.FitToPage(self.datumpage) # # # new location created? # self.location = None # success = False # # # location created in different GIS database? # self.altdb = False # # run wizard... # if self.wizard.RunWizard(self.startpage): pass # msg = self.OnWizFinished() # if len(msg) < 1: # self.wizard.Destroy() # self.location = self.startpage.location # # if self.altdb == False: # dlg = wx.MessageDialog(parent=self.parent, # message=_("Do you want to set the default " # "region extents and resolution now?"), # caption=_("Location <%s> created") % self.location, # style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) # dlg.CenterOnScreen() # if dlg.ShowModal() == wx.ID_YES: # dlg.Destroy() # defineRegion = RegionDef(self.parent, location=self.location) # defineRegion.CenterOnScreen() # defineRegion.Show() # else: # dlg.Destroy() # else: # -> error # self.wizard.Destroy() # wx.MessageBox(parent=self.parent, # message="%s" % _("Unable to create new location. " # "Location <%(loc)s> not created.\n\n" # "Details: %(err)s") % \ # { 'loc' : self.startpage.location, # 'err' : msg }, # caption=_("Location wizard"), # style=wx.OK | wx.ICON_ERROR | wx.CENTRE) # else: # win = wx.MessageBox(parent=self.parent, # message=_("Location wizard canceled. " # "Location not created."), # caption=_("Location wizard")) def __readData(self): """!Get georeferencing information from tables in $GISBASE/etc""" # read projection and parameters f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r") self.projections = {} self.projdesc = {} for line in f.readlines(): line = line.strip() try: proj, projdesc, params = line.split(':') paramslist = params.split(';') plist = [] for p in paramslist: if p == '': continue p1, pdefault = p.split(',') pterm, pask = p1.split('=') p = [pterm.strip(), pask.strip(), pdefault.strip()] plist.append(p) self.projections[proj.lower().strip()] = (projdesc.strip(), plist) self.projdesc[proj.lower().strip()] = projdesc.strip() except: continue f.close() # read datum definitions f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r") self.datums = {} paramslist = [] for line in f.readlines(): line = line.expandtabs(1) line = line.strip() if line == '' or line[0] == "#": continue datum, info = line.split(" ", 1) info = info.strip() datumdesc, params = info.split(" ", 1) datumdesc = datumdesc.strip('"') paramlist = params.split() ellipsoid = paramlist.pop(0) self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist) f.close() # read ellipsiod definitions f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r") self.ellipsoids = {} for line in f.readlines(): line = line.expandtabs(1) line = line.strip() if line == '' or line[0] == "#": continue ellipse, rest = line.split(" ", 1) rest = rest.strip('" ') desc, params = rest.split('"', 1) desc = desc.strip('" ') paramslist = params.split() self.ellipsoids[ellipse] = (desc, paramslist) f.close() # read projection parameter description and parsing table f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r") self.paramdesc = {} for line in f.readlines(): line = line.strip() try: pparam, datatype, proj4term, desc = line.split(':') self.paramdesc[pparam] = (datatype, proj4term, desc) except: continue f.close() def OnWizFinished(self): database = self.startpage.grassdatabase location = self.startpage.location global coordsys msg = '' # error message (empty on success) # location already exists? if os.path.isdir(os.path.join(database,location)): dlg = wx.MessageDialog(parent=self.wizard, message="%s <%s>: %s" % \ (_("Unable to create new location"), os.path.join(database, location), _("Location already exists in GRASS Database.")), caption=_("Error"), style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return False # current GISDbase or a new one? current_gdb = grass.gisenv()['GISDBASE'] if current_gdb != database: # change to new GISDbase or create new one if os.path.isdir(database) != True: # create new directory os.mkdir(database) # change to new GISDbase directory gcmd.RunCommand('g.gisenv', parent = self.wizard, set='GISDBASE=%s' % database) wx.MessageBox(parent=self.wizard, message=_("Location <%(loc)s> will be created " "in GIS data directory <%(dir)s>." "You will need to change the default GIS " "data directory in the GRASS startup screen.") % \ { 'loc' : location, 'dir' : database}, caption=_("New GIS data directory"), style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE) # location created in alternate GISDbase self.altdb = True if coordsys == "xy": msg = self.XYCreate() elif coordsys == "proj": proj4string = self.CreateProj4String() msg = self.Proj4Create(proj4string) elif coordsys == 'custom': msg = self.CustomCreate() elif coordsys == "epsg": msg = self.EPSGCreate() elif coordsys == "file": msg = self.FileCreate() elif coordsys == "wkt": msg = self.WKTCreate() return msg def XYCreate(self): """!Create an XY location @return error message (empty string on success) """ database = self.startpage.grassdatabase location = self.startpage.location # create location directory and PERMANENT mapset try: os.mkdir(os.path.join(database, location)) os.mkdir(os.path.join(database, location, 'PERMANENT')) # create DEFAULT_WIND and WIND files regioninfo = ['proj: 0', 'zone: 0', 'north: 1', 'south: 0', 'east: 1', 'west: 0', 'cols: 1', 'rows: 1', 'e-w resol: 1', 'n-s resol: 1', 'top: 1', 'bottom: 0', 'cols3: 1', 'rows3: 1', 'depths: 1', 'e-w resol3: 1', 'n-s resol3: 1', 't-b resol: 1'] defwind = open(os.path.join(database, location, "PERMANENT", "DEFAULT_WIND"), 'w') for param in regioninfo: defwind.write(param + '%s' % os.linesep) defwind.close() shutil.copy(os.path.join(database, location, "PERMANENT", "DEFAULT_WIND"), os.path.join(database, location, "PERMANENT", "WIND")) # create MYNAME file myname = open(os.path.join(database, location, "PERMANENT", "MYNAME"), 'w') myname.write('%s' % os.linesep) myname.close() except OSError, e: return e return '' def CreateProj4String(self): """!Constract PROJ.4 string""" location = self.startpage.location proj = self.projpage.p4proj projdesc = self.projpage.projdesc proj4params = self.paramspage.p4projparams datum = self.datumpage.datum if self.datumpage.datumdesc: datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse else: datumdesc = '' datumparams = self.datumpage.datumparams ellipse = self.ellipsepage.ellipse ellipsedesc = self.ellipsepage.ellipsedesc ellipseparams = self.ellipsepage.ellipseparams # # creating PROJ.4 string # proj4string = '%s %s' % (proj, proj4params) # set ellipsoid parameters if ellipse != '': proj4string = '%s +ellps=%s' % (proj4string, ellipse) for item in ellipseparams: if item[:4] == 'f=1/': item = ' +rf='+item[4:] else: item = ' +'+item proj4string = '%s %s' % (proj4string, item) # set datum and transform parameters if relevant if datum != '': proj4string = '%s +datum=%s' % (proj4string, datum) if datumparams: for item in datumparams: proj4string = '%s +%s' % (proj4string,item) proj4string = '%s +no_defs' % proj4string return proj4string def Proj4Create(self, proj4string): """!Create a new location for selected projection @return error message (empty string on success) """ ret, msg = gcmd.RunCommand('g.proj', flags = 'c', proj4 = proj4string, location = self.startpage.location, datumtrans = self.datumtrans, getErrorMsg = True) if ret == 0: return '' return msg def CustomCreate(self): """!Create a new location based on given proj4 string @return error message (empty string on success) """ proj4string = self.custompage.customstring location = self.startpage.location ret, msg = gcmd.RunCommand('g.proj', flags = 'c', proj4 = proj4string, location = location, getErrorMsg = True) if ret == 0: return '' return msg def EPSGCreate(self): """!Create a new location from an EPSG code. @return error message (empty string on success) """ epsgcode = self.epsgpage.epsgcode epsgdesc = self.epsgpage.epsgdesc location = self.startpage.location # should not happend if epsgcode == '': return _('EPSG code missing.') ret, msg = gcmd.RunCommand('g.proj', flags = 'c', epsg = epsgcode, location = location, datumtrans = self.datumtrans, getErrorMsg = True) if ret == 0: return '' return msg def FileCreate(self): """!Create a new location from a georeferenced file @return error message (empty string on success) """ georeffile = self.filepage.georeffile location = self.startpage.location # this should not happen if not georeffile or not os.path.isfile(georeffile): return _("File not found.") # creating location ret, msg = gcmd.RunCommand('g.proj', flags = 'c', georef = georeffile, location = location, getErrorMsg = True) if ret == 0: return '' return msg def WKTCreate(self): """!Create a new location from a WKT file @return error message (empty string on success) """ wktfile = self.wktpage.wktfile location = self.startpage.location # this should not happen if not wktfile or not os.path.isfile(wktfile): return _("File not found.") # creating location ret, msg = gcmd.RunCommand('g.proj', flags = 'c', wkt = wktfile, location = location, getErrorMsg = True) if ret == 0: return '' return msg class SummaryPage(TitledPage): """ Shows summary result of choosing coordinate system parameters prior to creating location """ def __init__(self, wizard, parent): TitledPage.__init__(self, wizard, _("Summary")) self.parent = parent # labels self.ldatabase = self.MakeLabel("") self.llocation = self.MakeLabel("") self.lprojection = self.MakeLabel("") self.lproj4string = self.MakeLabel("") self.lproj4stringLabel = self.MakeLabel("") self.lprojection.Wrap(400) self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) # self.Bind(wx.EVT_BUTTON, self.OnFinish, wx.ID_FINISH) # do sub-page layout self.__DoLayout() def __DoLayout(self): """!Do page layout""" self.sizer.AddGrowableCol(1) self.sizer.Add(item=self.MakeLabel(_("GRASS Database:")), flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(1, 0)) self.sizer.Add(item=self.ldatabase, flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(1, 1)) self.sizer.Add(item=self.MakeLabel(_("Location Name:")), flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(2, 0)) self.sizer.Add(item=self.llocation, flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(2, 1)) self.sizer.Add(item=self.MakeLabel(_("Projection:")), flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(3, 0)) self.sizer.Add(item=self.lprojection, flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(3, 1)) self.sizer.Add(item=self.lproj4stringLabel, flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(4, 0)) self.sizer.Add(item=self.lproj4string, flag=wx.ALIGN_LEFT | wx.ALL, border=5, pos=(4, 1)) self.sizer.Add(item=(10,20), flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, border=5, pos=(5, 0), span=(1, 2)) def OnEnterPage(self,event): """ Insert values into text controls for summary of location creation options """ # database = self.parent.startpage.grassdatabase # location = self.parent.startpage.location proj4string = self.parent.CreateProj4String() epsgcode = self.parent.epsgpage.epsgcode dtrans = self.parent.datumtrans global coordsys if coordsys not in ['proj', 'epsg']: self.lproj4stringLabel.Hide() self.lproj4string.Hide() self.lproj4stringLabel.SetLabel('') self.lproj4string.SetLabel('') else: self.lproj4string.Show() self.lproj4stringLabel.SetLabel(_("PROJ.4 definition:")) if coordsys == 'proj': ret, msg, err = gcmd.RunCommand('g.proj', flags = 'j', proj4 = proj4string, datumtrans = dtrans, location = location, getErrorMsg = True, read = True) elif coordsys == 'epsg': ret, msg, err = gcmd.RunCommand('g.proj', flags = 'j', epsg = epsgcode, datumtrans = dtrans, location = location, getErrorMsg = True, read = True) if ret == 0: projlabel = '' for line in msg.splitlines(): projlabel = projlabel + '%s ' % line self.lproj4string.SetLabel(projlabel) else: wx.MessageBox(err, 'Error', wx.ICON_ERROR) self.lproj4string.Wrap(400) projdesc = self.parent.projpage.projdesc ellipsedesc = self.parent.ellipsepage.ellipsedesc datumdesc = self.parent.datumpage.datumdesc # self.ldatabase.SetLabel(database) # self.llocation.SetLabel(location) label = '' if coordsys == 'epsg': label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc) self.lprojection.SetLabel(label) elif coordsys == 'file': label = 'matches file %s' % self.parent.filepage.georeffile self.lprojection.SetLabel(label) elif coordsys == 'wkt': label = 'matches file %s' % self.parent.wktpage.wktfile self.lprojection.SetLabel(label) elif coordsys == 'proj': label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc)) self.lprojection.SetLabel(label) elif coordsys == 'xy': label = ('XY coordinate system (not projected).') self.lprojection.SetLabel(label) elif coordsys == 'custom': label = ('%s' % self.parent.custompage.customstring) self.lprojection.SetLabel(label) def OnFinish(self, event): dlg = wx.MessageDialog(parent=self.wizard, message=_("Do you want to create GRASS location <%s>?") % location, caption=_("Create new location?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_NO: dlg.Destroy() event.Veto() else: dlg.Destroy() event.Skip() if __name__ == "__main__": app = wx.App() gWizard = LocationWizard(None) # gWizard.Show() app.MainLoop()