location_wizard.py 104 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807
  1. """!
  2. @package location_wizard.py
  3. @brief Location wizard - creates a new GRASS Location. User can choose
  4. from multiple methods.
  5. Classes:
  6. - BaseClass
  7. - TitledPage
  8. - DatabasePage
  9. - CoordinateSystemPage
  10. - ProjectionsPage
  11. - ItemList
  12. - ProjParamsPage
  13. - DatumPage
  14. - EllipsePage
  15. - GeoreferencedFilePage
  16. - EPSGPage
  17. - CustomPage
  18. - SummaryPage
  19. - RegionDef
  20. - LocationWizard
  21. - SelectTransformDialog
  22. (C) 2007-2010 by the GRASS Development Team
  23. This program is free software under the GNU General Public License
  24. (>=v2). Read the file COPYING that comes with GRASS for details.
  25. @author Michael Barton
  26. @author Jachym Cepicky
  27. @author Martin Landa <landa.martin gmail.com>
  28. """
  29. import os
  30. import shutil
  31. import string
  32. import sys
  33. import locale
  34. import platform
  35. import wx
  36. import wx.lib.mixins.listctrl as listmix
  37. import wx.wizard as wiz
  38. import wx.lib.scrolledpanel as scrolled
  39. import time
  40. import gcmd
  41. import globalvar
  42. import utils
  43. from grass.script import core as grass
  44. try:
  45. import subprocess
  46. except:
  47. CompatPath = os.path.join(globalvar.ETCWXDIR)
  48. sys.path.append(CompatPath)
  49. from compat import subprocess
  50. global coordsys
  51. global north
  52. global south
  53. global east
  54. global west
  55. global resolution
  56. global wizerror
  57. global translist
  58. class BaseClass(wx.Object):
  59. """!Base class providing basic methods"""
  60. def __init__(self):
  61. pass
  62. def MakeLabel(self, text="", style=wx.ALIGN_LEFT, parent=None):
  63. """!Make aligned label"""
  64. if not parent:
  65. parent = self
  66. return wx.StaticText(parent=parent, id=wx.ID_ANY, label=text,
  67. style=style)
  68. def MakeTextCtrl(self, text='', size=(100,-1), style=0, parent=None):
  69. """!Generic text control"""
  70. if not parent:
  71. parent = self
  72. return wx.TextCtrl(parent=parent, id=wx.ID_ANY, value=text,
  73. size=size, style=style)
  74. def MakeButton(self, text, id=wx.ID_ANY, size=(-1,-1), parent=None):
  75. """!Generic button"""
  76. if not parent:
  77. parent = self
  78. return wx.Button(parent=parent, id=id, label=text,
  79. size=size)
  80. class TitledPage(BaseClass, wiz.WizardPageSimple):
  81. """
  82. Class to make wizard pages. Generic methods to make
  83. labels, text entries, and buttons.
  84. """
  85. def __init__(self, parent, title):
  86. self.page = wiz.WizardPageSimple.__init__(self, parent)
  87. # page title
  88. self.title = wx.StaticText(parent=self, id=wx.ID_ANY, label=title)
  89. self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
  90. # main sizers
  91. self.pagesizer = wx.BoxSizer(wx.VERTICAL)
  92. self.sizer = wx.GridBagSizer(vgap=0, hgap=0)
  93. def DoLayout(self):
  94. """!Do page layout"""
  95. self.pagesizer.Add(item=self.title, proportion=0,
  96. flag=wx.ALIGN_CENTRE | wx.ALL,
  97. border=5)
  98. self.pagesizer.Add(item=wx.StaticLine(self, -1), proportion=0,
  99. flag=wx.EXPAND | wx.ALL,
  100. border=0)
  101. self.pagesizer.Add(item=self.sizer)
  102. self.SetAutoLayout(True)
  103. self.SetSizer(self.pagesizer)
  104. # tmpsizer.Fit(self)
  105. self.Layout()
  106. class DatabasePage(TitledPage):
  107. """
  108. Wizard page for setting GIS data directory and location name
  109. """
  110. def __init__(self, wizard, parent, grassdatabase):
  111. TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
  112. self.grassdatabase = grassdatabase
  113. self.location = ''
  114. # buttons
  115. self.bbrowse = self.MakeButton(_("Browse"))
  116. # text controls
  117. self.tgisdbase = self.MakeTextCtrl(grassdatabase, size=(300, -1))
  118. self.tlocation = self.MakeTextCtrl("newLocation", size=(300, -1))
  119. # layout
  120. self.sizer.AddGrowableCol(3)
  121. self.sizer.Add(item=self.MakeLabel(_("GIS Data Directory:")),
  122. flag=wx.ALIGN_RIGHT |
  123. wx.ALIGN_CENTER_VERTICAL |
  124. wx.ALL, border=5,
  125. pos=(1, 1))
  126. self.sizer.Add(item=self.tgisdbase,
  127. flag=wx.ALIGN_LEFT |
  128. wx.ALIGN_CENTER_VERTICAL |
  129. wx.ALL, border=5,
  130. pos=(1, 2))
  131. self.sizer.Add(item=self.bbrowse,
  132. flag=wx.ALIGN_LEFT |
  133. wx.ALIGN_CENTER_VERTICAL |
  134. wx.ALL, border=5,
  135. pos=(1, 3))
  136. #
  137. self.sizer.Add(item=self.MakeLabel("%s:" % _("Project Location")),
  138. flag=wx.ALIGN_RIGHT |
  139. wx.ALIGN_CENTER_VERTICAL |
  140. wx.ALL, border=5,
  141. pos=(2, 1))
  142. self.sizer.Add(item=self.tlocation,
  143. flag=wx.ALIGN_LEFT |
  144. wx.ALIGN_CENTER_VERTICAL |
  145. wx.ALL, border=5,
  146. pos=(2, 2))
  147. # self.sizer.Add(item=self.MakeLabel(_("(projection/coordinate system)")),
  148. # flag=wx.ALIGN_LEFT |
  149. # wx.ALIGN_CENTER_VERTICAL |
  150. # wx.ALL, border=5,
  151. # pos=(2, 4))
  152. # bindings
  153. self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse)
  154. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  155. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  156. self.tgisdbase.Bind(wx.EVT_TEXT, self.OnChangeName)
  157. self.tlocation.Bind(wx.EVT_TEXT, self.OnChangeName)
  158. # do page layout
  159. # self.DoLayout()
  160. def OnChangeName(self, event):
  161. """!Name for new location was changed"""
  162. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  163. if len(event.GetString()) > 0:
  164. if not nextButton.IsEnabled():
  165. nextButton.Enable()
  166. else:
  167. nextButton.Disable()
  168. event.Skip()
  169. def OnBrowse(self, event):
  170. dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
  171. os.getcwd(), wx.DD_DEFAULT_STYLE)
  172. if dlg.ShowModal() == wx.ID_OK:
  173. self.grassdatabase = dlg.GetPath()
  174. self.tgisdbase.SetValue(self.grassdatabase)
  175. dlg.Destroy()
  176. def OnPageChanging(self,event=None):
  177. error = ''
  178. if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
  179. error = _("Location already exists in GRASS Database.")
  180. if error != '':
  181. dlg = wx.MessageDialog(parent=self, message="%s <%s>.%s%s" % (_("Unable to create location"),
  182. str(self.tlocation.GetValue()),
  183. os.linesep,
  184. error),
  185. caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
  186. dlg.ShowModal()
  187. dlg.Destroy()
  188. event.Veto()
  189. return
  190. self.location = self.tlocation.GetValue()
  191. self.grassdatabase = self.tgisdbase.GetValue()
  192. def OnEnterPage(self, event):
  193. """!Wizard page changed"""
  194. self.grassdatabase = self.tgisdbase.GetValue()
  195. self.location = self.tlocation.GetValue()
  196. event.Skip()
  197. class CoordinateSystemPage(TitledPage):
  198. """
  199. Wizard page for choosing method for location creation
  200. """
  201. def __init__(self, wizard, parent):
  202. TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
  203. self.parent = parent
  204. global coordsys
  205. # toggles
  206. self.radio1 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  207. label=_("Select coordinate system parameters from a list"),
  208. style = wx.RB_GROUP)
  209. self.radio2 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  210. label=_("Select EPSG code of spatial reference system"))
  211. self.radio3 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  212. label=_("Read projection and datum terms from a "
  213. "georeferenced data file"))
  214. self.radio4 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  215. label=_("Read projection and datum terms from a "
  216. "WKT or PRJ file"))
  217. self.radio5 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  218. label=_("Specify projection and datum terms using custom "
  219. "PROJ.4 parameters"))
  220. self.radio6 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  221. label=_("Create an arbitrary non-earth coordinate system (XY)"))
  222. # layout
  223. self.sizer.AddGrowableCol(1)
  224. self.sizer.SetVGap(10)
  225. self.sizer.Add(item=self.radio1,
  226. flag=wx.ALIGN_LEFT, pos=(1, 1))
  227. self.sizer.Add(item=self.radio2,
  228. flag=wx.ALIGN_LEFT, pos=(2, 1))
  229. self.sizer.Add(item=self.radio3,
  230. flag=wx.ALIGN_LEFT, pos=(3, 1))
  231. self.sizer.Add(item=self.radio4,
  232. flag=wx.ALIGN_LEFT, pos=(4, 1))
  233. self.sizer.Add(item=self.radio5,
  234. flag=wx.ALIGN_LEFT, pos=(5, 1))
  235. self.sizer.Add(item=self.radio6,
  236. flag=wx.ALIGN_LEFT, pos=(6, 1))
  237. # bindings
  238. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId())
  239. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio2.GetId())
  240. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio3.GetId())
  241. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio4.GetId())
  242. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio5.GetId())
  243. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio6.GetId())
  244. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  245. # do page layout
  246. # self.DoLayout()
  247. def OnEnterPage(self, event):
  248. global coordsys
  249. if not coordsys:
  250. coordsys = "proj"
  251. self.radio1.SetValue(True)
  252. else:
  253. if coordsys == 'proj':
  254. self.radio1.SetValue(True)
  255. if coordsys == "epsg":
  256. self.radio2.SetValue(True)
  257. if coordsys == "file":
  258. self.radio3.SetValue(True)
  259. if coordsys == "wkt":
  260. self.radio4.SetValue(True)
  261. if coordsys == "custom":
  262. self.radio5.SetValue(True)
  263. if coordsys == "xy":
  264. self.radio6.SetValue(True)
  265. if event.GetDirection():
  266. self.SetNext(self.parent.projpage)
  267. self.parent.sumpage.SetPrev(self.parent.datumpage)
  268. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  269. wx.FindWindowById(wx.ID_FORWARD).Enable()
  270. def SetVal(self, event):
  271. """!Choose method"""
  272. global coordsys
  273. if event.GetId() == self.radio1.GetId():
  274. coordsys = "proj"
  275. self.SetNext(self.parent.projpage)
  276. self.parent.sumpage.SetPrev(self.parent.datumpage)
  277. elif event.GetId() == self.radio2.GetId():
  278. coordsys = "epsg"
  279. self.SetNext(self.parent.epsgpage)
  280. self.parent.sumpage.SetPrev(self.parent.epsgpage)
  281. elif event.GetId() == self.radio3.GetId():
  282. coordsys = "file"
  283. self.SetNext(self.parent.filepage)
  284. self.parent.sumpage.SetPrev(self.parent.filepage)
  285. elif event.GetId() == self.radio4.GetId():
  286. coordsys = "wkt"
  287. self.SetNext(self.parent.wktpage)
  288. self.parent.sumpage.SetPrev(self.parent.wktpage)
  289. elif event.GetId() == self.radio5.GetId():
  290. coordsys = "custom"
  291. self.SetNext(self.parent.custompage)
  292. self.parent.sumpage.SetPrev(self.parent.custompage)
  293. elif event.GetId() == self.radio6.GetId():
  294. coordsys = "xy"
  295. self.SetNext(self.parent.sumpage)
  296. self.parent.sumpage.SetPrev(self.parent.csystemspage)
  297. class ProjectionsPage(TitledPage):
  298. """
  299. Wizard page for selecting projection (select coordinate system option)
  300. """
  301. def __init__(self, wizard, parent):
  302. TitledPage.__init__(self, wizard, _("Choose projection"))
  303. self.parent = parent
  304. self.proj = ''
  305. self.projdesc = ''
  306. self.p4proj = ''
  307. # text input
  308. self.tproj = self.MakeTextCtrl("", size=(200,-1))
  309. # search box
  310. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  311. style=wx.TE_PROCESS_ENTER)
  312. # projection list
  313. self.projlist = ItemList(self, data=self.parent.projdesc.items(),
  314. columns=[_('Code'), _('Description')])
  315. self.projlist.resizeLastColumn(30)
  316. # layout
  317. self.sizer.AddGrowableCol(3)
  318. self.sizer.Add(item=self.MakeLabel(_("Projection code:")),
  319. flag=wx.ALIGN_LEFT |
  320. wx.ALIGN_CENTER_VERTICAL |
  321. wx.ALL, border=5, pos=(1, 1))
  322. self.sizer.Add(item=self.tproj,
  323. flag=wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
  324. border=5, pos=(1, 2))
  325. self.sizer.Add(item=self.MakeLabel(_("Search in description:")),
  326. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  327. border=5, pos=(2, 1))
  328. self.sizer.Add(item=self.searchb,
  329. flag=wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
  330. border=5, pos=(2, 2))
  331. self.sizer.AddGrowableRow(3)
  332. self.sizer.Add(item=self.projlist,
  333. flag=wx.EXPAND |
  334. wx.ALIGN_LEFT |
  335. wx.ALL, border=5, pos=(3, 1), span=(1, 3))
  336. # events
  337. self.tproj.Bind(wx.EVT_TEXT, self.OnText)
  338. self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  339. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  340. self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  341. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  342. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  343. # do layout
  344. # self.Layout()
  345. def OnPageChanging(self,event):
  346. if event.GetDirection() and self.proj not in self.parent.projections.keys():
  347. event.Veto()
  348. def OnText(self, event):
  349. """!Projection name changed"""
  350. self.proj = event.GetString().lower()
  351. self.p4proj = ''
  352. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  353. if len(self.proj) == 0 and nextButton.IsEnabled():
  354. nextButton.Enable(False)
  355. if self.proj in self.parent.projections.keys():
  356. if self.proj == 'stp':
  357. wx.MessageBox('Currently State Plane projections must be selected using the '
  358. 'text-based setup (g.setproj), or entered by EPSG code or '
  359. 'custom PROJ.4 terms.',
  360. 'Warning', wx.ICON_WARNING)
  361. self.proj = ''
  362. self.tproj.SetValue(self.proj)
  363. nextButton.Enable(False)
  364. return
  365. elif self.proj.lower() == 'll':
  366. self.p4proj = '+proj=longlat'
  367. else:
  368. self.p4proj = '+proj=' + self.proj.lower()
  369. self.projdesc = self.parent.projections[self.proj][0]
  370. nextButton.Enable()
  371. def OnEnterPage(self, event):
  372. if len(self.proj) == 0:
  373. # disable 'next' button by default
  374. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  375. else:
  376. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  377. event.Skip()
  378. def OnSearch(self, event):
  379. """!Search projection by desc"""
  380. str = event.GetString()
  381. try:
  382. self.proj, self.projdesc = self.projlist.Search(index=[0,1], pattern=event.GetString())
  383. except:
  384. self.proj = self.projdesc = ''
  385. event.Skip()
  386. def OnItemSelected(self, event):
  387. """!Projection selected"""
  388. index = event.m_itemIndex
  389. # set values
  390. self.proj = self.projlist.GetItem(index, 0).GetText().lower()
  391. self.tproj.SetValue(self.proj)
  392. event.Skip()
  393. class ItemList(wx.ListCtrl,
  394. listmix.ListCtrlAutoWidthMixin,
  395. listmix.ColumnSorterMixin):
  396. """!Generic list (for projections, ellipsoids, etc.)"""
  397. def __init__(self, parent, columns, data=None):
  398. wx.ListCtrl.__init__(self, parent=parent, id=wx.ID_ANY,
  399. style=wx.LC_REPORT |
  400. wx.LC_VIRTUAL |
  401. wx.LC_HRULES |
  402. wx.LC_VRULES |
  403. wx.LC_SINGLE_SEL |
  404. wx.LC_SORT_ASCENDING, size=(550, 125))
  405. # original data or None
  406. self.sourceData = data
  407. #
  408. # insert columns
  409. #
  410. i = 0
  411. for column in columns:
  412. self.InsertColumn(i, column)
  413. i += 1
  414. if self.sourceData:
  415. self.Populate()
  416. for i in range(self.GetColumnCount()):
  417. self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
  418. if self.GetColumnWidth(i) < 80:
  419. self.SetColumnWidth(i, 80)
  420. #
  421. # listmix
  422. #
  423. listmix.ListCtrlAutoWidthMixin.__init__(self)
  424. listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
  425. #
  426. # add some attributes
  427. #
  428. self.attr1 = wx.ListItemAttr()
  429. self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
  430. self.attr2 = wx.ListItemAttr()
  431. self.attr2.SetBackgroundColour("white")
  432. self.il = wx.ImageList(16, 16)
  433. self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR,
  434. (16,16)))
  435. self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
  436. (16,16)))
  437. self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
  438. #
  439. # sort by first column
  440. #
  441. if self.sourceData:
  442. self.SortListItems(col=0, ascending=True)
  443. #
  444. # bindings
  445. #
  446. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
  447. def Populate(self, data=None, update=False):
  448. """!Populate list"""
  449. self.itemDataMap = {}
  450. self.itemIndexMap = []
  451. if data is None:
  452. data = self.sourceData
  453. elif update:
  454. self.sourceData = data
  455. try:
  456. data.sort()
  457. self.DeleteAllItems()
  458. row = 0
  459. for value in data:
  460. self.itemDataMap[row] = [value[0]]
  461. for i in range(1, len(value)):
  462. self.itemDataMap[row].append(value[i])
  463. self.itemIndexMap.append(row)
  464. row += 1
  465. self.SetItemCount(row)
  466. # set column width
  467. self.SetColumnWidth(0, 80)
  468. self.SetColumnWidth(1, 300)
  469. self.SendSizeEvent()
  470. except StandardError, e:
  471. wx.MessageBox(parent=self,
  472. message=_("Unable to read list: %s") % e,
  473. caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
  474. def OnColumnClick(self, event):
  475. """!Sort by column"""
  476. self._col = event.GetColumn()
  477. # remove duplicated arrow symbol from column header
  478. # FIXME: should be done automatically
  479. info = wx.ListItem()
  480. info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
  481. info.m_image = -1
  482. for column in range(self.GetColumnCount()):
  483. info.m_text = self.GetColumn(column).GetText()
  484. self.SetColumn(column, info)
  485. event.Skip()
  486. def GetSortImages(self):
  487. """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
  488. return (self.sm_dn, self.sm_up)
  489. def OnGetItemText(self, item, col):
  490. """!Get item text"""
  491. index = self.itemIndexMap[item]
  492. s = str(self.itemDataMap[index][col])
  493. return s
  494. def OnGetItemAttr(self, item):
  495. """!Get item attributes"""
  496. index = self.itemIndexMap[item]
  497. if ( index % 2) == 0:
  498. return self.attr2
  499. else:
  500. return self.attr1
  501. def SortItems(self, sorter=cmp):
  502. """!Sort items"""
  503. items = list(self.itemDataMap.keys())
  504. items.sort(self.Sorter)
  505. self.itemIndexMap = items
  506. # redraw the list
  507. self.Refresh()
  508. def Sorter(self, key1, key2):
  509. colName = self.GetColumn(self._col).GetText()
  510. ascending = self._colSortFlag[self._col]
  511. # convert always string
  512. item1 = self.itemDataMap[key1][self._col]
  513. item2 = self.itemDataMap[key2][self._col]
  514. if type(item1) == type('') or type(item2) == type(''):
  515. cmpVal = locale.strcoll(str(item1), str(item2))
  516. else:
  517. cmpVal = cmp(item1, item2)
  518. # If the items are equal then pick something else to make the sort value unique
  519. if cmpVal == 0:
  520. cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
  521. if ascending:
  522. return cmpVal
  523. else:
  524. return -cmpVal
  525. def GetListCtrl(self):
  526. """!Used by listmix.ColumnSorterMixin"""
  527. return self
  528. def Search (self, index, pattern):
  529. """!Search projection by description
  530. Return first found item or None
  531. """
  532. if pattern == '':
  533. self.Populate(self.sourceData)
  534. return []
  535. data = []
  536. pattern = pattern.lower()
  537. for i in range(len(self.sourceData)):
  538. for idx in index:
  539. try:
  540. value = str(self.sourceData[i][idx]).lower()
  541. if pattern in value:
  542. data.append(self.sourceData[i])
  543. break
  544. except UnicodeDecodeError:
  545. # osgeo4w problem (should be fixed)
  546. pass
  547. self.Populate(data)
  548. if len(data) > 0:
  549. return data[0]
  550. else:
  551. # self.Populate(self.sourceData)
  552. return []
  553. class ProjParamsPage(TitledPage):
  554. """
  555. Wizard page for selecting method of setting coordinate system parameters
  556. (select coordinate system option)
  557. """
  558. def __init__(self, wizard, parent):
  559. TitledPage.__init__(self, wizard, _("Choose projection parameters"))
  560. global coordsys
  561. self.parent = parent
  562. self.panel = None
  563. self.prjParamSizer = None
  564. self.pparam = dict()
  565. self.p4projparams = ''
  566. self.projdesc = ''
  567. radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  568. label = " %s " % _("Select datum or ellipsoid (next page)"))
  569. radioSBSizer = wx.StaticBoxSizer(radioSBox)
  570. self.sizer.Add(item = radioSBSizer, pos = (0, 1),
  571. flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
  572. self.radio1 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  573. label=_("Datum with associated ellipsoid"),
  574. style = wx.RB_GROUP)
  575. self.radio2 = wx.RadioButton(parent=self, id=wx.ID_ANY,
  576. label=_("Ellipsoid only"))
  577. # default button setting
  578. if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
  579. self.radio1.SetValue(True)
  580. self.SetNext(self.parent.datumpage)
  581. # self.parent.sumpage.SetPrev(self.parent.datumpage)
  582. radioSBSizer.Add(item=self.radio1,
  583. flag=wx.ALIGN_LEFT | wx.RIGHT, border=20)
  584. radioSBSizer.Add(item=self.radio2,
  585. flag=wx.ALIGN_LEFT)
  586. # bindings
  587. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
  588. self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
  589. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
  590. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  591. def OnParamEntry(self, event):
  592. """!Parameter value changed"""
  593. id = event.GetId()
  594. val = event.GetString()
  595. if not self.pparam.has_key(id):
  596. event.Skip()
  597. return
  598. param = self.pparam[id]
  599. win = self.FindWindowById(id)
  600. if param['type'] == 'zone':
  601. val = event.GetInt()
  602. if val < 1:
  603. win.SetValue(1)
  604. elif val > 60:
  605. win.SetValue(60)
  606. if param['type'] == 'bool':
  607. param['value'] = event.GetSelection()
  608. else:
  609. param['value'] = val
  610. event.Skip()
  611. def OnPageChange(self,event=None):
  612. """!Go to next page"""
  613. if event.GetDirection():
  614. self.p4projparams = ''
  615. for id, param in self.pparam.iteritems():
  616. if param['type'] == 'bool':
  617. if param['value'] == False:
  618. continue
  619. else:
  620. self.p4projparams += (' +' + param['proj4'])
  621. else:
  622. if param['value'] is None:
  623. wx.MessageBox(parent = self,
  624. message = _('You must enter a value for %s') % param['desc'],
  625. caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
  626. event.Veto()
  627. else:
  628. self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
  629. def OnEnterPage(self,event):
  630. """!Page entered"""
  631. self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
  632. if self.prjParamSizer is None:
  633. # entering page for the first time
  634. paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  635. label=_(" Enter parameters for %s projection ") % self.projdesc)
  636. paramSBSizer = wx.StaticBoxSizer(paramSBox)
  637. self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
  638. self.panel.SetupScrolling()
  639. self.prjParamSizer = wx.GridBagSizer(vgap=0, hgap=0)
  640. self.pagesizer.Add(item = paramSBSizer, proportion = 1,
  641. flag = wx.EXPAND | wx.ALIGN_TOP | wx.ALL, border = 10)
  642. paramSBSizer.Add(item = self.panel, proportion = 1,
  643. flag = wx.ALIGN_CENTER | wx.EXPAND)
  644. paramSBSizer.Fit(self.panel)
  645. self.panel.SetSizer(self.prjParamSizer)
  646. if event.GetDirection():
  647. self.prjParamSizer.Clear(True)
  648. self.pparam = dict()
  649. row = 0
  650. for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
  651. # get parameters
  652. id = wx.NewId()
  653. param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
  654. 'proj4': self.parent.paramdesc[paramgrp[0]][1],
  655. 'desc' : self.parent.paramdesc[paramgrp[0]][2] }
  656. # default values
  657. if param['type'] == 'bool':
  658. param['value'] = 0
  659. elif param['type'] == 'zone':
  660. param['value'] = 30
  661. param['desc'] += ' (1-60)'
  662. else:
  663. param['value'] = paramgrp[2]
  664. label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'],
  665. style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
  666. if param['type'] == 'bool':
  667. win = wx.Choice(parent = self.panel, id = id, size = (100,-1),
  668. choices = [_('No'), _('Yes')])
  669. win.SetSelection(param['value'])
  670. win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
  671. elif param['type'] == 'zone':
  672. win = wx.SpinCtrl(parent = self.panel, id = id,
  673. size = (100, -1),
  674. style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
  675. min = 1, max = 60)
  676. win.SetValue(param['value'])
  677. win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
  678. win.Bind(wx.EVT_TEXT, self.OnParamEntry)
  679. else:
  680. win = wx.TextCtrl(parent = self.panel, id = id,
  681. value = param['value'],
  682. size=(100, -1))
  683. win.Bind(wx.EVT_TEXT, self.OnParamEntry)
  684. if paramgrp[1] == 'noask':
  685. win.Enable(False)
  686. self.prjParamSizer.Add(item = label, pos = (row, 1),
  687. flag = wx.ALIGN_RIGHT |
  688. wx.ALIGN_CENTER_VERTICAL |
  689. wx.RIGHT, border = 5)
  690. self.prjParamSizer.Add(item = win, pos = (row, 2),
  691. flag = wx.ALIGN_LEFT |
  692. wx.ALIGN_CENTER_VERTICAL |
  693. wx.LEFT, border = 5)
  694. row += 1
  695. self.panel.SetSize(self.panel.GetBestSize())
  696. self.panel.Layout()
  697. self.Layout()
  698. self.Update()
  699. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  700. wx.FindWindowById(wx.ID_FORWARD).Enable()
  701. event.Skip()
  702. def SetVal(self, event):
  703. """!Set value"""
  704. if event.GetId() == self.radio1.GetId():
  705. self.SetNext(self.parent.datumpage)
  706. self.parent.sumpage.SetPrev(self.parent.datumpage)
  707. elif event.GetId() == self.radio2.GetId():
  708. self.SetNext(self.parent.ellipsepage)
  709. self.parent.sumpage.SetPrev(self.parent.ellipsepage)
  710. class DatumPage(TitledPage):
  711. """
  712. Wizard page for selecting datum (with associated ellipsoid)
  713. and datum transformation parameters (select coordinate system option)
  714. """
  715. def __init__(self, wizard, parent):
  716. TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
  717. self.parent = parent
  718. self.datum = ''
  719. self.datumdesc = ''
  720. self.ellipse = ''
  721. self.datumparams = ''
  722. self.proj4params = ''
  723. # text input
  724. self.tdatum = self.MakeTextCtrl("", size=(200,-1))
  725. # search box
  726. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  727. style=wx.TE_PROCESS_ENTER)
  728. # create list control for datum/elipsoid list
  729. data = []
  730. for key in self.parent.datums.keys():
  731. data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
  732. self.datumlist = ItemList(self,
  733. data=data,
  734. columns=[_('Code'), _('Ellipsoid'), _('Description')])
  735. self.datumlist.resizeLastColumn(10)
  736. # layout
  737. self.sizer.AddGrowableCol(4)
  738. self.sizer.Add(item=self.MakeLabel(_("Datum code:")),
  739. flag=wx.ALIGN_LEFT |
  740. wx.ALIGN_CENTER_VERTICAL |
  741. wx.ALL, border=5, pos=(1, 1))
  742. self.sizer.Add(item=self.tdatum,
  743. flag=wx.ALIGN_LEFT |
  744. wx.ALIGN_CENTER_VERTICAL |
  745. wx.ALL, border=5, pos=(1, 2))
  746. self.sizer.Add(item=self.MakeLabel(_("Search in description:")),
  747. flag=wx.ALIGN_LEFT |
  748. wx.ALIGN_CENTER_VERTICAL |
  749. wx.ALL, border=5, pos=(2, 1))
  750. self.sizer.Add(item=self.searchb,
  751. flag=wx.ALIGN_LEFT |
  752. wx.ALIGN_CENTER_VERTICAL |
  753. wx.ALL, border=5, pos=(2, 2))
  754. self.sizer.AddGrowableRow(3)
  755. self.sizer.Add(item=self.datumlist,
  756. flag=wx.EXPAND |
  757. wx.ALIGN_LEFT |
  758. wx.ALL, border=5, pos=(3, 1), span=(1, 4))
  759. # events
  760. self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
  761. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
  762. self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
  763. self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
  764. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  765. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  766. # do page layout
  767. # self.DoLayout()
  768. def OnPageChanging(self, event):
  769. self.proj4params = ''
  770. proj = self.parent.projpage.p4proj
  771. if event.GetDirection():
  772. if self.datum not in self.parent.datums:
  773. event.Veto()
  774. else:
  775. # check for datum tranforms
  776. # proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
  777. ret = gcmd.RunCommand('g.proj',
  778. read = True,
  779. proj4 = '%s +datum=%s' % (proj, self.datum),
  780. datumtrans = '-1')
  781. if ret != '':
  782. dtrans = ''
  783. # open a dialog to select datum transform number
  784. dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
  785. if dlg.ShowModal() == wx.ID_OK:
  786. dtrans = dlg.GetTransform()
  787. if dtrans == '':
  788. dlg.Destroy()
  789. event.Veto()
  790. return 'Datum transform is required.'
  791. else:
  792. dlg.Destroy()
  793. event.Veto()
  794. return 'Datum transform is required.'
  795. self.parent.datumtrans = dtrans
  796. self.GetNext().SetPrev(self)
  797. self.parent.ellipsepage.ellipse = self.ellipse
  798. self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  799. def OnEnterPage(self,event):
  800. self.parent.datumtrans = 0
  801. if event.GetDirection():
  802. if len(self.datum) == 0:
  803. # disable 'next' button by default when entering from previous page
  804. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  805. else:
  806. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  807. event.Skip()
  808. def OnDText(self, event):
  809. self.datum = event.GetString()
  810. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  811. if len(self.datum) == 0 or self.datum not in self.parent.datums:
  812. nextButton.Enable(False)
  813. else:
  814. self.ellipse = self.parent.datums[self.datum][0]
  815. self.datumdesc = self.parent.datums[self.datum][1]
  816. self.datumparams = self.parent.datums[self.datum][2]
  817. try:
  818. self.datumparams.remove('dx=0.0')
  819. except:
  820. pass
  821. try:
  822. self.datumparams.remove('dy=0.0')
  823. except:
  824. pass
  825. try:
  826. self.datumparams.remove('dz=0.0')
  827. except:
  828. pass
  829. nextButton.Enable(True)
  830. self.Update()
  831. event.Skip()
  832. def OnDSearch(self, event):
  833. str = self.searchb.GetValue()
  834. try:
  835. self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index=[0,1,2], pattern=str)
  836. except:
  837. self.datum = self.datumdesc = self.ellipsoid = ''
  838. event.Skip()
  839. def OnDatumSelected(self, event):
  840. index = event.m_itemIndex
  841. item = event.GetItem()
  842. self.datum = self.datumlist.GetItem(index, 0).GetText()
  843. self.tdatum.SetValue(self.datum)
  844. event.Skip()
  845. class EllipsePage(TitledPage):
  846. """
  847. Wizard page for selecting ellipsoid (select coordinate system option)
  848. """
  849. def __init__(self, wizard, parent):
  850. TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
  851. self.parent = parent
  852. self.ellipse = ''
  853. self.ellipsedesc = ''
  854. self.ellipseparams = ''
  855. self.proj4params = ''
  856. # text input
  857. self.tellipse = self.MakeTextCtrl("", size=(200,-1))
  858. # search box
  859. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  860. style=wx.TE_PROCESS_ENTER)
  861. # create list control for ellipse list
  862. data = []
  863. # extract code, desc
  864. for key in self.parent.ellipsoids.keys():
  865. data.append([key, self.parent.ellipsoids[key][0]])
  866. self.ellipselist = ItemList(self, data=data,
  867. columns=[_('Code'), _('Description')])
  868. self.ellipselist.resizeLastColumn(30)
  869. # layout
  870. self.sizer.AddGrowableCol(4)
  871. self.sizer.Add(item=self.MakeLabel(_("Ellipsoid code:")),
  872. flag=wx.ALIGN_RIGHT |
  873. wx.ALIGN_CENTER_VERTICAL |
  874. wx.ALL, border=5, pos=(1, 1))
  875. self.sizer.Add(item=self.tellipse,
  876. flag=wx.ALIGN_LEFT |
  877. wx.ALIGN_CENTER_VERTICAL |
  878. wx.ALL, border=5, pos=(1, 2))
  879. self.sizer.Add(item=self.MakeLabel(_("Search in description:")),
  880. flag=wx.ALIGN_RIGHT |
  881. wx.ALIGN_CENTER_VERTICAL |
  882. wx.ALL, border=5, pos=(2, 1))
  883. self.sizer.Add(item=self.searchb,
  884. flag=wx.ALIGN_LEFT |
  885. wx.ALIGN_CENTER_VERTICAL |
  886. wx.ALL, border=5, pos=(2, 2))
  887. self.sizer.AddGrowableRow(3)
  888. self.sizer.Add(item=self.ellipselist,
  889. flag=wx.EXPAND |
  890. wx.ALIGN_LEFT |
  891. wx.ALL, border=5, pos=(3, 1), span=(1, 4))
  892. # events
  893. self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  894. self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
  895. self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  896. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  897. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  898. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  899. def OnEnterPage(self,event):
  900. if len(self.ellipse) == 0:
  901. # disable 'next' button by default
  902. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  903. else:
  904. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  905. event.Skip()
  906. def OnPageChanging(self, event):
  907. if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
  908. event.Veto()
  909. self.proj4params = ''
  910. self.GetNext().SetPrev(self)
  911. self.parent.datumpage.datumparams = ''
  912. # self.GetNext().SetPrev(self) (???)
  913. def OnText(self, event):
  914. """!Ellipspoid code changed"""
  915. self.ellipse = event.GetString()
  916. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  917. if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
  918. nextButton.Enable(False)
  919. self.ellipsedesc = ''
  920. self.ellipseparams = ''
  921. self.proj4params = ''
  922. elif self.ellipse in self.parent.ellipsoids:
  923. self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
  924. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  925. nextButton.Enable(True)
  926. def OnSearch(self, event):
  927. """!Search ellipsoid by desc"""
  928. try:
  929. self.ellipse, self.ellipsedesc = \
  930. self.ellipselist.Search(index=[0,1], pattern=event.GetString())
  931. self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
  932. except:
  933. self.ellipse = self.ellipsedesc = self.ellipseparams = ''
  934. event.Skip()
  935. def OnItemSelected(self,event):
  936. index = event.m_itemIndex
  937. item = event.GetItem()
  938. self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
  939. self.tellipse.SetValue(self.ellipse)
  940. event.Skip()
  941. class GeoreferencedFilePage(TitledPage):
  942. """
  943. Wizard page for selecting georeferenced file to use
  944. for setting coordinate system parameters
  945. """
  946. def __init__(self, wizard, parent):
  947. TitledPage.__init__(self, wizard, _("Select georeferenced file"))
  948. self.georeffile = ''
  949. # create controls
  950. self.lfile= self.MakeLabel(_("Georeferenced file:"))
  951. self.tfile = self.MakeTextCtrl(size=(300,-1))
  952. self.bbrowse = self.MakeButton(_("Browse"))
  953. # do layout
  954. self.sizer.AddGrowableCol(3)
  955. self.sizer.Add(item=self.lfile, flag=wx.ALIGN_LEFT |
  956. wx.ALIGN_CENTRE_VERTICAL |
  957. wx.ALL, border=5, pos=(1, 1))
  958. self.sizer.Add(item=self.tfile, flag=wx.ALIGN_LEFT |
  959. wx.ALIGN_CENTRE_VERTICAL |
  960. wx.ALL, border=5, pos=(1, 2))
  961. self.sizer.Add(item=self.bbrowse, flag=wx.ALIGN_LEFT |
  962. wx.ALL, border=5, pos=(1, 3))
  963. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  964. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  965. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  966. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  967. # do page layout
  968. # self.DoLayout()
  969. def OnEnterPage(self, event):
  970. if len(self.georeffile) == 0:
  971. # disable 'next' button by default
  972. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  973. else:
  974. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  975. event.Skip()
  976. def OnPageChanging(self, event):
  977. if event.GetDirection() and self.georeffile == '':
  978. event.Veto()
  979. self.GetNext().SetPrev(self)
  980. event.Skip()
  981. def OnText(self, event):
  982. self.georeffile = event.GetString()
  983. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  984. if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
  985. if not nextButton.IsEnabled():
  986. nextButton.Enable(True)
  987. else:
  988. if nextButton.IsEnabled():
  989. nextButton.Enable(False)
  990. event.Skip()
  991. def OnBrowse(self, event):
  992. """!Choose file"""
  993. dlg = wx.FileDialog(self,
  994. _("Select georeferenced file"),
  995. os.getcwd(), "", "*.*", wx.OPEN)
  996. if dlg.ShowModal() == wx.ID_OK:
  997. path = dlg.GetPath()
  998. self.tfile.SetValue(path)
  999. dlg.Destroy()
  1000. event.Skip()
  1001. def OnCreate(self, event):
  1002. pass
  1003. class WKTPage(TitledPage):
  1004. """
  1005. Wizard page for selecting WKT file to use
  1006. for setting coordinate system parameters
  1007. """
  1008. def __init__(self, wizard, parent):
  1009. TitledPage.__init__(self, wizard, _("Select WKT file"))
  1010. self.wktfile = ''
  1011. # create controls
  1012. self.lfile= self.MakeLabel(_("WKT file:"))
  1013. self.tfile = self.MakeTextCtrl(size=(300,-1))
  1014. self.bbrowse = self.MakeButton(_("Browse"))
  1015. # do layout
  1016. self.sizer.AddGrowableCol(3)
  1017. self.sizer.Add(item=self.lfile, flag=wx.ALIGN_LEFT |
  1018. wx.ALIGN_CENTRE_VERTICAL |
  1019. wx.ALL, border=5, pos=(1, 1))
  1020. self.sizer.Add(item=self.tfile, flag=wx.ALIGN_LEFT |
  1021. wx.ALIGN_CENTRE_VERTICAL |
  1022. wx.ALL, border=5, pos=(1, 2))
  1023. self.sizer.Add(item=self.bbrowse, flag=wx.ALIGN_LEFT |
  1024. wx.ALL, border=5, pos=(1, 3))
  1025. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1026. self.tfile.Bind(wx.EVT_TEXT, self.OnText)
  1027. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1028. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1029. def OnEnterPage(self, event):
  1030. if len(self.wktfile) == 0:
  1031. # disable 'next' button by default
  1032. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1033. else:
  1034. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1035. event.Skip()
  1036. def OnPageChanging(self, event):
  1037. if event.GetDirection() and self.wktfile == '':
  1038. event.Veto()
  1039. self.GetNext().SetPrev(self)
  1040. event.Skip()
  1041. def OnText(self, event):
  1042. self.wktfile = event.GetString()
  1043. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1044. if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
  1045. if not nextButton.IsEnabled():
  1046. nextButton.Enable(True)
  1047. else:
  1048. if nextButton.IsEnabled():
  1049. nextButton.Enable(False)
  1050. event.Skip()
  1051. def OnBrowse(self, event):
  1052. """!Choose file"""
  1053. dlg = wx.FileDialog(self,
  1054. _("Select WKT file"),
  1055. os.getcwd(), "", "*.*", wx.OPEN)
  1056. if dlg.ShowModal() == wx.ID_OK:
  1057. path = dlg.GetPath()
  1058. self.tfile.SetValue(path)
  1059. dlg.Destroy()
  1060. event.Skip()
  1061. def OnCreate(self, event):
  1062. pass
  1063. class EPSGPage(TitledPage):
  1064. """
  1065. Wizard page for selecting EPSG code for
  1066. setting coordinate system parameters
  1067. """
  1068. def __init__(self, wizard, parent):
  1069. TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
  1070. self.parent = parent
  1071. self.epsgCodeDict = {}
  1072. self.epsgcode = None
  1073. self.epsgdesc = ''
  1074. self.epsgparams = ''
  1075. # labels
  1076. self.lfile= self.MakeLabel(_("Path to the EPSG-codes file:"),
  1077. style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1078. self.lcode= self.MakeLabel(_("EPSG code:"),
  1079. style=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  1080. # text input
  1081. epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
  1082. self.tfile = self.MakeTextCtrl(text=epsgdir, size=(200,-1),
  1083. style = wx.TE_PROCESS_ENTER)
  1084. self.tcode = self.MakeTextCtrl(size=(200,-1))
  1085. # buttons
  1086. self.bbrowse = self.MakeButton(_("Browse"))
  1087. # search box
  1088. self.searchb = wx.SearchCtrl(self, size=(200,-1),
  1089. style=wx.TE_PROCESS_ENTER)
  1090. self.epsglist = ItemList(self, data=None,
  1091. columns=[_('Code'), _('Description'), _('Parameters')])
  1092. # layout
  1093. self.sizer.AddGrowableCol(3)
  1094. self.sizer.Add(item=self.lfile,
  1095. flag=wx.ALIGN_LEFT |
  1096. wx.ALIGN_CENTER_VERTICAL |
  1097. wx.ALL, border=5, pos=(1, 1), span=(1, 2))
  1098. self.sizer.Add(item=self.tfile,
  1099. flag=wx.ALIGN_LEFT |
  1100. wx.ALIGN_CENTER_VERTICAL |
  1101. wx.ALL, border=5, pos=(1, 3))
  1102. self.sizer.Add(item=self.bbrowse,
  1103. flag=wx.ALIGN_LEFT |
  1104. wx.ALIGN_CENTER_VERTICAL |
  1105. wx.ALL, border=5, pos=(1, 4))
  1106. self.sizer.Add(item=self.lcode,
  1107. flag=wx.ALIGN_LEFT |
  1108. wx.ALIGN_CENTER_VERTICAL |
  1109. wx.ALL, border=5, pos=(2, 1), span=(1, 2))
  1110. self.sizer.Add(item=self.tcode,
  1111. flag=wx.ALIGN_LEFT |
  1112. wx.ALIGN_CENTER_VERTICAL |
  1113. wx.ALL, border=5, pos=(2, 3))
  1114. self.sizer.Add(item=self.searchb,
  1115. flag=wx.ALIGN_LEFT |
  1116. wx.ALIGN_CENTER_VERTICAL |
  1117. wx.ALL, border=5, pos=(3, 3))
  1118. self.sizer.AddGrowableRow(4)
  1119. self.sizer.Add(item=self.epsglist,
  1120. flag=wx.ALIGN_LEFT | wx.EXPAND, pos=(4, 1),
  1121. span=(1, 4))
  1122. # events
  1123. self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
  1124. self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
  1125. self.tcode.Bind(wx.EVT_TEXT, self.OnText)
  1126. self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
  1127. self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  1128. self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
  1129. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1130. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1131. def OnEnterPage(self, event):
  1132. self.parent.datumtrans = 0
  1133. if event.GetDirection():
  1134. if not self.epsgcode:
  1135. # disable 'next' button by default
  1136. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1137. else:
  1138. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1139. # load default epsg database file
  1140. self.OnBrowseCodes(None)
  1141. event.Skip()
  1142. def OnPageChanging(self, event):
  1143. if event.GetDirection():
  1144. if not self.epsgcode:
  1145. event.Veto()
  1146. return
  1147. else:
  1148. # check for datum transforms
  1149. ret = gcmd.RunCommand('g.proj',
  1150. read = True,
  1151. epsg = self.epsgcode,
  1152. datumtrans = '-1')
  1153. if ret != '':
  1154. dtrans = ''
  1155. # open a dialog to select datum transform number
  1156. dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
  1157. if dlg.ShowModal() == wx.ID_OK:
  1158. dtrans = dlg.GetTransform()
  1159. if dtrans == '':
  1160. dlg.Destroy()
  1161. event.Veto()
  1162. return 'Datum transform is required.'
  1163. else:
  1164. dlg.Destroy()
  1165. event.Veto()
  1166. return 'Datum transform is required.'
  1167. self.parent.datumtrans = dtrans
  1168. self.GetNext().SetPrev(self)
  1169. def OnText(self, event):
  1170. self.epsgcode = event.GetString()
  1171. try:
  1172. self.epsgcode = int(self.epsgcode)
  1173. except:
  1174. self.epsgcode = None
  1175. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1176. if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
  1177. self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
  1178. self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
  1179. if not nextButton.IsEnabled():
  1180. nextButton.Enable(True)
  1181. else:
  1182. self.epsgcode = None # not found
  1183. if nextButton.IsEnabled():
  1184. nextButton.Enable(False)
  1185. self.epsgdesc = self.epsgparams = ''
  1186. def OnSearch(self, event):
  1187. value = self.searchb.GetValue()
  1188. if value == '':
  1189. self.epsgcode = None
  1190. self.epsgdesc = self.epsgparams = ''
  1191. self.tcode.SetValue('')
  1192. self.searchb.SetValue('')
  1193. self.OnBrowseCodes(None)
  1194. else:
  1195. try:
  1196. self.epsgcode, self.epsgdesc, self.epsgparams = \
  1197. self.epsglist.Search(index=[0,1,2], pattern=value)
  1198. except (IndexError, ValueError): # -> no item found
  1199. self.epsgcode = None
  1200. self.epsgdesc = self.epsgparams = ''
  1201. self.tcode.SetValue('')
  1202. self.searchb.SetValue('')
  1203. event.Skip()
  1204. def OnBrowse(self, event):
  1205. """!Define path for EPSG code file"""
  1206. path = os.path.dirname(self.tfile.GetValue())
  1207. if not path:
  1208. path = os.getcwd()
  1209. dlg = wx.FileDialog(parent=self, message=_("Choose EPSG codes file"),
  1210. defaultDir=path, defaultFile="", wildcard="*", style=wx.OPEN)
  1211. if dlg.ShowModal() == wx.ID_OK:
  1212. path = dlg.GetPath()
  1213. self.tfile.SetValue(path)
  1214. self.OnBrowseCodes(None)
  1215. dlg.Destroy()
  1216. event.Skip()
  1217. def OnItemSelected(self, event):
  1218. """!EPSG code selected from the list"""
  1219. index = event.m_itemIndex
  1220. item = event.GetItem()
  1221. self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
  1222. self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
  1223. self.tcode.SetValue(str(self.epsgcode))
  1224. event.Skip()
  1225. def OnBrowseCodes(self, event, search=None):
  1226. """!Browse EPSG codes"""
  1227. self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
  1228. if type(self.epsgCodeDict) != dict:
  1229. wx.MessageBox(parent=self,
  1230. message=_("Unable to read EPGS codes: %s") % self.epsgCodeDict,
  1231. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1232. self.epsglist.Populate(list(), update=True)
  1233. return
  1234. data = list()
  1235. for code, val in self.epsgCodeDict.iteritems():
  1236. if code is not None:
  1237. data.append((code, val[0], val[1]))
  1238. self.epsglist.Populate(data, update=True)
  1239. class CustomPage(TitledPage):
  1240. """
  1241. Wizard page for entering custom PROJ.4 string
  1242. for setting coordinate system parameters
  1243. """
  1244. def __init__(self, wizard, parent):
  1245. TitledPage.__init__(self, wizard,
  1246. _("Choose method of specifying georeferencing parameters"))
  1247. global coordsys
  1248. self.customstring = ''
  1249. self.parent = parent
  1250. # widgets
  1251. self.text_proj4string = self.MakeTextCtrl(size=(400, 200),
  1252. style=wx.TE_MULTILINE)
  1253. self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
  1254. # layout
  1255. self.sizer.AddGrowableCol(2)
  1256. self.sizer.Add(self.label_proj4string,
  1257. flag=wx.ALIGN_LEFT | wx.ALL,
  1258. border=5, pos=(1, 1))
  1259. self.sizer.AddGrowableRow(2)
  1260. self.sizer.Add(self.text_proj4string,
  1261. flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
  1262. border=5, pos=(2, 1), span=(1, 2))
  1263. self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
  1264. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  1265. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1266. def OnEnterPage(self, event):
  1267. if len(self.customstring) == 0:
  1268. # disable 'next' button by default
  1269. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  1270. else:
  1271. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  1272. event.Skip()
  1273. def OnPageChanging(self, event):
  1274. if event.GetDirection() and not self.customstring:
  1275. event.Veto()
  1276. elif not event.GetDirection() and not self.customstring:
  1277. return
  1278. else: # check for datum tranforms
  1279. ret, out, err = gcmd.RunCommand('g.proj',
  1280. read = True, getErrorMsg = True,
  1281. proj4 = self.customstring,
  1282. datumtrans = '-1')
  1283. if ret != 0:
  1284. wx.MessageBox(parent = self,
  1285. message = err,
  1286. caption = _("Error"),
  1287. style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1288. event.Veto()
  1289. return
  1290. if out:
  1291. dtrans = ''
  1292. # open a dialog to select datum transform number
  1293. dlg = SelectTransformDialog(self.parent.parent, transforms=out)
  1294. if dlg.ShowModal() == wx.ID_OK:
  1295. dtrans = dlg.GetTransform()
  1296. if len(dtrans) == 0:
  1297. dlg.Destroy()
  1298. event.Veto()
  1299. return _('Datum transform is required.')
  1300. else:
  1301. dlg.Destroy()
  1302. event.Veto()
  1303. return _('Datum transform is required.')
  1304. self.parent.datumtrans = dtrans
  1305. self.GetNext().SetPrev(self)
  1306. def GetProjstring(self, event):
  1307. """!Change proj string"""
  1308. # TODO: check PROJ.4 syntax
  1309. self.customstring = event.GetString()
  1310. nextButton = wx.FindWindowById(wx.ID_FORWARD)
  1311. if len(self.customstring) == 0:
  1312. if nextButton.IsEnabled():
  1313. nextButton.Enable(False)
  1314. else:
  1315. if not nextButton.IsEnabled():
  1316. nextButton.Enable()
  1317. class SummaryPage(TitledPage):
  1318. """
  1319. Shows summary result of choosing coordinate system parameters
  1320. prior to creating location
  1321. """
  1322. def __init__(self, wizard, parent):
  1323. TitledPage.__init__(self, wizard, _("Summary"))
  1324. self.parent = parent
  1325. # labels
  1326. self.ldatabase = self.MakeLabel("")
  1327. self.llocation = self.MakeLabel("")
  1328. self.lprojection = self.MakeLabel("")
  1329. self.lproj4string = self.MakeLabel("")
  1330. self.lproj4stringLabel = self.MakeLabel("")
  1331. self.lprojection.Wrap(400)
  1332. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  1333. # self.Bind(wx.EVT_BUTTON, self.OnFinish, wx.ID_FINISH)
  1334. # do sub-page layout
  1335. self.__DoLayout()
  1336. def __DoLayout(self):
  1337. """!Do page layout"""
  1338. self.sizer.AddGrowableCol(1)
  1339. self.sizer.Add(item=self.MakeLabel(_("GRASS Database:")),
  1340. flag=wx.ALIGN_LEFT | wx.ALL,
  1341. border=5, pos=(1, 0))
  1342. self.sizer.Add(item=self.ldatabase,
  1343. flag=wx.ALIGN_LEFT | wx.ALL,
  1344. border=5, pos=(1, 1))
  1345. self.sizer.Add(item=self.MakeLabel(_("Location Name:")),
  1346. flag=wx.ALIGN_LEFT | wx.ALL,
  1347. border=5, pos=(2, 0))
  1348. self.sizer.Add(item=self.llocation,
  1349. flag=wx.ALIGN_LEFT | wx.ALL,
  1350. border=5, pos=(2, 1))
  1351. self.sizer.Add(item=self.MakeLabel(_("Projection:")),
  1352. flag=wx.ALIGN_LEFT | wx.ALL,
  1353. border=5, pos=(3, 0))
  1354. self.sizer.Add(item=self.lprojection,
  1355. flag=wx.ALIGN_LEFT | wx.ALL,
  1356. border=5, pos=(3, 1))
  1357. self.sizer.Add(item=self.lproj4stringLabel,
  1358. flag=wx.ALIGN_LEFT | wx.ALL,
  1359. border=5, pos=(4, 0))
  1360. self.sizer.Add(item=self.lproj4string,
  1361. flag=wx.ALIGN_LEFT | wx.ALL,
  1362. border=5, pos=(4, 1))
  1363. self.sizer.Add(item=(10,20),
  1364. flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
  1365. border=5, pos=(5, 0), span=(1, 2))
  1366. def OnEnterPage(self,event):
  1367. """
  1368. Insert values into text controls for summary of location creation options
  1369. """
  1370. database = self.parent.startpage.grassdatabase
  1371. location = self.parent.startpage.location
  1372. proj4string = self.parent.CreateProj4String()
  1373. epsgcode = self.parent.epsgpage.epsgcode
  1374. dtrans = self.parent.datumtrans
  1375. global coordsys
  1376. if coordsys not in ['proj', 'epsg']:
  1377. self.lproj4stringLabel.Hide()
  1378. self.lproj4string.Hide()
  1379. self.lproj4stringLabel.SetLabel('')
  1380. self.lproj4string.SetLabel('')
  1381. else:
  1382. self.lproj4string.Show()
  1383. self.lproj4stringLabel.SetLabel(_("PROJ.4 definition:"))
  1384. if coordsys == 'proj':
  1385. ret, msg, err = gcmd.RunCommand('g.proj',
  1386. flags = 'j',
  1387. proj4 = proj4string,
  1388. datumtrans = dtrans,
  1389. location = location,
  1390. getErrorMsg = True,
  1391. read = True)
  1392. elif coordsys == 'epsg':
  1393. ret, msg, err = gcmd.RunCommand('g.proj',
  1394. flags = 'j',
  1395. epsg = epsgcode,
  1396. datumtrans = dtrans,
  1397. location = location,
  1398. getErrorMsg = True,
  1399. read = True)
  1400. if ret == 0:
  1401. projlabel = ''
  1402. for line in msg.splitlines():
  1403. projlabel = projlabel + '%s ' % line
  1404. self.lproj4string.SetLabel(projlabel)
  1405. else:
  1406. wx.MessageBox(err, 'Error', wx.ICON_ERROR)
  1407. self.lproj4string.Wrap(400)
  1408. projdesc = self.parent.projpage.projdesc
  1409. ellipsedesc = self.parent.ellipsepage.ellipsedesc
  1410. datumdesc = self.parent.datumpage.datumdesc
  1411. self.ldatabase.SetLabel(database)
  1412. self.llocation.SetLabel(location)
  1413. label = ''
  1414. if coordsys == 'epsg':
  1415. label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
  1416. self.lprojection.SetLabel(label)
  1417. elif coordsys == 'file':
  1418. label = 'matches file %s' % self.parent.filepage.georeffile
  1419. self.lprojection.SetLabel(label)
  1420. elif coordsys == 'wkt':
  1421. label = 'matches file %s' % self.parent.wktpage.wktfile
  1422. self.lprojection.SetLabel(label)
  1423. elif coordsys == 'proj':
  1424. label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
  1425. self.lprojection.SetLabel(label)
  1426. elif coordsys == 'xy':
  1427. label = ('XY coordinate system (not projected).')
  1428. self.lprojection.SetLabel(label)
  1429. elif coordsys == 'custom':
  1430. label = ('%s' % self.parent.custompage.customstring)
  1431. self.lprojection.SetLabel(label)
  1432. def OnFinish(self, event):
  1433. dlg = wx.MessageDialog(parent=self.wizard,
  1434. message=_("Do you want to create GRASS location <%s>?") % location,
  1435. caption=_("Create new location?"),
  1436. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  1437. if dlg.ShowModal() == wx.ID_NO:
  1438. dlg.Destroy()
  1439. event.Veto()
  1440. else:
  1441. dlg.Destroy()
  1442. event.Skip()
  1443. class LocationWizard(wx.Object):
  1444. """!
  1445. Start wizard here and finish wizard here
  1446. """
  1447. def __init__(self, parent, grassdatabase):
  1448. self.__cleanUp()
  1449. global coordsys
  1450. self.parent = parent
  1451. #
  1452. # define wizard image
  1453. #
  1454. imagePath = os.path.join(globalvar.ETCWXDIR, "images", "loc_wizard_qgis.png")
  1455. wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
  1456. wizbmp = wizbmp.ConvertToBitmap()
  1457. #
  1458. # get georeferencing information from tables in $GISBASE/etc
  1459. #
  1460. self.__readData()
  1461. #
  1462. # datum transform number and list of datum transforms
  1463. #
  1464. self.datumtrans = 0
  1465. self.proj4string = ''
  1466. #
  1467. # define wizard pages
  1468. #
  1469. self.wizard = wiz.Wizard(parent, id=wx.ID_ANY, title=_("Define new GRASS Location"),
  1470. bitmap=wizbmp)
  1471. self.startpage = DatabasePage(self.wizard, self, grassdatabase)
  1472. self.csystemspage = CoordinateSystemPage(self.wizard, self)
  1473. self.projpage = ProjectionsPage(self.wizard, self)
  1474. self.datumpage = DatumPage(self.wizard, self)
  1475. self.paramspage = ProjParamsPage(self.wizard,self)
  1476. self.epsgpage = EPSGPage(self.wizard, self)
  1477. self.filepage = GeoreferencedFilePage(self.wizard, self)
  1478. self.wktpage = WKTPage(self.wizard, self)
  1479. self.ellipsepage = EllipsePage(self.wizard, self)
  1480. self.custompage = CustomPage(self.wizard, self)
  1481. self.sumpage = SummaryPage(self.wizard, self)
  1482. #
  1483. # set the initial order of the pages
  1484. # (should follow the epsg line)
  1485. #
  1486. self.startpage.SetNext(self.csystemspage)
  1487. self.csystemspage.SetPrev(self.startpage)
  1488. self.csystemspage.SetNext(self.sumpage)
  1489. self.projpage.SetPrev(self.csystemspage)
  1490. self.projpage.SetNext(self.paramspage)
  1491. self.paramspage.SetPrev(self.projpage)
  1492. self.paramspage.SetNext(self.datumpage)
  1493. self.datumpage.SetPrev(self.paramspage)
  1494. self.datumpage.SetNext(self.sumpage)
  1495. self.ellipsepage.SetPrev(self.paramspage)
  1496. self.ellipsepage.SetNext(self.sumpage)
  1497. self.epsgpage.SetPrev(self.csystemspage)
  1498. self.epsgpage.SetNext(self.sumpage)
  1499. self.filepage.SetPrev(self.csystemspage)
  1500. self.filepage.SetNext(self.sumpage)
  1501. self.wktpage.SetPrev(self.csystemspage)
  1502. self.wktpage.SetNext(self.sumpage)
  1503. self.custompage.SetPrev(self.csystemspage)
  1504. self.custompage.SetNext(self.sumpage)
  1505. self.sumpage.SetPrev(self.csystemspage)
  1506. #
  1507. # do pages layout
  1508. #
  1509. self.startpage.DoLayout()
  1510. self.csystemspage.DoLayout()
  1511. self.projpage.DoLayout()
  1512. self.datumpage.DoLayout()
  1513. self.paramspage.DoLayout()
  1514. self.epsgpage.DoLayout()
  1515. self.filepage.DoLayout()
  1516. self.wktpage.DoLayout()
  1517. self.ellipsepage.DoLayout()
  1518. self.custompage.DoLayout()
  1519. self.sumpage.DoLayout()
  1520. self.wizard.FitToPage(self.datumpage)
  1521. # new location created?
  1522. self.location = None
  1523. success = False
  1524. # location created in different GIS database?
  1525. self.altdb = False
  1526. #
  1527. # run wizard...
  1528. #
  1529. if self.wizard.RunWizard(self.startpage):
  1530. msg = self.OnWizFinished()
  1531. if len(msg) < 1:
  1532. self.wizard.Destroy()
  1533. self.location = self.startpage.location
  1534. if self.altdb == False:
  1535. dlg = wx.MessageDialog(parent=self.parent,
  1536. message=_("Do you want to set the default "
  1537. "region extents and resolution now?"),
  1538. caption=_("Location <%s> created") % self.location,
  1539. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  1540. dlg.CenterOnScreen()
  1541. if dlg.ShowModal() == wx.ID_YES:
  1542. dlg.Destroy()
  1543. defineRegion = RegionDef(self.parent, location=self.location)
  1544. defineRegion.CenterOnScreen()
  1545. defineRegion.Show()
  1546. else:
  1547. dlg.Destroy()
  1548. else: # -> error
  1549. self.wizard.Destroy()
  1550. wx.MessageBox(parent=self.parent,
  1551. message="%s" % _("Unable to create new location. "
  1552. "Location <%(loc)s> not created.\n\n"
  1553. "Details: %(err)s") % \
  1554. { 'loc' : self.startpage.location,
  1555. 'err' : msg },
  1556. caption=_("Location wizard"),
  1557. style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1558. else: # -> cancelled
  1559. self.wizard.Destroy()
  1560. wx.MessageBox(parent=self.parent,
  1561. message=_("Location wizard canceled. "
  1562. "Location not created."),
  1563. caption=_("Location wizard"),
  1564. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  1565. self.__cleanUp()
  1566. def __cleanUp(self):
  1567. global coordsys
  1568. global north
  1569. global south
  1570. global east
  1571. global west
  1572. global resolution
  1573. global wizerror
  1574. global translist
  1575. coordsys = None
  1576. north = None
  1577. south = None
  1578. east = None
  1579. west = None
  1580. resolution = None
  1581. transformlist = list()
  1582. def __readData(self):
  1583. """!Get georeferencing information from tables in $GISBASE/etc"""
  1584. # read projection and parameters
  1585. f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
  1586. self.projections = {}
  1587. self.projdesc = {}
  1588. for line in f.readlines():
  1589. line = line.strip()
  1590. try:
  1591. proj, projdesc, params = line.split(':')
  1592. paramslist = params.split(';')
  1593. plist = []
  1594. for p in paramslist:
  1595. if p == '': continue
  1596. p1, pdefault = p.split(',')
  1597. pterm, pask = p1.split('=')
  1598. p = [pterm.strip(), pask.strip(), pdefault.strip()]
  1599. plist.append(p)
  1600. self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
  1601. self.projdesc[proj.lower().strip()] = projdesc.strip()
  1602. except:
  1603. continue
  1604. f.close()
  1605. # read datum definitions
  1606. f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
  1607. self.datums = {}
  1608. paramslist = []
  1609. for line in f.readlines():
  1610. line = line.expandtabs(1)
  1611. line = line.strip()
  1612. if line == '' or line[0] == "#":
  1613. continue
  1614. datum, info = line.split(" ", 1)
  1615. info = info.strip()
  1616. datumdesc, params = info.split(" ", 1)
  1617. datumdesc = datumdesc.strip('"')
  1618. paramlist = params.split()
  1619. ellipsoid = paramlist.pop(0)
  1620. self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
  1621. f.close()
  1622. # read ellipsiod definitions
  1623. f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
  1624. self.ellipsoids = {}
  1625. for line in f.readlines():
  1626. line = line.expandtabs(1)
  1627. line = line.strip()
  1628. if line == '' or line[0] == "#":
  1629. continue
  1630. ellipse, rest = line.split(" ", 1)
  1631. rest = rest.strip('" ')
  1632. desc, params = rest.split('"', 1)
  1633. desc = desc.strip('" ')
  1634. paramslist = params.split()
  1635. self.ellipsoids[ellipse] = (desc, paramslist)
  1636. f.close()
  1637. # read projection parameter description and parsing table
  1638. f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
  1639. self.paramdesc = {}
  1640. for line in f.readlines():
  1641. line = line.strip()
  1642. try:
  1643. pparam, datatype, proj4term, desc = line.split(':')
  1644. self.paramdesc[pparam] = (datatype, proj4term, desc)
  1645. except:
  1646. continue
  1647. f.close()
  1648. def OnWizFinished(self):
  1649. database = self.startpage.grassdatabase
  1650. location = self.startpage.location
  1651. global coordsys
  1652. msg = '' # error message (empty on success)
  1653. # location already exists?
  1654. if os.path.isdir(os.path.join(database,location)):
  1655. dlg = wx.MessageDialog(parent=self.wizard,
  1656. message="%s <%s>: %s" % \
  1657. (_("Unable to create new location"),
  1658. os.path.join(database, location),
  1659. _("Location already exists in GRASS Database.")),
  1660. caption=_("Error"),
  1661. style=wx.OK | wx.ICON_ERROR)
  1662. dlg.ShowModal()
  1663. dlg.Destroy()
  1664. return False
  1665. # current GISDbase or a new one?
  1666. current_gdb = grass.gisenv()['GISDBASE']
  1667. if current_gdb != database:
  1668. # change to new GISDbase or create new one
  1669. if os.path.isdir(database) != True:
  1670. # create new directory
  1671. os.mkdir(database)
  1672. # change to new GISDbase directory
  1673. gcmd.RunCommand('g.gisenv',
  1674. parent = self.wizard,
  1675. set='GISDBASE=%s' % database)
  1676. wx.MessageBox(parent=self.wizard,
  1677. message=_("Location <%(loc)s> will be created "
  1678. "in GIS data directory <%(dir)s>."
  1679. "You will need to change the default GIS "
  1680. "data directory in the GRASS startup screen.") % \
  1681. { 'loc' : location, 'dir' : database},
  1682. caption=_("New GIS data directory"),
  1683. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  1684. # location created in alternate GISDbase
  1685. self.altdb = True
  1686. if coordsys == "xy":
  1687. msg = self.XYCreate()
  1688. elif coordsys == "proj":
  1689. proj4string = self.CreateProj4String()
  1690. msg = self.Proj4Create(proj4string)
  1691. elif coordsys == 'custom':
  1692. msg = self.CustomCreate()
  1693. elif coordsys == "epsg":
  1694. msg = self.EPSGCreate()
  1695. elif coordsys == "file":
  1696. msg = self.FileCreate()
  1697. elif coordsys == "wkt":
  1698. msg = self.WKTCreate()
  1699. return msg
  1700. def XYCreate(self):
  1701. """!Create an XY location
  1702. @return error message (empty string on success)
  1703. """
  1704. database = self.startpage.grassdatabase
  1705. location = self.startpage.location
  1706. # create location directory and PERMANENT mapset
  1707. try:
  1708. os.mkdir(os.path.join(database, location))
  1709. os.mkdir(os.path.join(database, location, 'PERMANENT'))
  1710. # create DEFAULT_WIND and WIND files
  1711. regioninfo = ['proj: 0',
  1712. 'zone: 0',
  1713. 'north: 1',
  1714. 'south: 0',
  1715. 'east: 1',
  1716. 'west: 0',
  1717. 'cols: 1',
  1718. 'rows: 1',
  1719. 'e-w resol: 1',
  1720. 'n-s resol: 1',
  1721. 'top: 1',
  1722. 'bottom: 0',
  1723. 'cols3: 1',
  1724. 'rows3: 1',
  1725. 'depths: 1',
  1726. 'e-w resol3: 1',
  1727. 'n-s resol3: 1',
  1728. 't-b resol: 1']
  1729. defwind = open(os.path.join(database, location,
  1730. "PERMANENT", "DEFAULT_WIND"), 'w')
  1731. for param in regioninfo:
  1732. defwind.write(param + '%s' % os.linesep)
  1733. defwind.close()
  1734. shutil.copy(os.path.join(database, location, "PERMANENT", "DEFAULT_WIND"),
  1735. os.path.join(database, location, "PERMANENT", "WIND"))
  1736. # create MYNAME file
  1737. myname = open(os.path.join(database, location, "PERMANENT",
  1738. "MYNAME"), 'w')
  1739. myname.write('%s' % os.linesep)
  1740. myname.close()
  1741. except OSError, e:
  1742. return e
  1743. return ''
  1744. def CreateProj4String(self):
  1745. """!Constract PROJ.4 string"""
  1746. location = self.startpage.location
  1747. proj = self.projpage.p4proj
  1748. projdesc = self.projpage.projdesc
  1749. proj4params = self.paramspage.p4projparams
  1750. datum = self.datumpage.datum
  1751. if self.datumpage.datumdesc:
  1752. datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
  1753. else:
  1754. datumdesc = ''
  1755. datumparams = self.datumpage.datumparams
  1756. ellipse = self.ellipsepage.ellipse
  1757. ellipsedesc = self.ellipsepage.ellipsedesc
  1758. ellipseparams = self.ellipsepage.ellipseparams
  1759. #
  1760. # creating PROJ.4 string
  1761. #
  1762. proj4string = '%s %s' % (proj, proj4params)
  1763. # set ellipsoid parameters
  1764. if ellipse != '': proj4string = '%s +ellps=%s' % (proj4string, ellipse)
  1765. for item in ellipseparams:
  1766. if item[:4] == 'f=1/':
  1767. item = ' +rf='+item[4:]
  1768. else:
  1769. item = ' +'+item
  1770. proj4string = '%s %s' % (proj4string, item)
  1771. # set datum and transform parameters if relevant
  1772. if datum != '': proj4string = '%s +datum=%s' % (proj4string, datum)
  1773. if datumparams:
  1774. for item in datumparams:
  1775. proj4string = '%s +%s' % (proj4string,item)
  1776. proj4string = '%s +no_defs' % proj4string
  1777. return proj4string
  1778. def Proj4Create(self, proj4string):
  1779. """!Create a new location for selected projection
  1780. @return error message (empty string on success)
  1781. """
  1782. ret, msg = gcmd.RunCommand('g.proj',
  1783. flags = 'c',
  1784. proj4 = proj4string,
  1785. location = self.startpage.location,
  1786. datumtrans = self.datumtrans,
  1787. getErrorMsg = True)
  1788. if ret == 0:
  1789. return ''
  1790. return msg
  1791. def CustomCreate(self):
  1792. """!Create a new location based on given proj4 string
  1793. @return error message (empty string on success)
  1794. """
  1795. proj4string = self.custompage.customstring
  1796. location = self.startpage.location
  1797. ret, msg = gcmd.RunCommand('g.proj',
  1798. flags = 'c',
  1799. proj4 = proj4string,
  1800. location = location,
  1801. getErrorMsg = True)
  1802. if ret == 0:
  1803. return ''
  1804. return msg
  1805. def EPSGCreate(self):
  1806. """!Create a new location from an EPSG code.
  1807. @return error message (empty string on success)
  1808. """
  1809. epsgcode = self.epsgpage.epsgcode
  1810. epsgdesc = self.epsgpage.epsgdesc
  1811. location = self.startpage.location
  1812. # should not happend
  1813. if epsgcode == '':
  1814. return _('EPSG code missing.')
  1815. ret, msg = gcmd.RunCommand('g.proj',
  1816. flags = 'c',
  1817. epsg = epsgcode,
  1818. location = location,
  1819. datumtrans = self.datumtrans,
  1820. getErrorMsg = True)
  1821. if ret == 0:
  1822. return ''
  1823. return msg
  1824. def FileCreate(self):
  1825. """!Create a new location from a georeferenced file
  1826. @return error message (empty string on success)
  1827. """
  1828. georeffile = self.filepage.georeffile
  1829. location = self.startpage.location
  1830. # this should not happen
  1831. if not georeffile or not os.path.isfile(georeffile):
  1832. return _("File not found.")
  1833. # creating location
  1834. ret, msg = gcmd.RunCommand('g.proj',
  1835. flags = 'c',
  1836. georef = georeffile,
  1837. location = location,
  1838. getErrorMsg = True)
  1839. if ret == 0:
  1840. return ''
  1841. return msg
  1842. def WKTCreate(self):
  1843. """!Create a new location from a WKT file
  1844. @return error message (empty string on success)
  1845. """
  1846. wktfile = self.wktpage.wktfile
  1847. location = self.startpage.location
  1848. # this should not happen
  1849. if not wktfile or not os.path.isfile(wktfile):
  1850. return _("File not found.")
  1851. # creating location
  1852. ret, msg = gcmd.RunCommand('g.proj',
  1853. flags = 'c',
  1854. wkt = wktfile,
  1855. location = location,
  1856. getErrorMsg = True)
  1857. if ret == 0:
  1858. return ''
  1859. return msg
  1860. class RegionDef(BaseClass, wx.Frame):
  1861. """
  1862. Page for setting default region extents and resolution
  1863. """
  1864. def __init__(self, parent, id=wx.ID_ANY,
  1865. title=_("Set default region extent and resolution"), location=None):
  1866. wx.Frame.__init__(self, parent, id, title, size=(650,300))
  1867. panel = wx.Panel(self, id=wx.ID_ANY)
  1868. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  1869. self.parent = parent
  1870. self.location = location
  1871. #
  1872. # default values
  1873. #
  1874. # 2D
  1875. self.north = 1.0
  1876. self.south = 0.0
  1877. self.east = 1.0
  1878. self.west = 0.0
  1879. self.nsres = 1.0
  1880. self.ewres = 1.0
  1881. # 3D
  1882. self.top = 1.0
  1883. self.bottom = 0.0
  1884. # self.nsres3 = 1.0
  1885. # self.ewres3 = 1.0
  1886. self.tbres = 1.0
  1887. #
  1888. # inputs
  1889. #
  1890. # 2D
  1891. self.tnorth = self.MakeTextCtrl(text=str(self.north), size=(150, -1), parent=panel)
  1892. self.tsouth = self.MakeTextCtrl(str(self.south), size=(150, -1), parent=panel)
  1893. self.twest = self.MakeTextCtrl(str(self.west), size=(150, -1), parent=panel)
  1894. self.teast = self.MakeTextCtrl(str(self.east), size=(150, -1), parent=panel)
  1895. self.tnsres = self.MakeTextCtrl(str(self.nsres), size=(150, -1), parent=panel)
  1896. self.tewres = self.MakeTextCtrl(str(self.ewres), size=(150, -1), parent=panel)
  1897. #
  1898. # labels
  1899. #
  1900. self.lrows = self.MakeLabel(parent=panel)
  1901. self.lcols = self.MakeLabel(parent=panel)
  1902. self.lcells = self.MakeLabel(parent=panel)
  1903. #
  1904. # buttons
  1905. #
  1906. self.bset = self.MakeButton(text=_("&Set region"), id=wx.ID_OK, parent=panel)
  1907. self.bcancel = wx.Button(panel, id=wx.ID_CANCEL)
  1908. self.bset.SetDefault()
  1909. #
  1910. # image
  1911. #
  1912. self.img = wx.Image(os.path.join(globalvar.ETCWXDIR, "images",
  1913. "qgis_world.png"), wx.BITMAP_TYPE_PNG).ConvertToBitmap()
  1914. #
  1915. # set current working environment to PERMANENT mapset
  1916. # in selected location in order to set default region (WIND)
  1917. #
  1918. envval = {}
  1919. ret = gcmd.RunCommand('g.gisenv',
  1920. read = True)
  1921. if ret:
  1922. for line in ret.splitlines():
  1923. key, val = line.split('=')
  1924. envval[key] = val
  1925. self.currlocation = envval['LOCATION_NAME'].strip("';")
  1926. self.currmapset = envval['MAPSET'].strip("';")
  1927. if self.currlocation != self.location or self.currmapset != 'PERMANENT':
  1928. gcmd.RunCommand('g.gisenv',
  1929. set = 'LOCATION_NAME=%s' % self.location)
  1930. gcmd.RunCommand('g.gisenv',
  1931. set = 'MAPSET=PERMANENT')
  1932. else:
  1933. dlg = wx.MessageBox(parent=self,
  1934. message=_('Invalid location selected.'),
  1935. caption=_("Error"), style=wx.ID_OK | wx.ICON_ERROR)
  1936. return
  1937. #
  1938. # get current region settings
  1939. #
  1940. region = {}
  1941. ret = gcmd.RunCommand('g.region',
  1942. read = True,
  1943. flags = 'gp3')
  1944. if ret:
  1945. for line in ret.splitlines():
  1946. key, val = line.split('=')
  1947. region[key] = float(val)
  1948. else:
  1949. dlg = wx.MessageBox(parent=self,
  1950. message=_("Invalid region"),
  1951. caption=_("Error"), style=wx.ID_OK | wx.ICON_ERROR)
  1952. dlg.ShowModal()
  1953. dlg.Destroy()
  1954. return
  1955. #
  1956. # update values
  1957. # 2D
  1958. self.north = float(region['n'])
  1959. self.south = float(region['s'])
  1960. self.east = float(region['e'])
  1961. self.west = float(region['w'])
  1962. self.nsres = float(region['nsres'])
  1963. self.ewres = float(region['ewres'])
  1964. self.rows = int(region['rows'])
  1965. self.cols = int(region['cols'])
  1966. self.cells = int(region['cells'])
  1967. # 3D
  1968. self.top = float(region['t'])
  1969. self.bottom = float(region['b'])
  1970. # self.nsres3 = float(region['nsres3'])
  1971. # self.ewres3 = float(region['ewres3'])
  1972. self.tbres = float(region['tbres'])
  1973. self.depth = int(region['depths'])
  1974. self.cells3 = int(region['3dcells'])
  1975. #
  1976. # 3D box collapsable
  1977. #
  1978. self.infoCollapseLabelExp = _("Click here to show 3D settings")
  1979. self.infoCollapseLabelCol = _("Click here to hide 3D settings")
  1980. self.settings3D = wx.CollapsiblePane(parent=panel,
  1981. label=self.infoCollapseLabelExp,
  1982. style=wx.CP_DEFAULT_STYLE |
  1983. wx.CP_NO_TLW_RESIZE | wx.EXPAND)
  1984. self.MakeSettings3DPaneContent(self.settings3D.GetPane())
  1985. self.settings3D.Collapse(False) # FIXME
  1986. self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSettings3DPaneChanged, self.settings3D)
  1987. #
  1988. # set current region settings
  1989. #
  1990. self.tnorth.SetValue(str(self.north))
  1991. self.tsouth.SetValue(str(self.south))
  1992. self.twest.SetValue(str(self.west))
  1993. self.teast.SetValue(str(self.east))
  1994. self.tnsres.SetValue(str(self.nsres))
  1995. self.tewres.SetValue(str(self.ewres))
  1996. self.ttop.SetValue(str(self.top))
  1997. self.tbottom.SetValue(str(self.bottom))
  1998. # self.tnsres3.SetValue(str(self.nsres3))
  1999. # self.tewres3.SetValue(str(self.ewres3))
  2000. self.ttbres.SetValue(str(self.tbres))
  2001. self.lrows.SetLabel(_("Rows: %d") % self.rows)
  2002. self.lcols.SetLabel(_("Cols: %d") % self.cols)
  2003. self.lcells.SetLabel(_("Cells: %d") % self.cells)
  2004. #
  2005. # bindings
  2006. #
  2007. self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
  2008. self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
  2009. self.tnorth.Bind(wx.EVT_TEXT, self.OnValue)
  2010. self.tsouth.Bind(wx.EVT_TEXT, self.OnValue)
  2011. self.teast.Bind(wx.EVT_TEXT, self.OnValue)
  2012. self.twest.Bind(wx.EVT_TEXT, self.OnValue)
  2013. self.tnsres.Bind(wx.EVT_TEXT, self.OnValue)
  2014. self.tewres.Bind(wx.EVT_TEXT, self.OnValue)
  2015. self.ttop.Bind(wx.EVT_TEXT, self.OnValue)
  2016. self.tbottom.Bind(wx.EVT_TEXT, self.OnValue)
  2017. # self.tnsres3.Bind(wx.EVT_TEXT, self.OnValue)
  2018. # self.tewres3.Bind(wx.EVT_TEXT, self.OnValue)
  2019. self.ttbres.Bind(wx.EVT_TEXT, self.OnValue)
  2020. self.__DoLayout(panel)
  2021. self.SetMinSize(self.GetBestSize())
  2022. self.minWindowSize = self.GetMinSize()
  2023. def MakeSettings3DPaneContent(self, pane):
  2024. """!Create 3D region settings pane"""
  2025. border = wx.BoxSizer(wx.VERTICAL)
  2026. gridSizer = wx.GridBagSizer(vgap=0, hgap=0)
  2027. # inputs
  2028. self.ttop = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.top),
  2029. size=(150, -1))
  2030. self.tbottom = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.bottom),
  2031. size=(150, -1))
  2032. self.ttbres = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.tbres),
  2033. size=(150, -1))
  2034. # self.tnsres3 = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.nsres3),
  2035. # size=(150, -1))
  2036. # self.tewres3 = wx.TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.ewres3),
  2037. # size=(150, -1))
  2038. #labels
  2039. self.ldepth = wx.StaticText(parent=pane, label=_("Depth: %d") % self.depth)
  2040. self.lcells3 = wx.StaticText(parent=pane, label=_("3D Cells: %d") % self.cells3)
  2041. # top
  2042. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("Top")),
  2043. flag=wx.ALIGN_CENTER |
  2044. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2045. pos=(0, 1))
  2046. gridSizer.Add(item=self.ttop,
  2047. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2048. wx.ALL, border=5, pos=(1, 1))
  2049. # bottom
  2050. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("Bottom")),
  2051. flag=wx.ALIGN_CENTER |
  2052. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2053. pos=(0, 2))
  2054. gridSizer.Add(item=self.tbottom,
  2055. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2056. wx.ALL, border=5, pos=(1, 2))
  2057. # tbres
  2058. gridSizer.Add(item=wx.StaticText(parent=pane, label=_("T-B resolution")),
  2059. flag=wx.ALIGN_CENTER |
  2060. wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2061. pos=(0, 3))
  2062. gridSizer.Add(item=self.ttbres,
  2063. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2064. wx.ALL, border=5, pos=(1, 3))
  2065. # res
  2066. # gridSizer.Add(item=wx.StaticText(parent=pane, label=_("3D N-S resolution")),
  2067. # flag=wx.ALIGN_CENTER |
  2068. # wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2069. # pos=(2, 1))
  2070. # gridSizer.Add(item=self.tnsres3,
  2071. # flag=wx.ALIGN_CENTER_HORIZONTAL |
  2072. # wx.ALL, border=5, pos=(3, 1))
  2073. # gridSizer.Add(item=wx.StaticText(parent=pane, label=_("3D E-W resolution")),
  2074. # flag=wx.ALIGN_CENTER |
  2075. # wx.LEFT | wx.RIGHT | wx.TOP, border=5,
  2076. # pos=(2, 3))
  2077. # gridSizer.Add(item=self.tewres3,
  2078. # flag=wx.ALIGN_CENTER_HORIZONTAL |
  2079. # wx.ALL, border=5, pos=(3, 3))
  2080. # rows/cols/cells
  2081. gridSizer.Add(item=self.ldepth,
  2082. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2083. wx.ALL, border=5, pos=(2, 1))
  2084. gridSizer.Add(item=self.lcells3,
  2085. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2086. wx.ALL, border=5, pos=(2, 2))
  2087. border.Add(item=gridSizer, proportion=1,
  2088. flag=wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border=5)
  2089. pane.SetSizer(border)
  2090. border.Fit(pane)
  2091. def OnSettings3DPaneChanged(self, event):
  2092. """!Collapse 3D settings box"""
  2093. if self.settings3D.IsExpanded():
  2094. self.settings3D.SetLabel(self.infoCollapseLabelCol)
  2095. self.Layout()
  2096. self.SetSize(self.GetBestSize())
  2097. self.SetMinSize(self.GetSize())
  2098. else:
  2099. self.settings3D.SetLabel(self.infoCollapseLabelExp)
  2100. self.Layout()
  2101. self.SetSize(self.minWindowSize)
  2102. self.SetMinSize(self.minWindowSize)
  2103. self.SendSizeEvent()
  2104. def __DoLayout(self, panel):
  2105. """!Window layout"""
  2106. frameSizer = wx.BoxSizer(wx.VERTICAL)
  2107. gridSizer = wx.GridBagSizer(vgap=0, hgap=0)
  2108. settings3DSizer = wx.BoxSizer(wx.VERTICAL)
  2109. buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
  2110. # north
  2111. gridSizer.Add(item=self.MakeLabel(text=_("North"), parent=panel),
  2112. flag=wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
  2113. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(0, 2))
  2114. gridSizer.Add(item=self.tnorth,
  2115. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2116. wx.ALIGN_CENTER_VERTICAL |
  2117. wx.ALL, border=5, pos=(1, 2))
  2118. # west
  2119. gridSizer.Add(item=self.MakeLabel(text=_("West"), parent=panel),
  2120. flag=wx.ALIGN_RIGHT |
  2121. wx.ALIGN_CENTER_VERTICAL |
  2122. wx.LEFT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 0))
  2123. gridSizer.Add(item=self.twest,
  2124. flag=wx.ALIGN_RIGHT |
  2125. wx.ALIGN_CENTER_VERTICAL |
  2126. wx.ALL, border=5, pos=(2, 1))
  2127. gridSizer.Add(item=wx.StaticBitmap(panel, wx.ID_ANY, self.img, (-1, -1),
  2128. (self.img.GetWidth(), self.img.GetHeight())),
  2129. flag=wx.ALIGN_CENTER |
  2130. wx.ALIGN_CENTER_VERTICAL |
  2131. wx.ALL, border=5, pos=(2, 2))
  2132. # east
  2133. gridSizer.Add(item=self.teast,
  2134. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2135. wx.ALIGN_CENTER_VERTICAL |
  2136. wx.ALL, border=5, pos=(2, 3))
  2137. gridSizer.Add(item=self.MakeLabel(text=_("East"), parent=panel),
  2138. flag=wx.ALIGN_LEFT |
  2139. wx.ALIGN_CENTER_VERTICAL |
  2140. wx.RIGHT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 4))
  2141. # south
  2142. gridSizer.Add(item=self.tsouth,
  2143. flag=wx.ALIGN_CENTER_HORIZONTAL |
  2144. wx.ALIGN_CENTER_VERTICAL |
  2145. wx.ALL, border=5, pos=(3, 2))
  2146. gridSizer.Add(item=self.MakeLabel(text=_("South"), parent=panel),
  2147. flag=wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
  2148. wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5, pos=(4, 2))
  2149. # ns-res
  2150. gridSizer.Add(item=self.MakeLabel(text=_("N-S resolution"), parent=panel),
  2151. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2152. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 1))
  2153. gridSizer.Add(item=self.tnsres,
  2154. flag=wx.ALIGN_RIGHT |
  2155. wx.ALIGN_CENTER_VERTICAL |
  2156. wx.ALL, border=5, pos=(6, 1))
  2157. # ew-res
  2158. gridSizer.Add(item=self.MakeLabel(text=_("E-W resolution"), parent=panel),
  2159. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2160. wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 3))
  2161. gridSizer.Add(item=self.tewres,
  2162. flag=wx.ALIGN_RIGHT |
  2163. wx.ALIGN_CENTER_VERTICAL |
  2164. wx.ALL, border=5, pos=(6, 3))
  2165. # rows/cols/cells
  2166. gridSizer.Add(item=self.lrows,
  2167. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2168. wx.ALL, border=5, pos=(7, 1))
  2169. gridSizer.Add(item=self.lcells,
  2170. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2171. wx.ALL, border=5, pos=(7, 2))
  2172. gridSizer.Add(item=self.lcols,
  2173. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
  2174. wx.ALL, border=5, pos=(7, 3))
  2175. # 3D
  2176. settings3DSizer.Add(item=self.settings3D,
  2177. flag=wx.ALL,
  2178. border=5)
  2179. # buttons
  2180. buttonSizer.Add(item=self.bcancel, proportion=1,
  2181. flag=wx.ALIGN_RIGHT |
  2182. wx.ALIGN_CENTER_VERTICAL |
  2183. wx.ALL, border=10)
  2184. buttonSizer.Add(item=self.bset, proportion=1,
  2185. flag=wx.ALIGN_CENTER |
  2186. wx.ALIGN_CENTER_VERTICAL |
  2187. wx.ALL, border=10)
  2188. frameSizer.Add(item=gridSizer, proportion=1,
  2189. flag=wx.ALL | wx.ALIGN_CENTER, border=5)
  2190. frameSizer.Add(item=settings3DSizer, proportion=0,
  2191. flag=wx.ALL | wx.ALIGN_CENTER, border=5)
  2192. frameSizer.Add(item=buttonSizer, proportion=0,
  2193. flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
  2194. self.SetAutoLayout(True)
  2195. panel.SetSizer(frameSizer)
  2196. frameSizer.Fit(panel)
  2197. self.Layout()
  2198. def OnValue(self, event):
  2199. """!Set given value"""
  2200. try:
  2201. if event.GetId() == self.tnorth.GetId():
  2202. self.north = float(event.GetString())
  2203. elif event.GetId() == self.tsouth.GetId():
  2204. self.south = float(event.GetString())
  2205. elif event.GetId() == self.teast.GetId():
  2206. self.east = float(event.GetString())
  2207. elif event.GetId() == self.twest.GetId():
  2208. self.west = float(event.GetString())
  2209. elif event.GetId() == self.tnsres.GetId():
  2210. self.nsres = float(event.GetString())
  2211. elif event.GetId() == self.tewres.GetId():
  2212. self.ewres = float(event.GetString())
  2213. elif event.GetId() == self.ttop.GetId():
  2214. self.top = float(event.GetString())
  2215. elif event.GetId() == self.tbottom.GetId():
  2216. self.bottom = float(event.GetString())
  2217. # elif event.GetId() == self.tnsres3.GetId():
  2218. # self.nsres3 = float(event.GetString())
  2219. # elif event.GetId() == self.tewres3.GetId():
  2220. # self.ewres3 = float(event.GetString())
  2221. elif event.GetId() == self.ttbres.GetId():
  2222. self.tbres = float(event.GetString())
  2223. self.__UpdateInfo()
  2224. except ValueError, e:
  2225. if len(event.GetString()) > 0 and event.GetString() != '-':
  2226. dlg = wx.MessageBox(parent=self,
  2227. message=_("Invalid value: %s") % e,
  2228. caption=_("Error"),
  2229. style=wx.OK | wx.ICON_ERROR)
  2230. # reset values
  2231. self.tnorth.SetValue(str(self.north))
  2232. self.tsouth.SetValue(str(self.south))
  2233. self.teast.SetValue(str(self.east))
  2234. self.twest.SetValue(str(self.west))
  2235. self.tnsres.SetValue(str(self.nsres))
  2236. self.tewres.SetValue(str(self.ewres))
  2237. self.ttop.SetValue(str(self.top))
  2238. self.tbottom.SetValue(str(self.bottom))
  2239. self.ttbres.SetValue(str(self.tbres))
  2240. # self.tnsres3.SetValue(str(self.nsres3))
  2241. # self.tewres3.SetValue(str(self.ewres3))
  2242. event.Skip()
  2243. def __UpdateInfo(self):
  2244. """!Update number of rows/cols/cells"""
  2245. self.rows = int((self.north - self.south) / self.nsres)
  2246. self.cols = int((self.east - self.west) / self.ewres)
  2247. self.cells = self.rows * self.cols
  2248. self.depth = int((self.top - self.bottom) / self.tbres)
  2249. self.cells3 = self.rows * self.cols * self.depth
  2250. # 2D
  2251. self.lrows.SetLabel(_("Rows: %d") % self.rows)
  2252. self.lcols.SetLabel(_("Cols: %d") % self.cols)
  2253. self.lcells.SetLabel(_("Cells: %d") % self.cells)
  2254. # 3D
  2255. self.ldepth.SetLabel(_("Depth: %d" % self.depth))
  2256. self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))
  2257. def OnSetButton(self, event=None):
  2258. """!Set default region"""
  2259. ret = gcmd.RunCommand('g.region',
  2260. flags = 'sgpa',
  2261. n = self.north,
  2262. s = self.south,
  2263. e = self.east,
  2264. w = self.west,
  2265. nsres = self.nsres,
  2266. ewres = self.ewres,
  2267. t = self.top,
  2268. b = self.bottom,
  2269. tbres = self.tbres)
  2270. if ret == 0:
  2271. self.Destroy()
  2272. def OnCancel(self, event):
  2273. self.Destroy()
  2274. class TransList(wx.VListBox):
  2275. """!Creates a multiline listbox for selecting datum transforms"""
  2276. def OnDrawItem(self, dc, rect, n):
  2277. if self.GetSelection() == n:
  2278. c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
  2279. else:
  2280. c = self.GetForegroundColour()
  2281. dc.SetFont(self.GetFont())
  2282. dc.SetTextForeground(c)
  2283. dc.DrawLabel(self._getItemText(n), rect,
  2284. wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
  2285. def OnMeasureItem(self, n):
  2286. height = 0
  2287. if self._getItemText(n) == None: return
  2288. for line in self._getItemText(n).splitlines():
  2289. w, h = self.GetTextExtent(line)
  2290. height += h
  2291. return height + 5
  2292. def _getItemText(self, item):
  2293. global transformlist
  2294. transitem = transformlist[item]
  2295. if transitem.strip() !='':
  2296. return transitem
  2297. class SelectTransformDialog(wx.Dialog):
  2298. """!Dialog for selecting datum transformations"""
  2299. def __init__(self, parent, transforms, title=_("Select datum transformation"),
  2300. pos=wx.DefaultPosition, size=wx.DefaultSize,
  2301. style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
  2302. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  2303. global transformlist
  2304. self.CentreOnParent()
  2305. # default transform number
  2306. self.transnum = 0
  2307. panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
  2308. sizer = wx.BoxSizer(wx.VERTICAL)
  2309. #
  2310. # set panel sizer
  2311. #
  2312. panel.SetSizer(sizer)
  2313. panel.SetupScrolling()
  2314. #
  2315. # dialog body
  2316. #
  2317. bodyBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
  2318. label=" %s " % _("Select from list of datum transformations"))
  2319. bodySizer = wx.StaticBoxSizer(bodyBox)
  2320. # add no transform option
  2321. transforms = '---\n\n0\nDo not apply any datum transformations\n\n' + transforms
  2322. transformlist = transforms.split('---')
  2323. tlistlen = len(transformlist)
  2324. # calculate size for transform list
  2325. height = 0
  2326. width = 0
  2327. for line in transforms.splitlines():
  2328. w, h = self.GetTextExtent(line)
  2329. height += h
  2330. width = max(width, w)
  2331. height = height + 5
  2332. if height > 400: height = 400
  2333. width = width + 5
  2334. if width > 400: width = 400
  2335. #
  2336. # VListBox for displaying and selecting transformations
  2337. #
  2338. self.translist = TransList(panel, id=-1, size=(width, height), style=wx.SUNKEN_BORDER)
  2339. self.translist.SetItemCount(tlistlen)
  2340. self.translist.SetSelection(2)
  2341. self.translist.SetFocus()
  2342. self.Bind(wx.EVT_LISTBOX, self.ClickTrans, self.translist)
  2343. bodySizer.Add(item=self.translist, proportion=1, flag=wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
  2344. #
  2345. # buttons
  2346. #
  2347. btnsizer = wx.StdDialogButtonSizer()
  2348. btn = wx.Button(parent=panel, id=wx.ID_OK)
  2349. btn.SetDefault()
  2350. btnsizer.AddButton(btn)
  2351. btn = wx.Button(parent=panel, id=wx.ID_CANCEL)
  2352. btnsizer.AddButton(btn)
  2353. btnsizer.Realize()
  2354. sizer.Add(item=bodySizer, proportion=1,
  2355. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  2356. sizer.Add(item=btnsizer, proportion=0,
  2357. flag= wx.ALL | wx.ALIGN_RIGHT, border=5)
  2358. sizer.Fit(panel)
  2359. self.SetSize(self.GetBestSize())
  2360. self.Layout()
  2361. def ClickTrans(self, event):
  2362. """!Get the number of the datum transform to use in g.proj"""
  2363. self.transnum = event.GetSelection()
  2364. self.transnum = self.transnum - 1
  2365. def GetTransform(self):
  2366. """!Get the number of the datum transform to use in g.proj"""
  2367. self.transnum = self.translist.GetSelection()
  2368. self.transnum = self.transnum - 1
  2369. return self.transnum
  2370. if __name__ == "__main__":
  2371. import gettext
  2372. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
  2373. app = wx.PySimpleApp()
  2374. # gWizard = LocationWizard(None, "")
  2375. gWizard = RegionDef(None)
  2376. gWizzard.Show()
  2377. app.MainLoop()