location_wizard.py 103 KB

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